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.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Understanding Java Integer Caching and Autoboxing: Why == Fails and How to Use equals

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
false

Java 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.class

The 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.<init>:()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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaperformanceAutoboxingequalsJavapIntegerCache
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.