Comparing Boxed Long Values 127 and 128

Comparing boxed Long values 127 and 128

TL;DR

Java caches boxed Integer instances from -128 to 127. Since you are using == to compare objects references instead of values, only cached objects will match. Either work with long unboxed primitive values or use .equals() to compare your Long objects.

Long (pun intended) version

Why there is problem in comparing Long variable with value greater than 127? If the data type of above variable is primitive (long) then code work for all values.

Java caches Integer objects instances from the range -128 to 127. That said:

  • If you set to N Long variables the value 127 (cached), the same object instance will be pointed by all references. (N variables, 1 instance)
  • If you set to N Long variables the value 128 (not cached), you will have an object instance pointed by every reference. (N variables, N instances)

That's why this:

Long val1 = 127L;
Long val2 = 127L;

System.out.println(val1 == val2);

Long val3 = 128L;
Long val4 = 128L;

System.out.println(val3 == val4);

Outputs this:

true

false

For the 127L value, since both references (val1 and val2) point to the same object instance in memory (cached), it returns true.

On the other hand, for the 128 value, since there is no instance for it cached in memory, a new one is created for any new assignments for boxed values, resulting in two different instances (pointed by val3 and val4) and returning false on the comparison between them.

That happens solely because you are comparing two Long object references, not long primitive values, with the == operator. If it wasn't for this Cache mechanism, these comparisons would always fail, so the real problem here is comparing boxed values with == operator.

Changing these variables to primitive long types will prevent this from happening, but in case you need to keep your code using Long objects, you can safely make these comparisons with the following approaches:

System.out.println(val3.equals(val4));                     // true
System.out.println(val3.longValue() == val4.longValue()); // true
System.out.println((long)val3 == (long)val4); // true

(Proper null checking is necessary, even for castings)

IMO, it's always a good idea to stick with .equals() methods when dealing with Object comparisons.

Reference links:

  • https://today.java.net/pub/a/today/2005/03/24/autoboxing.html
  • https://blogs.oracle.com/darcy/entry/boxing_and_caches_integer_valueof
  • http://java.dzone.com/articles/surprising-results-autoboxing

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.

How is it possible that 127==127 while 128!=128?

Because the Integer type interns the values (by the static class IntegerCache) from -128 to 127.

Why comparing two longs with == returns false and when I cast to int or String it returns true?

When you use == with two references, you are comparing whether the references are the same, not whether the contents of the objects referenced are the same.

This is made more complicated with auto-boxing caches. e.g. Longs between -128 and 127 are cached so you will get the same object every time.

e.g.

Long x = 100, y = 100;
System.out.println(x == y); // true, references are the same.

Long a = 200, b = 200; // values not cached.
System.out.println(a == b); // false, references are not the same.
System.out.println(a.equals(b)); // true, the objects referenced are equal

Comparing the intValue() is dangerous due to the risk of overflow.

Long c = -1, d = Long.MAX_VALUE;
System.out.println(c.equals(d)); // false
System.out.println(c.longValue() == d.longValue()); // false
System.out.println(c.intValue() == d.intValue()); // true, lower 32-bits are the same.

Why Integer class caching values in the range -128 to 127?

Just wondering, why between -128 and 127?

A larger range of integers may be cached, but at least those between -128 and 127 must be cached because it is mandated by the Java Language Specification (emphasis mine):

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.

The rationale for this requirement is explained in the same paragraph:

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. [...]

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.


How can I cache other values outside of this range.?

You can use the -XX:AutoBoxCacheMax JVM option, which is not really documented in the list of available Hotspot JVM Options. However it is mentioned in the comments inside the Integer class around line 590:

The size of the cache may be controlled by the -XX:AutoBoxCacheMax=<size> option.

Note that this is implementation specific and may or may not be available on other JVMs.

Why equal operator works for Integer value until 128 number?

Check out the source code of Integer . You can see the caching of values there.

The caching happens only if you use Integer.valueOf(int), not if you use new Integer(int). The autoboxing used by you uses Integer.valueOf.

According to the JLS, you can always count on the fact that for values between -128 and 127, you get the identical Integer objects after autoboxing, and on some implementations you might get identical objects even for higher values.

Actually in Java 7 (and I think in newer versions of Java 6), the implementation of the IntegerCache class has changed, and the upper bound is no longer hardcoded, but it is configurable via the property "java.lang.Integer.IntegerCache.high", so if you run your program with the VM parameter -Djava.lang.Integer.IntegerCache.high=1000, you get "Same values" for all values.

But the JLS still guarantees it only until 127:

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 characters and shorts, as well as integers and longs in the range of -32K - +32K.

In Java, does == Box or Unbox when comparing an object and a constant value?

What you call "a constant value" is an int literal, so its type is int.

JLS 15.21.1 says:

If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands.

In your v1 == 1000 test, 1000 is of numeric type and v1 is convertible to numeric type, so binary numeric promotion is performed.

JLS 5.6.2 (Binary numeric promotion) says:

If any operand is of a reference type, it is subjected to unboxing conversion

Hence, the Integer operand - v1 - is unboxed to an int and a comparison of two ints is performed. Therefore the result of the comparison is true.

When you compare two reference types - v1 == v2 - no unboxing takes places, only the references are compared, as written in JLS 15.21.3:

If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.

Since 1000 is too large to be cached by the Integer cache, b1 and b2 are not referencing the same instance, and therefore the result of the comparison is false.



Related Topics



Leave a reply



Submit