Svi*_*ish 27 java if-statement micro-optimization
问一个无关的问题,我有这样的代码:
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
// Check property values
}
Run Code Online (Sandbox Code Playgroud)
我得到了一条评论,声称这不是最优的,相反(如果我理解正确的话)应该这样做:
public boolean equals(Object obj)
{
if (this == obj)
return true;
else if (obj == null)
return false;
else if (getClass() != obj.getClass())
return false;
// Check property values
}
Run Code Online (Sandbox Code Playgroud)
由于返回语句,我无法真正理解为什么它们中的任何一个应该比另一个更高效或更快.鉴于某个对象,就我所见,这两种方法都必须进行相同数量的检查.并且由于返回语句,不会在其中任何一个中运行额外的代码.
我在这里错过了什么吗?有东西吗?是否有一些编译器优化或正在发生的事情或其他什么?
我知道这是微优化,我很可能会坚持第一种方式,因为我认为它看起来比较清晰,所有的ifs都在同一个位置上.但我无能为力; 我很好奇!
Joa*_*uer 23
对于这两种情况,生成的字节代码是相同的,因此它纯粹是一种风格问题.
我生成了两个方法e1
,e2
并且都生成了这个字节代码(使用读取javap -v
):
public boolean e1(java.lang.Object); Code: Stack=2, Locals=2, Args_size=2 0: aload_0 1: aload_1 2: if_acmpne 7 5: iconst_1 6: ireturn 7: aload_1 8: ifnonnull 13 11: iconst_0 12: ireturn 13: aload_0 14: invokevirtual #25; //Method java/lang/Object.getClass:()Ljava/lang/Class; 17: aload_1 18: invokevirtual #25; //Method java/lang/Object.getClass:()Ljava/lang/Class; 21: if_acmpeq 26 24: iconst_0 25: ireturn
我省略了我之后编写的代码以使其编译.
两者都没有比另一个更有效率.编译器可以很容易地看到两者是相同的,实际上Suns/Oracles 为这两种方法javac
生成相同的字节码.
这是一IfTest
堂课:
class IfTest {
public boolean eq1(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
return true;
}
public boolean eq2(Object obj) {
if (this == obj)
return true;
else if (obj == null)
return false;
else if (getClass() != obj.getClass())
return false;
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
我编译了它,javac
反汇编如下:
public boolean eq1(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: if_acmpne 7
5: iconst_1
6: ireturn
7: aload_1
8: ifnonnull 13
11: iconst_0
12: ireturn
13: aload_0
14: invokevirtual #2; //Method Object.getClass:()Ljava/lang/Class;
17: aload_1
18: invokevirtual #2; //Method Object.getClass:()Ljava/lang/Class;
21: if_acmpeq 26
24: iconst_0
25: ireturn
26: iconst_1
27: ireturn
Run Code Online (Sandbox Code Playgroud)
public boolean eq2(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: if_acmpne 7
5: iconst_1
6: ireturn
7: aload_1
8: ifnonnull 13
11: iconst_0
12: ireturn
13: aload_0
14: invokevirtual #2; //Method Object.getClass:()Ljava/lang/Class;
17: aload_1
18: invokevirtual #2; //Method Object.getClass:()Ljava/lang/Class;
21: if_acmpeq 26
24: iconst_0
25: ireturn
26: iconst_1
27: ireturn
Run Code Online (Sandbox Code Playgroud)
也就是说,我建议使用第一个版本(没有else
).有些人可能认为它与其他部分相比更干净,但我认为相反.包括在else
表明程序员并没有意识到,这是不必要的.
我认为没有任何实际理由可以用任何方向替换其中一个实现.
如果你想在一种方法中避免多个return语句,那么第二个例子就有意义了 - 有些人更喜欢这种编码方式.然后我们需要if-else if构造:
public boolean equals(Object obj)
{
boolean result = true;
if (this == obj)
result = true;
else if (obj == null)
result = false;
else if (getClass() != obj.getClass())
result = false;
return result;
}
Run Code Online (Sandbox Code Playgroud)