当比较Java中的Integer包装器时,为什么128 == 128 false但127 == 127为真?

时间:2009-11-09 09:58:51

标签: java integer comparison pass-by-reference pass-by-value

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之间的数字为真。

7 个答案:

答案 0 :(得分:195)

在Java中编译数字文字并将其分配给Integer(大写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,b3值,b2.equals(b3)将打印为true。

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

Integer#valueOf(int)也会记录此行为:

  

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

答案 1 :(得分:21)

Autoboxing缓存-128到127.这在JLS(5.1.7)中指定。

  

如果 p 的值为true,则为false,一个字节,范围为\ u0000到\ u007f的字符,或者介于-128之间的int或short数字   127,然后让r1和r2成为任意两次拳击转换的结果   p。始终是r1 == r2。

的情况

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

答案 2 :(得分:8)

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

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

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

要比较对象的值,您应该使用equals()方法 E.g。

 b2.equals(b1)

表示b2是否小于b1,大于或等于(查看API详情)

答案 3 :(得分:7)

与Java相关的内存优化。

  

为了节省内存,Java&#39;重用&#39;所有包装器对象的值   属于以下范围:

     

所有布尔值(true和false)

     

所有字节值

     

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

     

从-128到127的所有短整数和整数值。

答案 4 :(得分:2)

看看Integer.java,如果值介于-128和127之间,它将使用缓存池,因此(Integer) 1 == (Integer) 1(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);
}       

答案 5 :(得分:1)

其他答案描述了为什么可以观察到所观察到的效果,但这实际上与程序员的意义无关(当然很有趣,但是在编写实际代码时您应该忘记所有这些)。

要比较Integer对象是否相等,请使用equals方法。

请勿尝试使用身份运算符==比较Integer对象是否相等。

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

答案 6 :(得分:-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

}