Boxed primitives in Java and how they really work

This article focuses on a low level detail of the JVM and on why it can be extremely dangerous, especially for beginner Java developers. It can be an interesting piece of information even if you are a bit more experienced. The topic we are going to dive into is objects comparison in Java, why the == operator does not work when comparing objects, and why sometimes it actually works.

Boxed primitives can be weird

How do you compare two boxed primitives such as Integer and Long?


Integer a = 1;
Integer b = 1;

if (a == b) /** Do something */

Any java book or teacher will prevent you from doing the above because of the behaviour of the Java == operator which only compares object instances and not objects values. Since a and b are different instances of the Integer class the code above will not work. We must use the equals() method to compare objects values in Java.

So far so good right? Nope. The code above works like a charm. The if block is executed. That’s weird. It gets worse, let’s change the values:

Integer a = 1000;
Integer b = 1000;

if (a == b) /** Do something */

If we run this code we notice that this time the if block is not executed. Weird. So why does this code behave in a different way just by changing the values of a and b?

The truth about boxed primitives

The secret is called interning. It is a rather obscure optimisation strategy. It is basically a cache. Instead of creating new objects over and over again, the JVM stores, or interns, some frequently used instances, so they are already there when requested. In this example this is happening for Integer and Long instances with values ranging from -128 to 127, however the range can be different depending on the specific JVM implementation.

When we create an Integer instance by assigning a value between -128 and 127 the JVM does not create a new Integer instance, it simply looks it up in its cache and returns that instance. Therefore when creating two or more instances of the Integer class with values inside the interning range the == operator will work, simply because we are comparing two references to the same instance.

Note that the interning mechanism does not apply if we explicitly create two instances of the Integer class using the new operator:

Integer a = new Integer(1);
Integer b = new Integer(1);

if (a == b) /** Do something */

This code works as expected, the == evaluates to false.

Conclusion

The interning mechanism can be an extremely dangerous pitfall that can trick developers, especially beginners, into believing that the Java == operator works on Integer and Long as well as with primitives int and long. And sometimes it will, but not for the reason you think of. So, be safe, just use equals().

Unique opportunity! Help a fellow grow his blog!

Hi there! If you’ve read this far maybe you think this was useful, or fun, or I don’t know what but for some reason You Got Here! Great! Please consider sharing this post with your network, I am trying to get The Code Butchery to grow so I can provide more content like this, will you help me in my journey? Thank you!

Share this

Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.