Here is a question for you. What happens when we compile and run the following code:
1: 2: 3: 4: 5: 6: 7: |
public class IntegerBig {
public static void main(String[] args) {
Integer a = 1000;
Integer b = 1000;
System.out.println("a == b : " + (a == b));
}
}
|
Many of you probably know the rule, which says that using “==” between objects compares their references. So if we have two separate objects, we should get “false”. Well, in this case that’s correct! But now, let’s change slightly our code :
1: 2: 3: 4: 5: 6: 7: |
public class IntegerSmall {
public static void main(String[] args) {
Integer a = 1;
Integer b = 1;
System.out.println("a == b : " + (a == b));
}
}
|
The only difference is the value of our two Integers. Should it have any meaning? Compile, run, and the answer is… true! What happened? For some reason, a and b are pointing this time to the same object. Hmm, why?
Java has a few confusing mechanisms. One of them is the way autoboxing works. If we are autoboxing some value to one of the wrapper classes (Boolean, Byte, Short, Char, Integer, Long), the compiler sometimes creates a new object and sometimes uses the pool of values, similarly like with Strings.
When does it do the first and when the latter? Here are some rules as with Java 5 :
- autoboxing to Boolean and Byte always returns an object from the pool
- autoboxing to Char, Short, Integer and Long returns an object from the pool when the autoboxed value is between -128 and 127 (inclusive)
- autoboxing of Float and Double does not use the pool and always returns a new object
It should be noted that those rules are implementation specific and can change between subsequent Java releases.
One can argue if this behavior of autoboxing in Java is good or bad. On one hand it looks strange when comparing two equal integers with “==” sometimes gives false and sometimes true. But then, weren’t we taught from the very first day, that one should never use “==” when comparing values of objects? That is what the Object.equals(Object o) method is for.
Let’s see how funny it can be when we forget about this rule, and try to prove a well known fact – when a equals b, and b equals c, then c equals a:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: |
public class TransitiveEquality {
public static void main(String[] args) {
Integer a=1000;
int b=1000;
Integer c=1000;
System.out.println("a equals b : " + (a == b));
System.out.println("b equals c : " + (b == c));
System.out.println("c equals a : " + (c == a));
}
}
|
If you compile and run this program, it will display :
a equals b : true b equals c : true c equals a : false |
To avoid such inconsistencies, you should always use the Object.equals(Object o) method if you want to compare the values, and leave the usage of “==” only to cases when you want to check if two references are really pointing to the same object.
2 Comments until now
I’ve been reading up on Ruby and it uses “==” to test object values, and uses equals() to test references. In a lot of ways, I wish Java had done the same.
Good Explaination!!
Thank You
Add your Comment!