194
class D {
    public static void main(String args[]) {
        Integer b2=128;
        Integer b3=128;
        System.out.println(b2==b3);
    }
}

输出:

false

class D {
    public static void main(String args[]) {
        Integer b2=127;
        Integer b3=127;
        System.out.println(b2==b3);
    }
}

输出:

true

注意:-128 到 127 之间的数字为真。

4

8 回答 8

238

当您在 Java 中编译数字文字并将其分配给整数(大写I)时,编译器会发出:

Integer b2 =Integer.valueOf(127)

使用自动装箱时也会生成这行代码。

valueOf实现了某些数字被“池化”,并且它为小于 128 的值返回相同的实例。

从 java 1.6 源代码,第 621 行:

public static Integer valueOf(int i) {
    if(i >= -128 && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}

可以使用系统属性将 的值high配置为另一个值。

-Djava.lang.Integer.IntegerCache.high=999

如果您使用该系统属性运行程序,它将输出 true!

显而易见的结论:永远不要依赖两个相同的引用,总是将它们与.equals()方法进行比较。

因此b2.equals(b3),对于 b2,b3 的所有逻辑相等值,将打印 true。

请注意,Integer缓存不是出于性能原因,而是为了符合JLS,第 5.1.7 节;必须为值 -128 到 127(含)提供对象标识。

Integer#valueOf(int)也记录了这种行为:

通过缓存频繁请求的值,此方法可能会显着提高空间和时间性能。此方法将始终缓存 -128 到 127(含)范围内的值,并且可能缓存此范围之外的其他值。

于 2009-11-09T10:06:18.890 回答
27

自动装箱缓存 -128 到 127。这在 JLS ( 5.1.7 ) 中指定。

如果被装箱的值p是真、假、一个字节、一个在 \u0000 到 \u007f 范围内的字符,或者一个介于 -128 和 127 之间的 int 或短数字,则令 r1 和 r2 为任意两次装箱转换的结果p。r1 == r2 总是如此。

处理对象时要记住的一个简单规则是 -.equals如果您想检查两个对象是否“相等”,请使用==,当您想查看它们是否指向同一个实例时使用。

于 2009-11-09T10:04:14.143 回答
11

使用原始数据类型 ints 在这两种情况下都会产生预期的输出。

但是,由于您使用的是 Integer 对象,因此 == 运算符具有不同的含义。

在对象的上下文中, == 检查变量是否引用相同的对象引用。

要比较对象的值,您应该使用 equals() 方法,例如

 b2.equals(b1)

这将指示 b2 是否小于 b1、大于或等于(查看 API 了解详细信息)

于 2009-11-09T10:09:09.873 回答
8

它与Java相关的内存优化。

为了节省内存,Java“重用”所有值在以下范围内的包装对象:

所有布尔值(真和假)

所有字节值

从 \u0000 到 \u007f 的所有字符值(即十进制的 0 到 127)

从 -128 到 127 的所有 Short 和 Integer 值。

于 2016-02-26T07:25:31.523 回答
4

看一下 Integer.java,如果值在 -128 到 127 之间,就会使用缓存池,所以(Integer) 1 == (Integer) 1while(Integer) 222 != (Integer) 222

 /**
 * Returns an {@code Integer} instance representing the specified
 * {@code int} value.  If a new {@code Integer} instance is not
 * required, this method should generally be used in preference to
 * the constructor {@link #Integer(int)}, as this method is likely
 * to yield significantly better space and time performance by
 * caching frequently requested values.
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}       
于 2016-02-16T02:05:28.767 回答
2

其他答案描述了为什么可以观察到观察到的效果,但这对程序员来说真的是无关紧要的(当然很有趣,但在编写实际代码时你应该忘记这一切)。

要比较 Integer 对象的相等性,请使用该equals方法。

不要尝试使用恒等运算符比较 Integer 对象的相等性==

可能会发生一些相等的值是相同的对象,但这不是通常应该依赖的东西。

于 2020-06-08T22:54:31.300 回答
0

如果该值介于 -128 和 127 之间,它将使用缓存池,并且仅在 auto-boxing 时才如此。因此,您将拥有以下内容:

    public static void main(String[] args) {
        Integer a  = new Integer(100);
        Integer b = new Integer(100);
        System.out.println(a == b);         // false. == compare two instances, they are difference
        System.out.println(a.equals(b));    // true. equals compares the value

        Integer a2 = 100;
        Integer b2 = 100;
        System.out.println(a2 == b2);       // true. auto-boxing uses cached pool between -128/127
        System.out.println(a2.equals(b2));  // true. equals compares the value

        Integer a3 = 129;
        Integer b3 = 129;
        System.out.println(a3 == b3);       // false. not using cached pool
        System.out.println(a3.equals(b3));  // true. equals compares the value
    }
}
于 2022-02-03T20:20:10.537 回答
-4

我写了以下内容,因为这个问题不仅仅针对 Integer。我的结论是,如果您不正确地使用 API,您通常会看到不正确的行为。正确使用它,您应该会看到正确的行为:

public static void main (String[] args) {
    Byte b1=127;
    Byte b2=127;

    Short s1=127; //incorrect should use Byte
    Short s2=127; //incorrect should use Byte
    Short s3=128;
    Short s4=128;

    Integer i1=127; //incorrect should use Byte
    Integer i2=127; //incorrect should use Byte
    Integer i3=128;
    Integer i4=128;

    Integer i5=32767; //incorrect should use Short
    Integer i6=32767; //incorrect should use Short

    Long l1=127L;           //incorrect should use Byte
    Long l2=127L;           //incorrect should use Byte
    Long l3=13267L;         //incorrect should use Short
    Long l4=32767L;         //incorrect should use Short
    Long l5=2147483647L;    //incorrect should use Integer 
    Long l6=2147483647L;    //incorrect should use Integer
    Long l7=2147483648L;
    Long l8=2147483648L;

    System.out.print(b1==b2); //true  (incorrect) Used API correctly
    System.out.print(s1==s2); //true  (incorrect) Used API incorrectly
    System.out.print(i1==i2); //true  (incorrect) Used API incorrectly
    System.out.print(l1==l2); //true  (incorrect) Used API incorrectly

    System.out.print(s3==s4); //false (correct) Used API correctly
    System.out.print(i3==i4); //false (correct) Used API correctly
    System.out.print(i5==i6); //false (correct) Used API correctly
    System.out.print(l3==l4); //false (correct) Used API correctly
    System.out.print(l7==l8); //false (correct) Used API correctly
    System.out.print(l5==l6); //false (correct) Used API incorrectly

}
于 2012-06-11T08:19:09.020 回答