Equality and Autoboxing

| 3 Comments | 1 TrackBack

In Java 1.4 and before, the equality operators == and != allow you to compare two booleans, two numbers, or two references. Any other combination of operands was a compilation error.

In Java 1.5 auto-unboxing enters the picture. It is now possible to compare a boolean with a Boolean, and a number of primitive type with a number expressed as a reference type. That is, it is no longer a compilation error to use the equality operators with a primitive on one side and a reference type on the other. (The public review draft for autoboxing doesn't get this right. I have reported the bug, and the beta-release implementation appears to be correct.)

Now where it really starts to get interesting

is when you think about primitive wrapper objects on both sides of the operator. The equality operators already have a meaning when there are two operands of reference type, so we can't unbox both sides of the operator and compare their contents: we have to compare the object references. This produces some surprising results:
public class Equality {
    public static void main(String[] args) {
        Integer i = new Integer(0), j = new Integer(0);
        // The two objects are both equal to 0
        System.out.println(i == 0 && j == 0); 
        // But they are not equal to each other
        System.out.println(i == j);
        // true: relational ops unbox both sides
        System.out.println(i <= j && i >= j);
} 

Another wrinkle is that we'd get different results if we'd used autoboxing to create the two wrapper objects we wanted to compare. Unlike the code above, this code prints true:

Integer i = 0, j = 0;
System.out.println(i == j);

The reason is that the autoboxing spec requires that small integers (-128 to 127) always box to the same wrapper object. Implementations are encouraged, but not requied, to do the same for larger values as well. So if we used 1023 instead of 0 in the code above it might print "true" or it might print "false".

None of this is intended as a criticism of autoboxing, by the way. Just an exploration of an interesting (and necessary) limitation.

1 TrackBack

Java could really use a nice helping of DWIMmery — Equality and Autoboxing.... Read More

3 Comments

Using jdk1.5 beta 1, I get:

Integer i = 0, j = 0;
System.out.println(i == j);

.. to print false.

Integer.valueOf( int value) does only return a new Integer( value), and Integer( int value) only stores the value.

Perhaps thats good, even though using a flyweight or similar, probably would increase performace.

Personally I think transalting:
Integer i = 0; to
Integer i = Integer.valueOf(0);
is sad, since it removes backwards compability. Iteger.valueOf( int) is added in Java1.5.

> Using jdk1.5 beta 1, I get:
>
> Integer i = 0, j = 0;
> System.out.println(i == j);
>
> .. to print false.

Hmm. Maybe I should have tested it... This is a bug. The autoboxing spec says that integers between -128 and 127 must always box to identical objects.

I believe that this will be fixed in the next beta release.

'Implementations are encouraged, but not requied, to do the same for larger values as well. So if we used 1023 instead of 0 in the code above it might print "true" or it might print "false". '

this feature enhances the saying "write once - test everywhere" :-)

i wonder what this would print in the fixed up beta:

Integer i,j;
int n;
//...

i = j = n;

System.out.println(i == j);

Books

Comprehensive coverage of Ruby 1.8 and 1.9

"The New Most Important Ruby Book"
Peter Cooper,
rubyinside.com

Completely updated for Ajax and Web 2.0

"A must-have reference"
Brendan Eich,
creator of JavaScript

The classic Java quick-reference