Why 1000 == 1000 returns false but 100 == 100 returns true in java?

This is probably one of the well discussed topic, but I found it interesting.

if you run the following code-


    Integer a = 1000, b = 1000;  
    System.out.println(a == b);//1
    Integer c = 100, d = 100;  
    System.out.println(c == d);//2

You will get –

false
true

Here is the basic:  we know that , if two references point to the same object, they are equal in terms of ==. If two references point to different objects, they are not equal in terms of == even though they have the same contents.

So, here last statement should be false as well.

This actually where it gets interesting, if you look into the Integer.java class , you will find that there is a inner private class, IntegerCache.java that caches all Integer objects between -128 and 127.

So thing is, all small integers are cached internally and when we declare something like –

Integer c = 100;

What it does internally is:

Integer i = Integer.valueOf(100);

Now if we look into the valueOf() method , we will see-

    public static Integer valueOf(int i) {

      if (i >= IntegerCache.low && i
          return IntegerCache.cache[i + (-IntegerCache.low)];

      return new Integer(i);
    }

If the value in the range -128 to 127, it returns the instance from the cache.

So

 Integer c = 100, d = 100;

basically point to the same object.

Thats why we do –

System.out.println(c == d);

We get true.

Now you might ask why does this caching require?

Well, the logical rationale is that “smaller” integers in this range are used much more often than larger ones, so using the same underlying objects is worth it to reduce the potential memory footprint.

However, you can abuse this thing using reflection API.

Run the following code, and enjoy the magic-

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

      Class cache = Integer.class.getDeclaredClasses()[0]; //1
      Field myCache = cache.getDeclaredField("cache"); //2
      myCache.setAccessible(true);//3

      Integer[] newCache = (Integer[]) myCache.get(cache); //4
      newCache[132] = newCache[133]; //5

      int a = 2;
      int b = a + a;
      System.out.printf("%d + %d = %d", a, a, b); //
    }

Advertisements

3 Comments

  1. This kind of headache is ridiculous in Java. The only bright side is that we get paid lots of money to understand it and prevent it. At my current job and the previous job, we’re very careful to use
    a.intValue() == b.intValue() everywhere, and since that extracts the primitives from the Objects, so to speak, it works properly whether Integer a and Integer b are both initialized to 100 or 1000.

    But the average person shouldn’t have to know this kind of nonsense, it’s a design flaw in the language. I know Scala and Kotlin don’t have this headache, I’m not sure about Clojure, Ceylon, and other JVM Java offshoots.

  2. This is interesting only to bystanders, as we Java programmers know to use int instead of the Integer class. If you don’t know the difference between int and Integer, then you’d better stay away from Java, go do JavaScript or some other consistent language, or Scala where this is rock solid.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s