This is someting that shocked me about Java, if you keep reading you’ll be shocked too.
The question is simple: how do you compare two Integers? And two Longs?
If you are a decent java developer you’d never do it like this:
Integer a = 1; Integer b = 1; if (a == b) /** Do some shit */
If you are wondering why, please stop reading this and never come back.
Any good java tutorial/book/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. You must always 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.
But wait there’s more, let’s now try something different:
Integer a = 1000; Integer b = 1000; if (a == b) /** Do some shit */
If you run this code you’ll notice that this time the if block is not executed. Weird.
So why this code behaves in a different way just by changing the values of a and b?
Very simple, once you know the secret.
The secret is called interning, it is a perverted mechanism used by the Java Virtual Machine to optimize code execution by keeping some frequently used instances ready to be used by your code. What happens is that Integer and Long instances with values ranging from -128 to 127 (range can be different depending on the specific JVM implementation) are created and stored permanently, or interned, by the Java Virtual Machine.
So when you create an Integer instance by assigning a value between -128 and 127 the JVM does not create a new Integer instance, it simply takes the Integer reference you declared and points it to it’s interned instance.
If you create two or more instances of the Integer class with values inside the interning range and then try to compare them using the == operator it will work, simply because you are comparing two Integer references that are referring to the same interned instance. Now you know the secret.
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 some shit */
This code works as expected, the == operator does not work.
This interning stuff is an extremely dangerous mechanism that can possibly trick you into believing that the Java == operator works on Integers and Longs as well as with primitives int and long. It will work until your values are inside the interning range, once values being compared fall outside of the interning range.. well.. may the Force be with you.