Integer Cache in Java
Here's a famous Java puzzle: two Integer variables holding 127 are ==, but two holding 128 are not. Nothing is wrong with the numbers. == on objects compares references, and Java keeps a ready-made cache of Integer objects for small values. Inside the cache range, boxing the same value always returns the same object; outside it, every boxing creates a new one.
The Puzzle
public class Cache {
public static void main(String[] args) {
Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b);
System.out.println(c == d);
System.out.println(c.equals(d));
System.out.println(c.intValue() == d.intValue());
Long x = 127L, y = 127L;
Double p = 1.0, q = 1.0;
System.out.println(x == y);
System.out.println(p == q);
}
}true
false
true
true
true
falseHow it works
Integer a = 127compiles toInteger.valueOf(127). For values from -128 to 127,valueOfreturns an object from a cache built whenIntegerloads, soaandbrefer to the same object:true.- 128 is outside the cache, so each
valueOf(128)creates a new object:c == disfalse. equalscompares values:true. Comparing unboxedints also works.Longhas the same -128 to 127 cache.Doublehas no cache, so even1.0 == 1.0onDoubleobjects isfalse.
Inside the Cache
Integer.valueOf looks like this (simplified from the JDK source):
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high) {
return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i);
}The cache is safe to share because Integer objects are immutable. It saves memory and time for the small numbers programs use most.
| Wrapper | Cached values |
|---|---|
Integer | -128 to 127 (the upper limit can be raised) |
Long, Short, Byte | -128 to 127 |
Character | 0 to 127 |
Boolean | Both values: TRUE and FALSE |
Float, Double | None |
The upper limit for Integer can be raised with a JVM option, for example java -XX:AutoBoxCacheMax=1000 Cache; then c == d above prints true. That's a curiosity, not a fix: code must never depend on it.
Why This Matters in Real Code
The bug usually hides in tests: ids, quantities and counts in test data are small, so == passes; in production, with values like 4500, it fails.
Integer expected = order.getQuantity();
Integer actual = shipment.getQuantity();
if (expected == actual) { // true for 50, false for 500
markComplete();
}Common Mistakes
Using == on Integer, Long or other wrappers. Use equals or Objects.equals.
Trusting tests that use small numbers. The cache hides the bug until values exceed 127.
Writing new Integer(5). The constructor is deprecated for removal; use Integer.valueOf(5) or autoboxing.
Interview Corner
Why does Integer a = 127, b = 127; a == b return true, but 128 returns false?
Autoboxing calls Integer.valueOf, which returns cached objects for values from -128 to 127. Two boxings of 127 return the same cached object, so ==, which compares references, is true. 128 is outside the cache, so each boxing creates a new object and == is false. Values should be compared with equals.
Which wrapper classes have caches?
Integer, Long, Short and Byte cache -128 to 127; Character caches 0 to 127; Boolean has its two constants. Float and Double have no cache. Only Integer's upper limit is configurable, with -XX:AutoBoxCacheMax.
Practice
- Easy: Predict, then check:
Integer.valueOf(100) == Integer.valueOf(100)andInteger.valueOf(1000) == Integer.valueOf(1000). - Harder: Write a loop from 120 to 135 that boxes
itwice and prints where==stops beingtrue.
Key Takeaways
Was this tutorial helpful?