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

Viv*_*vek 36 java integer constants

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

我理解字符串的行为,因此能够证明自己与Integer Constants的情况相同.

所以,对于整数

Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1==i2); // True
Run Code Online (Sandbox Code Playgroud)

&

Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1==i2); // False
Run Code Online (Sandbox Code Playgroud)

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

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

Integer i1 = 128;
Integer i2 = 128;
System.out.println(i1==i2); // False. WHY?????
Run Code Online (Sandbox Code Playgroud)

有人可以帮我理解吗?

Jon*_*eet 45

不,数字的常量池与字符串的工作方式不同.对于字符串,仅实现编译时常量 - 而对于整数类型的包装类型,任何装箱操作将始终使用池(如果它适用于该值).例如:

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
Run Code Online (Sandbox Code Playgroud)

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

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

Integer x = Integer.valueOf(100);
Integer y = Integer.valueOf(100);
System.out.println(x == y); // true
Run Code Online (Sandbox Code Playgroud)

JLS的5.1.7节:

如果被装箱值p为真,假,字节,或在范围\ u0000的一个char到\ u007f,或int或-128和127(含)之间的短号码,然后让r1和r2是的结果p的任何两个拳击转换.始终是r1 == r2的情况.

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

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


Ami*_*nde 20

Java维护整数池-128127

像下面一样声明整数

Integer i1 = 127;
Run Code Online (Sandbox Code Playgroud)

结果到

Integer i1 = Integer.valueOf(127);
Run Code Online (Sandbox Code Playgroud)

那么第一种情况实际发生的是

Integer i1 = 127;<---Integer.valueOf(127);
Integer i2 = 127;<---Integer.valueOf(127);<---Same reference as first
Run Code Online (Sandbox Code Playgroud)

IntegervalueOf 方法的源代码

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

因此,如果值介于-128to 之间,则会得到相同的引用,127并且您调用valueOfelse,它只返回new Integer(i)

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

  • 提及Integer.valueOf()的+1.其他答案似乎认为这只是魔术. (2认同)

Roh*_*ain 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
Run Code Online (Sandbox Code Playgroud)

但是,当您使用newoperator 创建整数实例时,将在Heap上创建一个新对象.所以,

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

System.out.println(i == i2); // false
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

19629 次

最近记录:

10 年,4 月 前