282

我知道,如果您将盒装原始整数与常量进行比较,例如:

Integer a = 4;
if (a < 5)

a将自动取消装箱并且比较将起作用。

但是,当您比较两个装箱Integers并想要比较相等或小于/大于时会发生什么?

Integer a = 4;
Integer b = 5;

if (a == b)

上面的代码会导致检查它们是否是同一个对象,还是会在这种情况下自动拆箱?

关于什么:

Integer a = 4;
Integer b = 5;

if (a < b)

?

4

10 回答 10

378

不,== 在 Integer、Long 等之间将检查引用是否相等- 即

Integer x = ...;
Integer y = ...;

System.out.println(x == y);

这将检查是否xy引用相同的对象而不是相等的对象。

所以

Integer x = new Integer(10);
Integer y = new Integer(10);

System.out.println(x == y);

保证打印false。“小”自动装箱值的实习可能会导致棘手的结果:

Integer x = 10;
Integer y = 10;

System.out.println(x == y);

true由于拳击规则(JLS 第 5.1.7 节),这将打印出来。它仍然使用引用相等,但引用确实相等的。

如果被装箱的值 p 是 int 类型的整数文字,介于 -128 和 127 之间(第 3.10.1 节),或者布尔文字真或假(第 3.10.3 节),或者是介于 '\u0000' 和'\u007f' (第 3.10.4 节),则令 a 和 b 为 p 的任意两次装箱转换的结果。a == b 总是如此。

我个人会使用:

if (x.intValue() == y.intValue())

或者

if (x.equals(y))

Integer正如您所说,对于包装器类型(等Long)和数字类型(int等)之间的任何比较,long包装器类型值被取消装箱,并且测试应用于所涉及的原始值。

这作为二进制数字提升的一部分发生(JLS 第 5.6.2 节)。查看每个操作员的文档以查看它是否已应用。例如,来自==and !=( JLS 15.21.1 ) 的文档:

如果相等运算符的操作数都是数字类型,或者一个是数字类型而另一个是可转换的(第 5.1.8 节)为数字类型,则对操作数执行二进制数字提升(第 5.6.2 节)。

<, <=,>>=( JLS 15.20.1 )

数值比较运算符的每个操作数的类型必须是可转换(第 5.1.8 节)为原始数值类型的类型,否则会发生编译时错误。对操作数执行二进制数字提升(第 5.6.2 节)。如果操作数的提升类型是 int 或 long,则执行有符号整数比较;如果此提升的类型是 float 或 double,则执行浮点比较。

请注意,这些都不被视为两种类型都不是数字类型的情况的一部分。

于 2009-10-04T07:10:48.770 回答
48

==仍将测试对象相等性。然而,很容易被愚弄:

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)。这是一个不错的优化,因为原始盒子类是不可变的。

于 2009-10-03T21:39:49.090 回答
42

从 Java 1.7 开始,您可以使用Objects.equals

java.util.Objects.equals(oneInteger, anotherInteger);

如果参数彼此相等,则返回 true,否则返回 false。因此,如果两个参数都为 null,则返回 true,如果恰好一个参数为 null,则返回 false。否则,相等性是通过使用第一个参数的 equals 方法来确定的。

于 2018-03-22T14:57:04.207 回答
16

我们应该总是使用 equals() 方法来比较两个整数。这是推荐的做法。

如果我们使用 == 比较两个整数,由于 JVM 的内部优化,这将适用于特定范围的整数值(从 -128 到 127 的整数)。

请看示例:

情况1:

Integer a = 100;
Integer b = 100;

if (a == b) {
  System.out.println("a and b are equal");
} else {
  System.out.println("a and b are not equal");
}

在上述情况下,JVM 使用缓存池中的 a 和 b 的值并返回整数对象的相同对象实例(因此是内存地址),我们得到两者相等。它是JVM对某些范围值进行的优化。

情况 2:在这种情况下,a 和 b 不相等,因为它不包含从 -128 到 127 的范围。

Integer a = 220;
Integer b = 220;
   
if (a == b) {
  System.out.println("a and b are equal");
} else {
  System.out.println("a and b are not equal");
}

合适的方式:

Integer a = 200;             
Integer b = 200;  
System.out.println("a == b? " + a.equals(b)); // true
于 2019-12-04T12:51:55.040 回答
10

tl;博士我的意见是+在检查值相等时使用一元来触发对其中一个操作数的拆箱,否则只需使用数学运算符。理由如下:

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

我使用了通常的一堆方法:

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 只是触发身份比较,是不正确的方法比较值。

由于(如 JS 已经提到的)equals()会产生开销(它必须做instanceof和未经检查的强制转换),方法 2-4 将以完全相同的速度工作,在紧密循环中使用时明显优于方法 1,因为 HotSpot 不是可能会优化演员表 & instanceof

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

在我看来,很少使用的版本 4 是最简洁的方式——每个经验丰富的 C/Java 开发人员都知道一元加号在大多数情况下等于强制转换为int/ .intValue()——而对于某些人(主要是那些没有't 在他们的生命周期中使用一元加号),它可以说是最清楚和最简洁地显示了意图 - 它表明我们想要一个操作数的值,迫使另一个值也取消装箱。毫无疑问,它与用于原始值的常规比较最相似。inti1 == i2int

出于性能和一致性的原因,我的投票赞成对象i1 == +i2的风格i1 > i2Integer它还使代码可移植到原语,而无需更改类型声明以外的任何内容。使用命名方法似乎给我带来了语义噪音,类似于备受批评的bigInt.add(10).multiply(-3)风格。

于 2015-05-23T16:52:51.993 回答
10

== checks for reference equality, however when writing code like:

Integer a = 1;
Integer b = 1;

Java is smart enough to reuse the same immutable for a and b, so this is true: a == b. Curious, I wrote a small example to show where java stops optimizing in this way:

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");
    }
}

When I compile and run this (on my machine), I get:

Done: 128
于 2015-07-15T21:30:13.693 回答
8

打电话

if (a == b)

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

假设它们被命名为“a”和“b”,比较两个 Integer 类是否相等的最正确方法是调用:

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");
}
于 2016-09-22T17:55:40.567 回答
1

在我的情况下,我必须比较两个Integers 是否相等,它们都可能是 s null。我搜索了类似的主题,但我没有找到任何优雅的东西。我想出了简单的实用功能:

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);
}
于 2018-09-21T01:14:52.940 回答
-1

因为必须使用正确的运算符基于类型 int (x==y) 或类 Integer (x.equals(y)) 进行比较方法:

public class Example {

    public static void main(String[] args) {
        int[] arr = {-32735, -32735, -32700, -32645, -32645, -32560, -32560};

        for(int j=1; j<arr.length-1; j++)
            if((arr[j-1] != arr[j]) && (arr[j] != arr[j+1]))
                System.out.println("int>" + arr[j]);

        Integer[] I_arr = {-32735, -32735, -32700, -32645, -32645, -32560, -32560};

        for(int j=1; j<I_arr.length-1; j++)
            if((!I_arr[j-1].equals(I_arr[j])) && (!I_arr[j].equals(I_arr[j+1])))
                System.out.println("Interger>" + I_arr[j]);
    }
}
于 2019-10-03T09:37:09.443 回答
-2

此方法将两个整数与空检查进行比较。查看测试。

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
于 2017-03-02T12:06:52.193 回答