Understanding Java Integer Caching and Autoboxing: Why == Fails and How to Use equals
This article explains Java's Integer caching mechanism, why using == on Integer objects can give unexpected results outside the -128 to 127 range, how the Integer.valueOf method and the IntegerCache work, and how to inspect the behavior with javap and JVM options.
According to Alibaba's development manual (OOP rule 7), all comparisons between integer wrapper objects should use equals rather than == because values outside the cached range are distinct objects.
The following code demonstrates the issue:
public class IntegerTest {
public static void main(String[] args) {
Integer a = 100,
b = 100,
c = 200,
d = 200;
System.out.println(a == b);
System.out.println(c == d);
}
}Output:
true
falseJava caches Integer objects in the range -128 to 127 using IntegerCache.cache . Values outside this range are allocated on the heap, so == returns false. The cache size can be increased with the JVM option -XX:AutoBoxCacheMax=<size> , which changes IntegerCache.high .
The source of Integer.valueOf shows the caching logic:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}To see how the compiler translates the code, you can use IDEA to add an external tool that runs javap -c on the compiled class. The command looks like:
/Library/Java/JavaVirtualMachines/jdk1.8.0_101.jdk/Contents/Home/bin/javap -c IntegerTest.classThe resulting bytecode confirms that each assignment to an Integer is compiled to a call to Integer.valueOf (lines 2, 8, 15, 22):
Compiled from "IntegerTest.java"
public class com.github.codedrinker.basic.IntegerTest {
public com.github.codedrinker.basic.IntegerTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object.
:()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 100
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: bipush 100
8: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
11: astore_2
12: sipush 200
15: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
18: astore_3
19: sipush 200
22: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
25: astore 4
...
}Other wrapper types such as Character , Long , and Short have similar caching behavior, which can be verified by decompiling their classes in the same way.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
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.