Why Does Integer.compare Using ‘==’ Behave Unexpectedly in Java?
This article explains the JVM storage mechanisms for primitive and wrapper types, the Integer cache range, autoboxing/unboxing behavior, and why certain Integer comparisons using ‘==’ return true or false, providing code examples and detailed analysis.
During Java interviews, questions about comparing Integer objects with == appear frequently. Understanding the underlying JVM mechanisms—how primitives and reference types are stored, the Integer cache, and autoboxing/unboxing—allows you to answer these questions without memorization.
Interview Question
The following test prints which statements as true?
@Test
public void test2() {
Integer i1 = 64;
int i2 = 64;
Integer i3 = Integer.valueOf(64);
Integer i4 = new Integer(64);
Integer i5 = 256;
Integer i6 = Integer.valueOf(256);
System.out.println("A:" + (i1 == i2));
System.out.println("B:" + (i1 == i3));
System.out.println("C:" + (i3 == i4));
System.out.println("D:" + (i2 == i4));
System.out.println("E:" + (i3.equals(i4)));
System.out.println("F:" + (i5 == i6));
}Output:
A:true
B:true
C:false
D:true
E:true
F:falseOnly statements C and F are false, which seems contradictory because i1 == i2, i1 == i3, and i2 == i4 are all true, suggesting transitivity should make i3 == i4 true.
JVM Variable Storage
Variables are stored either on the stack (local variables) or on the heap (global/member variables). Primitive values are stored together with their variables, while reference variables store an address that points to an object on the heap.
Local Variables (Stack)
Created in a stack frame when a method is invoked.
Primitive variables and their values reside in the stack.
Reference variables hold an address; the actual object lives on the heap.
Global/Member Variables (Heap)
Stored in the heap and persist beyond method execution.
Both primitive and reference values are kept in heap memory.
Primitive vs. Wrapper Comparison
When == compares a primitive with a wrapper, the wrapper is automatically unboxed to a primitive, so the comparison is value‑based and yields true for equal numbers.
Integer Caching
The Integer class caches objects for values in the range -128 to 127. The cache is implemented in IntegerCache and is used by valueOf and by autoboxing.
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
int h = 127;
// high may be configured via system property
high = h;
cache = new Integer[(high - low) + 1];
for (int k = 0; k < cache.length; k++)
cache[k] = new Integer(low + k);
}
}Therefore:
Values within the cache range are reused; == works because both references point to the same cached object.
Values outside the range create new objects each time; == compares distinct references, so it returns false. Use equals() for value comparison.
Analysis of the Interview Code
A and D : int vs. Integer triggers unboxing, so the comparison is between two primitives (64), yielding true.
B : Both i1 and i3 are obtained via autoboxing/valueOf within the cache range, so they reference the same cached object; == is true.
C : i4 is created with new Integer(64), which always allocates a new object, while i3 comes from the cache; the references differ, so == is false.
F : Both i5 and i6 hold 256, which is outside the cache range; i5 is autoboxed (new object) and i6 is created via valueOf (new object), so the references differ, making == false.
E : equals() compares the underlying int values, so it returns true even for different objects.
Key Takeaways
If either side of == is a primitive, autounboxing occurs and the comparison is value‑based.
If both sides are Integer objects, the result depends on the cache and on how the objects were created; prefer equals() for reliable value comparison.
The cache range is configurable via the system property java.lang.Integer.IntegerCache.high, but by default it is -128 to 127.
Understanding these JVM details lets you answer a wide range of interview questions about Integer comparison without memorizing each case.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Senior Brother's Insights
A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
