Java中整数的!=和==运算符是如何工作的?

11

以下代码对我来说看起来很令人困惑,因为它提供了两个不同的输出。这段代码在JDK 1.7上进行了测试。

public class NotEq {

public static void main(String[] args) {

    ver1();
    System.out.println();
    ver2();
}

public static void ver1() {
    Integer a = 128;
    Integer b = 128;

    if (a == b) {
        System.out.println("Equal Object");
    }

    if (a != b) {
        System.out.println("Different objects");
    }

    if (a.equals(b)) {
        System.out.println("Meaningfully equal.");
    }
}

public static void ver2() {
    Integer i1 = 127;
    Integer i2 = 127;
    if (i1 == i2) {
        System.out.println("Equal Object");
    }

    if (i1 != i2){
        System.out.println("Different objects");
    }
    if (i1.equals(i2)){
        System.out.println("Meaningfully equal");
    }
}

}

输出:

[ver1 输出]
不同的对象
具有实际相等性。

[ver2 输出]
相等的对象
具有实际相等性

为什么对于值远小于Integer.MAX_VALUE的数字,== 和 != 检测会为 ver1() 和 ver2() 产生不同的结果?可以得出结论,对于大于127的数字(如代码中的 Integer 包装类),使用 == 进行检测完全是浪费时间吗?


3
这是因为自动装箱机制会为范围在-128到127之间的数值缓存并重复使用相同的对象。这是先前问题的一个副本。 - aioobe
1
https://dev59.com/jXI-5IYBdhLWcg3wu7Lv - Ciro Santilli OurBigBook.com
5个回答

10

整数值在-128到127之间时将被缓存,因此Integer i = 127将始终返回相同的引用。但Integer j = 128不一定如此。然后您需要使用equals来测试底层的int是否相等。

这是Java语言规范的一部分:

如果要封装的值p为true、false、一个字节或者字符(\u0000 to \u007f)中的任意一个,或者是-128到127(包括两端)之间的一个int或short类型的数字,则r1和r2是任何两个封箱转换的结果。结果总是r1 == r2。

但是,对Integer j = 128的2个调用可能返回相同的引用(但不是保证):

内存不受限制的实现可能会缓存所有char和short值,以及-32K到+32K范围内的int和long值。


构造函数不使用缓存。尝试:System.out.println(new Integer(2) == new Integer(2)) - fgb
1
new Integer(127) 永远不会返回相同的引用。事实上,它保证始终创建一个新对象。但是当像 Integer i = 127; 这样使用自动装箱时,缓存就会被使用。顺便说一下,上限 127 不是固定的,而是一个最小值。它可以配置为更大的值,但不能更低。 - Fabian Barney

4

由于Java中小整数被内部化,你尝试使用了小于和大于“小整数”限制的数字。


@downvoter,您是否可以详细说明您的投票原因? - Sergey Kalinichenko

3

默认情况下,存在一个从-128到127的整数对象缓存。可以配置上限边界。可以通过VM选项-XX:AutoBoxCacheMax=<size>控制上限缓存边界。

当您使用以下形式时,即在使用此缓存:

 Integer i1 = 127;

或者
Integer i1 = Integer.valueOf(127);

但是当您使用时
Integer i1 = new Integer(127);

如果您使用新的未缓存对象,那么就可以确保获得一个新的未缓存对象。在后一种情况下,两个版本都打印出相同的结果。如果使用缓存版本,它们可能会有所不同。

好知道。请不要在生产环境中这样做。 - atamanroman

0
Java 缓存 -128 到 127 的整数,这就是为什么对象是相同的原因。

0

我认为在处理基本类型时,== 和!= 运算符将按照您当前的使用方式工作,但是对于对象(Integer vs. int),您需要使用 .equals() 方法进行测试。

我不确定这一点,但是对于对象,== 将测试一个对象是否与另一个对象相同,而 .equals() 将执行测试,以确保这两个对象包含等价的值(或者需要为自定义对象创建/覆盖该方法)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接