(This pitfall applies equally to all primitive wrapper types, but we will illustrate it for Integer
and int
.)
When working with Integer
objects, it is tempting to use ==
to compare values, because that is what you would do with int
values. And in some cases this will seem to work:
Integer int1_1 = Integer.valueOf("1");
Integer int1_2 = Integer.valueOf(1);
System.out.println("int1_1 == int1_2: " + (int1_1 == int1_2)); // true
System.out.println("int1_1 equals int1_2: " + int1_1.equals(int1_2)); // true
Here we created two Integer
objects with the value 1
and compare them (In this case we created one from a String
and one from an int
literal. There are other alternatives). Also, we observe that the two comparison methods (==
and equals
) both yield true
.
This behavior changes when we choose different values:
Integer int2_1 = Integer.valueOf("1000");
Integer int2_2 = Integer.valueOf(1000);
System.out.println("int2_1 == int2_2: " + (int2_1 == int2_2)); // false
System.out.println("int2_1 equals int2_2: " + int2_1.equals(int2_2)); // true
In this case, only the equals
comparison yields the correct result.
The reason for this difference in behavior is, that the JVM maintains a cache of Integer
objects for the range -128 to 127. (The upper value can be overridden with the system property "java.lang.Integer.IntegerCache.high" or the JVM argument "-XX:AutoBoxCacheMax=size"). For values in this range, the Integer.valueOf()
will return the cached value rather than creating a new one.
Thus, in the first example the Integer.valueOf(1)
and Integer.valueOf("1")
calls returned the same cached Integer
instance. By contrast, in the second example the Integer.valueOf(1000)
and Integer.valueOf("1000")
both created and returned new Integer
objects.
The ==
operator for reference types tests for reference equality (i.e. the same object). Therefore, in the first example int1_1 == int1_2
is true
because the references are the same. In the second example int2_1 == int2_2
is false because the references are different.