Why Does the Behavior of the Integer Constant Pool Change at 127

Why does the behavior of the Integer constant pool change at 127?

No, the constant pool for numbers doesn't work the same way as for strings. For strings, only compile-time constants are interned - whereas for the wrapper types for integer types, any boxing operation will always use the pool if it's applicable for that value. So for example:

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

The JLS guarantees a small range of pooled values, but implementations can use a wider range if they wish.

Note that although it's not guaranteed, every implementation I've looked at uses Integer.valueOf to perform boxing operations - so you can get the same effect without the language's help:

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

From section 5.1.7 of the JLS:

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

Ideally, boxing a given primitive value p, would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rules above are a pragmatic compromise. The final clause above requires that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, this formulation disallows any assumptions about the identity of the boxed values on the programmer's part. This would allow (but not require) sharing of some or all of these references.

This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K.

Java Integer pool. Why?

It's called the Flyweight pattern and is used to minimize memory usage.

Those numbers are very likely to be used repeatedly, and autobox types like Integer are immutable (note this is done not just for Integer). Caching them makes it so there aren't lots of instances and reduces GC (Garbage Collection) work as well.

The JLS covers this in 5.1.7. Boxing Conversion specifically by saying:

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

Ideally, boxing a given primitive value p, would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rules above are a pragmatic compromise. The final clause above requires that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, this formulation disallows any assumptions about the identity of the boxed values on the programmer's part. This would allow (but not require) sharing of some or all of these references.

This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K.

Comparison of int to Integer not working after adding to Linkedlist

Do it as follows:

System.out.println(i.equals(ll.peek()));

Remember, == compares the references, not the content.

Check Why is 128==128 false but 127==127 is true when comparing Integer wrappers in Java? to understand why it returned true for a number less than 128.

Why Integers act as interns only for the values less than 128 (default) in java

Technically the values are pre-cached when the class is loaded. It is not like String.intern() where a value you created can be returned.

Also the maximum might not be 127, it can be higher if you set it so or use options like -XX:+AggressiveOpts

The default range is likely to be chosen just to be consistent with Byte. Note: the cached values are

Boolean: both values
Byte: all
Character: 0 to 127
Short: -128 to 127
Integer: -128 to 127
Long: -128 to 127
Float and Double: none
BigInteger: -16 to 16 (in HotSpot Java 7)
BigDecimal: 0 to 10 (if you use valueOf(long)) and
0 to 0.000000000000000 (if you use valueOf(long, int)) (in HotSpot Java 7)

The reason it is done is to improve performance and reduce GC pressure.

Creating garbage can fill your cache with garbage, slowing down all your code, it also takes work to create objects and to clean them up. The less work you do the faster and more consistent your program will be.

Here is a good article of the difference it makes http://www.javaspecialists.eu/archive/Issue191.html

Integer and Double difference

You are comparing Integer (capital I) objects by reference, which is not the "proper" way to compare objects in java.

References to some integers are cached in order to optimize for performance. This is why comparing certain Integer (capital I) objects by reference seems to work in a few cases in Java.

This is NOT a behavior that the Java developer is expected to rely on or make use of, as it is unreliable, may change, and makes code more difficult to understand.

Long and Double comparison (==) behaves differently

Long v1 = 1L;
Long v2 = 1L;
Double d1 = 1.0;
Double d2 = 1.0;

You are creating two references to objects here, and instantiating two objects with autoboxing behaviour of Java.

Java re-uses the same Long object instance from a pool for v1 and v2, The Doubles do not use a pool for remembering values, as can be read in this informative blog entry https://gerardnico.com/code/type/autoboxing

Here are some rules as with Java 5 :

autoboxing to Boolean and Byte always returns an object from the pool

autoboxing to Char, Short, Integer and Long returns an object from the
pool when the autoboxed value is between -128 and 127 (inclusive)

autoboxing of Float and Double does not use the pool and always
returns a new object

Your code becomes then with autoboxing(some pool is a visualisation of the pool java uses to cache certain values):

class SomePoolJavaUses {
static Long _l1 = new Long(1L);
static Long _l2 = new Long(2L);
static Long _l3 = new Long(3L);
...
}

Long v1 = SomePoolJavaUses._l1;
Long v2 = SomePoolJavaUses._l1;
Double d1 = new Double(1.0);
Double d2 = new Double(1.0);

This means that d1 and d2 are not equal instances, so they are not equal in ==

This means that v1 and v2 are equal instance, so they are equal in ==

the v1.equals returns true, because there is being looked at the actual value there instead of a quick check if the memory addresses are the same.

Java use same reference for some objects but sometimes it creates 2 instances

Integer uses Integer cache to store the values from -128 to +127. If == operator is used to check for any values between -128 to 127 then it returns true. for other than these values it returns false
If you have tried like this,

   Integer i1 = 1000;
Integer i2 = 1000;
Integer i3 = new Integer(10);
Integer i4 = new Integer(10);
System.out.println(i1 == i2);
System.out.println(i3 == i4);

Output:

  false
false

Why is 128==128 false but 127==127 is true when comparing Integer wrappers in Java?

When you compile a number literal in Java and assign it to a Integer (capital I) the compiler emits:

Integer b2 =Integer.valueOf(127)

This line of code is also generated when you use autoboxing.

valueOf is implemented such that certain numbers are "pooled", and it returns the same instance for values smaller than 128.

From the java 1.6 source code, line 621:

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

The value of high can be configured to another value, with the system property.

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

If you run your program with that system property, it will output true!

The obvious conclusion: never rely on two references being identical, always compare them with .equals() method.

So b2.equals(b3) will print true for all logically equal values of b2,b3.

Note that Integer cache is not there for performance reasons, but rather to conform to the JLS, section 5.1.7; object identity must be given for values -128 to 127 inclusive.

Integer#valueOf(int) also documents this behavior:

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.



Related Topics



Leave a reply



Submit