I can’t take credit for that title. Dondi sent it to me in an email. Not sure if he got it from anywhere, though. If he did, I’m sorry to be using it, but it makes perfect sense in the context of this post.

Anyway, Jacob posed this question (explained through a class) in Java:

public class WTFInteger
{
  public static void main(String args[])
  {
    Integer foo = 127;
    Integer bar = 127;

    System.out.println(foo + "," + bar); //127,127
    System.out.println(foo <= bar); //true
    System.out.println(foo >= bar); //true
    System.out.println(foo == bar); //true
    System.out.println(foo.intValue() == bar.intValue()); //true

    System.out.println();

    foo = 128;
    bar = 128;

    System.out.println(foo + "," + bar); //128,128
    System.out.println(foo <= bar); //true
    System.out.println(foo >= bar); //true
    System.out.println(foo == bar); //false
    System.out.println(foo.intValue() == bar.intValue()); //true
  }
}

A little test class and in the comments, the output from each evaluation. So what’s going on here? Auto unboxing seems to be going on for the comparison operations, but then why does the equality test pass in one instance but fail in another?

After some research, turns out that the object representation of primitives have a cache that acts kind like a String.intern(), meaning if you assign an Integer a value between a range (default for Integers [-128,127]), you end up getting the same object back, which is why the first (foo == bar) succeeds (value is 127) and why the second (foo == bar) fails (values are 128).

From the comments of the Integer class:

/** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. During VM initialization the * getAndRemoveCacheProperties method may be used to get and remove any system * properites that configure the cache size. At this time, the size of the * cache may be controlled by the vm option -XX:AutoBoxCacheMax=. */