Java:if-return-if-return与if-return-elseif-return

|| 问了一个不相关的问题,我在哪里有这样的代码:
public boolean equals(Object obj)
{
    if (this == obj)
        return true;

    if (obj == null)
        return false;

    if (getClass() != obj.getClass())
        return false;

    // Check property values
}
我收到一条评论,声称这不是最佳选择,相反(如果我理解正确的话)应该这样做:
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
}
由于return语句,我无法真正理解为什么其中任何一个都应该比另一个更高效或更快速。给定一个对象,据我所知,这两种方法都必须进行相同数量的检查。而且由于return语句,任何其他代码都不会运行。 我在这里想念什么吗?有东西吗?是否有一些编译器优化或正在进行的工作? 我知道这是微优化,我很可能会坚持第一种方法,因为我认为所有if都在同一位置看起来更干净。但我无能为力;我很好奇!     
已邀请:
对于这两种情况,生成的字节码是相同的,因此纯粹是样式问题。 我产生了两种方法
e1
e2
,并且都产生了这个字节码(使用
javap -v
读取): 公共布尔e1(java.lang.Object);   码:    堆栈= 2,局部变量= 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; //方法java / lang / Object.getClass :()Ljava / lang / Class;    17:aload_1    18:invokevirtual#25; //方法java / lang / Object.getClass :()Ljava / lang / Class;    21:if_acmpeq 26    24:iconst_0    25:ireturn 在此之后,我省略了放置的代码以进行编译。     
任一个都不比另一个更有效。编译器可以很容易地看出两者是相同的,实际上Suns / Oracles“ 5”为这两种方法产生了相同的字节码。 这是一个
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;
    }
}
我用
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
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
也就是说,我建议使用第一个版本(不带
else
)。有人可能会说其他部分比较干净,但我会相反。包括“ 11”表示程序员没有意识到这是不必要的。     
我看不出有任何实际原因可以在任何方向上用另一种实现替换这些实现。 如果您想避免在一种方法中使用多个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;
}
    
这样想吧。当执行return语句时,控件将保留该方法,因此
else
并不会真正增加任何值,除非您想证明它会增加可读性(我并不认为这样做会增加可读性,但其他人可能会不同意)。 。 所以当你有:
if (someCondition)
    return 42;

if (anotherCondition)
    return 43;
将ѭ11加到第二个
if
并没有任何价值。 实际上,我在编写称为Resharper的C#代码时使用了一个工具,在这种情况下,它实际上会将ѭ11标记为无用的代码。因此,我认为通常最好将它们排除在外。正如Joachim所述,编译器无论如何都会对其进行优化。     
我认为此代码可以进行一些改进(请注意,它非常可读):
  if (obj == null)
        return false;

  if (getClass() != obj.getClass())
        return false;
instanceof
运算符等同于两者的组合,并且可能更快—更少的代码,而且没有方法调用:
  if (!(obj instanceof MyClass))
        return false;
但是我知道什么...。我太懒了,无法分析字节码(以前从未做过)。 :-p     

要回复问题请先登录注册