为什么整数常量池的行为在127处变化?

时间:2012-10-27 07:21:22

标签: java integer constants

我无法理解Java Constant Pool for Integer的工作原理。

我理解字符串的行为,因此能够证明自己与整数常量的情况相同。

所以,对于整数

Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1==i2); // True

&安培;

Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1==i2); // False

直到这里,一切都在我的脑海里。

我无法消化的是,当我从127增加整数时,它的行为有所不同。此行为在127之后发生变化,下面是代码片段

Integer i1 = 128;
Integer i2 = 128;
System.out.println(i1==i2); // False. WHY?????

有人能帮我理解吗?

4 个答案:

答案 0 :(得分:44)

不,数字的常量池与字符串的工作方式不同。对于字符串,只有编译时常量被实现 - 而对于整数类型的包装类型,任何装箱操作总是使用该池,如果它适用于该值。例如:

int x = 10;
int y = x + 1;
Integer z = y; // Not a compile-time constant!
Integer constant = 11;
System.out.println(z == constant); // true; reference comparison

JLS保证了一小部分池化值,但如果愿意,实现可以使用更广泛的范围。

请注意,尽管不能保证,但我所看到的每个实现都使用Integer.valueOf来执行装箱操作 - 所以在没有语言帮助的情况下你可以获得相同的效果:

Integer x = Integer.valueOf(100);
Integer y = Integer.valueOf(100);
System.out.println(x == y); // true

来自section 5.1.7 of the JLS

  

如果装箱的值p为真,假,字节或范围为\ u0000到\ u007f的字符,或者介于-128和127(含)之间的整数或短数,则让r1和r2为p的任意两次拳击转换的结果。始终是r1 == r2。

的情况      

理想情况下,装箱给定的原始值p将始终产生相同的参考。实际上,使用现有的实现技术可能不可行。上述规则是一种务实的妥协。上面的最后一个条款要求将某些常见值装入无法区分的对象中。实现可以懒惰地或急切地缓存这些。对于其他值,此公式不允许对程序员的盒装值的身份进行任何假设。这将允许(但不要求)共享部分或全部这些引用。

     

这确保了在大多数情况下,行为将是所需的行为,而不会造成过度的性能损失,尤其是在小型设备上。例如,较少内存限制的实现可以缓存所有char和short值,以及-32K到+ 32K范围内的int和long值。

答案 1 :(得分:19)

Java维护从-128127

的整数池

如下所示声明整数

Integer i1 = 127;

结果

Integer i1 = Integer.valueOf(127);

所以第一种情况实际发生的是

Integer i1 = 127;<---Integer.valueOf(127);
Integer i2 = 127;<---Integer.valueOf(127);<---Same reference as first

来自IntegervalueOf方法的源代码

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

如果值介于-128127之间,并且您调用valueOf,则会获得相同的引用,否则它只返回new Integer(i)

因为引用相同,所以==运算符适用于valueOf在此范围之间返回的整数。

答案 2 :(得分:8)

Java缓存-128 to 127范围内的整数对象。因此,当您尝试将此范围中的值分配给wrapper对象时,boxing操作将调用Integer.valueOf方法,然后它将分配对已在该对象中的对象的引用池。

另一方面,如果您将此范围之外的值指定为wrapper引用类型,Integer.valueOf将为该值创建新的Integer对象。因此,比较具有此范围之外的值的referenceInteger对象将为您提供false

所以,

Integer i = 127;  --> // Equivalent to `Integer.valueOf(127)`
Integer i2 = 127;

// Equivalent to `Integer.valueOf(128)`
// returns `new Integer(128)` for value outside the `Range - [-128, 127]`
Integer i3 = 128; 
Integer i4 = 128;

System.out.println(i == i2); // true, reference pointing to same literal
System.out.println(i3 == i4); // false, reference pointing to different objects

但是,当您使用new运算符创建整数实例时,将在Heap上创建一个新对象。 所以,

Integer i = new Integer(127);
Integer i2 = new Integer(127);

System.out.println(i == i2); // false

答案 3 :(得分:2)

简而言之,较新版本的Java缓存Integer在-128到127范围内(256个值)。 看这里

What exactly does comparing Integers with == do?