The Integer Cache and == Comparison Bug
Fast recall
Quick revision
Core answer
Integer comparison bug occurs when code expects == to compare wrapped numbers. Boxing can reuse cached objects, so small test values may have the same identity while other equal values do not. For example, two boxed 100 values are required to share an object, but two boxed 200 values need not. Use Objects.equals(a, b) for null-safe value equality or unbox only when null is not possible.Whether you know this specific JVM behaviour and can explain why == on Integer gives inconsistent results depending on the value.
Using == to compare Integer objects expecting it to work like == on int. == on objects always compares addresses, not values.
The cache size (-128 to 127) can be extended via JVM flag -XX:AutoBoxCacheMax=N. Also: the same caching exists for Byte (all 256 values), Short (-128 to 127), Long (-128 to 127), Boolean (true/false), and Character (0 to 127).
Interview-ready guide
Interview answer
The bug comes from mixing primitive comparison with wrapper identity. int values are compared numerically by ==, but Integer operands are references, so == normally asks whether they denote the same wrapper object. Boxing makes the mistake hard to notice because Integer.valueOf() reuses objects for at least -128 through 127.
For example, a test with Integer expected = 100; Integer actual = 100; makes expected == actual true. The same code with 200 is not guaranteed to reuse one object, so it can become false even though both wrappers contain 200. The problem is the identity comparison, not the number 200. Automatic unboxing can also hide a different risk: comparing an Integer to an int unboxes the wrapper and throws NullPointerException if it is null.
I use Objects.equals(expected, actual) when null is a valid possibility. If the API guarantees non-null wrappers, I can compare their unboxed intValue() results. Either choice states the null policy and compares the numeric value rather than relying on the cache.
The Integer Cache and == Comparison Bug
Direct Answer
An Integer comparison bug occurs when code expects == to compare wrapped numbers. Boxing can reuse cached objects, so small test values may have the same identity while other equal values do not. For example, two boxed 100 values are required to share an object, but two boxed 200 values need not. Use Objects.equals(a, b) for null-safe value equality or unbox only when null is not possible.
Code Example
public class IntegerCacheDemo {
public static void main(String[] args) {
// Values in cache range (-128 to 127)
Integer a = 127; // Integer.valueOf(127) — returns cached object
Integer b = 127; // Integer.valueOf(127) — returns SAME cached object
System.out.println(a == b); // true — same object
System.out.println(a.equals(b)); // true — same value
// Values outside cache range
Integer c = 128; // Integer.valueOf(128) — creates new object
Integer d = 128; // Integer.valueOf(128) — creates DIFFERENT new object
System.out.println(c == d); // false — different objects!
System.out.println(c.equals(d)); // true — same value
// The boundary in action — 127 works, 128 doesn't
Integer x = 127;
Integer y = 127;
Integer p = 128;
Integer q = 128;
System.out.println(x == y); // true
System.out.println(p == q); // false — same code, different result!
// Rule: always use .equals() for Integer comparison
System.out.println(p.equals(q)); // true — correct
}
}
Common Mistakes & Pitfalls
- Using
==to compareIntegervalues — it compares references, so it passes for127and fails for128; the bug is invisible until your data crosses the cache boundary. - Assuming the cache covers all small numbers — it stops at
127;128and above always allocate fresh objects, so==flips tofalsethere. - Trusting
==because the tests passed — tests with small values fall inside-128to127and pass by accident, hiding the bug until production data goes higher. - Raising
-XX:AutoBoxCacheMaxto make==work — it only moves the boundary, it doesn't fix identity-vs-value comparison; use.equals()instead.
Check your understanding
Answer these without looking back at the article.
- Why does Java have the Integer cache at all?
- What JVM flag controls the Integer cache size?
- Does the same caching apply to Long and Short in Java?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.