Why do == comparisons with Integer.valueOf(String) give different results for 127 and 128?
I have no idea why these lines of code return different values:
System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));
The output is:
true
false
true
Why does the first one return true
and the second one return false
? Is there something different that I don't know between 127
and 128
? (Of course I know that 127
< 128
.)
Also, why does the third one return true
?
I have read the answer of this question, but I still didn't get how it can return true
, and why the code in second line returns false
.
There's a striking difference here.
valueOf
is returning an Integer
object, which may have its values cached between -128 and 127. This is why the first value returns true
- it's cached - and the second value returns false
- 128 isn't a cached value, so you're getting two separate Integer
instances.
It is important to note that you are comparing references with Integer#valueOf
, and if you are comparing a value that is larger than what the cache supports, it will not evaluate to true
, even if the parsed values are equivalent (case in point: Integer.valueOf(128) == Integer.valueOf(128)
). You must use equals()
instead.
parseInt
is returning a primitive int
. This is why the third value returns true
- 128 == 128
is evaluated, and is of course, true
.
Now, a fair bit happens to make that third result true
:
An unboxing conversion occurs with respect to the equivalence operator you're using and the datatypes you have - namely,
int
andInteger
. You're getting anInteger
fromvalueOf
on the right hand side, of course.After the conversion, you're comparing two primitive
int
values. Comparison happens just as you would expect it to with respect to primitives, so you wind up comparing128
and128
.
The Integer
class has a static cache, that stores 256 special Integer
objects - one for every value between -128 and 127. With that in mind, consider the difference between these three.
new Integer(123);
This (obviously) makes a brand new Integer
object.
Integer.parseInt("123");
This returns an int
primitive value after parsing the String
.
Integer.valueOf("123");
This is more complex than the others. It starts off by parsing the String
. Then, if the value is between -128 and 127, it returns the corresponding object from the static cache. If the value is outside of this range, then it invokes new Integer()
and passes in the value, so that you get a new object.
Now, consider the three expressions in the question.
Integer.valueOf("127")==Integer.valueOf("127");
This returns true, because the Integer
whose value is 127 is retrieved twice from the static cache, and compared to itself. There's only one Integer
object involved, so this returns true
.
Integer.valueOf("128")==Integer.valueOf("128");
This returns false
, because 128 is not in the static cache. So a new Integer
is created for each side of the equality. Since there are two different Integer
objects, and ==
for objects only returns true
if both sides are the exact same object, this is going to be false
.
Integer.parseInt("128")==Integer.valueOf("128");
This is comparing the primitive int
value 128 on the left, with a newly created Integer
object on the right. But because it doesn't make sense to compare an int
to an Integer
, Java will auto-unbox the Integer
before doing the comparison; so you end up comparing an int
to an int
. Since the primitive 128 is equal to itself, this returns true
.
Take care of returning values from these methods. The valueOf method returns an Integer instance:
public static Integer valueOf(int i)
The parseInt method returns integer value (primitive type):
public static int parseInt(String s) throws NumberFormatException
Explanation for comparison:
In order to save memory, two instances of the wrapper objects , will always be == when their primitive values are the same:
- Boolean
- Byte
- Character from \u0000 to \u007f (7f is 127 in decimal)
- Short and Integer from -128 to 127
When == is used to compare a primitive to a wrapper, the wrapper will be unwrapped and the comparison will be primitive to primitive.
In your situation (according to the above rules):
Integer.valueOf("127")==Integer.valueOf("127")
This expression compares references to the same object because it contains Integer value between -128 and 127 so it returns true
.
Integer.valueOf("128")==Integer.valueOf("128")
This expression compares references to different objects because they contain Integer values not in <-128, 127> so it returns false
.
Integer.parseInt("128")==Integer.valueOf("128")
This expression compares primitive value (left hand side) and reference to the object (right hand side)
so right hand side will be unwrapped and his primitive type will be compared to the left so it returns true
.