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 int
s 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
How to Reference a Method in Javadoc
How to Pass Console Arguments to Application in Eclipse
Write a File in Utf-8 Using Filewriter (Java)
Use a .Jar Java Library API in C#
Behaviour of Return Statement in Catch and Finally
When Do You Need to Explicitly Call a Superclass Constructor
Convert .Jar to an Osx Executable
How to Set a Long Java Classpath in Windows
Collections.Synchronizedlist and Synchronized
Can a Class Have No Constructor
A Simple Http Server with Java/Socket
Add Multiple Items to an Already Initialized Arraylist in Java
What Is the Idiomatic Way to Compose a Url or Uri in Java
Spring Cache with Collection of Items/Entities
Is Doing a Lot in Constructors Bad
Does Java Have Any Mechanism for a Vm to Trace Method Calls on Itself, Without Using Javaagent, etc
How to Read Text from Hidden Element with Selenium Webdriver