我知道如果你比较一个装箱的原语Integer和一个常量,比如:

Integer a = 4;
if (a < 5)

A将自动被打开,比较将会起作用。

但是,当您比较两个带框的整数并希望比较相等或小于/大于时会发生什么?

Integer a = 4;
Integer b = 5;

if (a == b)

上面的代码是否会检查它们是否是同一个对象,或者在这种情况下它会自动开箱吗?

是什么:

Integer a = 4;
Integer b = 5;

if (a < b)

?


当前回答

我的意见是,在检查值是否相等时,使用一元+来触发对其中一个操作数的开箱操作,否则只需使用数学操作符。基本原理:

已经提到,Integer的==比较是恒等比较,这通常不是程序员想要的,其目的是做值比较;尽管如此,我还是做了一些关于如何最有效地进行比较的科学研究,包括代码的紧凑性、正确性和速度。

我用了一些常用的方法:

public boolean method1() {
    Integer i1 = 7, i2 = 5;
    return i1.equals( i2 );
}

public boolean method2() {
    Integer i1 = 7, i2 = 5;
    return i1.intValue() == i2.intValue();
}

public boolean method3() {
    Integer i1 = 7, i2 = 5;
    return i1.intValue() == i2;
}

public boolean method4() {
    Integer i1 = 7, i2 = 5;
    return i1 == +i2;
}

public boolean method5() { // obviously not what we want..
    Integer i1 = 7, i2 = 5;
    return i1 == i2;
}

并在编译和反编译后得到以下代码:

public boolean method1() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    return var1.equals( var2 );
}

public boolean method2() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method3() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method4() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2.intValue() == var1.intValue() ) {
        return true;
    } else {
        return false;
    }
}

public boolean method5() {
    Integer var1 = Integer.valueOf( 7 );
    Integer var2 = Integer.valueOf( 5 );

    if ( var2 == var1 ) {
        return true;
    } else {
        return false;
    }
}

可以很容易地看到,方法1调用Integer.equals()(显然),方法2-4产生完全相同的代码,通过. intvalue()展开值,然后直接比较它们,而方法5只是触发标识比较,这是比较值的不正确方式。

由于equals()会产生开销(它必须执行instanceof和未检查的强制转换),方法2-4将以完全相同的速度工作,在紧循环中使用时明显优于方法1,因为HotSpot不太可能优化出强制转换和instanceof。

它与其他比较操作符(例如</>)非常相似——它们将触发开箱,而使用compareTo()不会——但这一次,操作由HS高度优化,因为intValue()只是一个getter方法(被优化的主要候选方法)。

In my opinion, the seldom used version 4 is the most concise way - every seasoned C/Java developer knows that unary plus is in most cases equal to cast to int/.intValue() - while it may be a little WTF moment for some (mostly those who didn't use unary plus in their lifetime), it arguably shows the intent most clearly and most tersely - it shows that we want an int value of one of the operands, forcing the other value to unbox as well. It is also unarguably most similar to the regular i1 == i2 comparison used for primitive int values.

对于Integer对象,我的投票是i1 == +i2 & i1 > i2风格,这是出于性能和一致性的考虑。它还使代码可以移植到原语,而不需要更改类型声明以外的任何内容。对我来说,使用命名方法似乎引入了语义噪声,类似于备受批评的bigInt.add(10).multiply(-3)风格。

其他回答

这个方法用空检查比较两个Integer。请参阅测试。

public static boolean compare(Integer int1, Integer int2) {
    if(int1!=null) {
        return int1.equals(int2);
    } else {
        return int2==null;
    }
    //inline version:
       //return (int1!=null) ? int1.equals(int2) : int2==null;
}

//results:
System.out.println(compare(1,1));           //true
System.out.println(compare(0,1));           //false
System.out.println(compare(1,0));           //false
System.out.println(compare(null,0));        //false
System.out.println(compare(0,null));        //false
System.out.println(compare(null,null));        //true

在我的情况下,我必须比较两个整数是否相等,其中它们都可以为空。我搜索了类似的主题,但没有找到合适的。我想出了一个简单的效用函数:

public static boolean integersEqual(Integer i1, Integer i2) {
    if (i1 == null && i2 == null) {
        return true;
    }
    if (i1 == null && i2 != null) {
        return false;
    }
    if (i1 != null && i2 == null) {
        return false;
    }
    return i1.intValue() == i2.intValue();
}

// Considering null is less than not-null
public static int integersCompare(Integer i1, Integer i2) {
    if (i1 == null && i2 == null) {
        return 0;
    }
    if (i1 == null && i2 != null) {
        return -1;
    }
    return i1.compareTo(i2);
}

==仍然测试对象是否相等。然而,这很容易被愚弄:

Integer a = 10;
Integer b = 10;

System.out.println(a == b); //prints true

Integer c = new Integer(10);
Integer d = new Integer(10);

System.out.println(c == d); //prints false

你使用不等式的例子是可以工作的,因为它们不是在对象上定义的。但是,使用==比较时,仍然会检查对象是否相等。在这种情况下,当你从一个盒装的原语中初始化对象时,使用了相同的对象(对于a和b)。这是一个不错的优化,因为原语盒类是不可变的。

==检查引用是否相等,但是当编写如下代码时:

Integer a = 1;
Integer b = 1;

Java足够聪明,可以为a和b重用相同的不可变变量,所以这是正确的:a == b。好奇的是,我写了一个小例子来说明Java停止以这种方式优化的地方:

public class BoxingLol {
    public static void main(String[] args) {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            Integer a = i;
            Integer b = i;
            if (a != b) {
                System.out.println("Done: " + i);
                System.exit(0);
            }
        }
        System.out.println("Done, all values equal");
    }
}

当我编译和运行这个(在我的机器上),我得到:

Done: 128

调用

if (a == b)

大部分时间都有效,但不能保证总是有效,所以不要使用它。

比较两个Integer类是否相等的最合适的方法是,假设它们分别命名为'a'和'b',调用:

if(a != null && a.equals(b)) {
  System.out.println("They are equal");
}

你也可以用这种稍微快一点的方法。

   if(a != null && b != null && (a.intValue() == b.intValue())) {
      System.out.println("They are equal");
    } 

在我的机器上,使用第一种方法执行990亿次操作需要47秒,使用第二种方法需要46秒。您需要比较数十亿个值才能看到任何差异。

注意,'a'可能是空的,因为它是一个对象。以这种方式进行比较不会导致空指针异常。

用于比较大于和小于,使用

if (a != null && b!=null) {
    int compareValue = a.compareTo(b);
    if (compareValue > 0) {
        System.out.println("a is greater than b");
    } else if (compareValue < 0) {
        System.out.println("b is greater than a");
    } else {
            System.out.println("a and b are equal");
    }
} else {
    System.out.println("a or b is null, cannot compare");
}