views:

972

answers:

2

I know that if you compare a boxed primitive Integer with a constant such as:

Integer a = 4;
if (a < 5)

a will automatically be unboxed and the comparison will work.

However, What happens when you are comparing two boxed Integers and want to compare either equality or less than/greater than?

Integer a = 4;
Integer b = 5;

if (a == b)

Will result in checking to see if they are the same object, or will it auto-unbox in that case?

What about:

Integer a = 4;
Integer b = 5;

if (a < 5)
+4  A: 

== will still test object equality. It is easy to be fooled, however:

Integer a = 10;
Integer b = 10;

System.out.println(a == b); //prints true

Integer c = new Integer(10);
Integer d = new Integer(10);

System.out.println(c == d); //prints false

Your examples with inequalities will work since they are not defined on Objects. However, with the == comparison, object equality will still be checked. In this case, when you initialize the objects from a boxed primitive, the same object is used (for both a and b). This is an okay optimization since the primitive box classes are immutable.

Adam Lewis
I figured it was object equality being tested. I had some weird results. Should I replace it with .equals()? Also, do you feel I should leave the inequalities as they are or do it another way as well?
Samatha84
There are some non-obvious edge cases with autoboxing. I have my IDE (Eclipse) set to color anything being un-boxed in red, this has saved me from bugs on a few occasions. If you are comparing two Integers, use .equals, if you want to make your inequalities clear, write the cast in explicitly: if ((int)c < (int)d) ... ;You can also do: c.compareTo(d) < 0 // === c < d
Adam Lewis
And if you change the number literals to `200`, both tests will print `false`.
Daniel Earwicker
... on most JVM implementations, that is. According to the language spec the result could vary between implementations.
Daniel Earwicker
I think it's clearer to call this "reference equality" - that way it's obvious what you mean. I'd normally understand "object equality" to mean "the result of `equals` being called".
Jon Skeet
+3  A: 

No, == between Integer, Long etc will check for reference equality - i.e.

Integer x = ...;
Integer y = ...;

System.out.println(x == y);

this will check whether x and y refer to the same object rather than equal objects.

So

Integer x = new Integer(10);
Integer y = new Integer(10);

System.out.println(x == y);

is guaranteed to print false. Interning of "small" autoboxed values can lead to tricky results:

Integer x = 10;
Integer y = 10;

System.out.println(x == y);

This will print true, due to the rules of boxing (JLS section 5.1.7). It's still reference equality being used, but the references genuinely are equal.

Personally I'd use:

if (x.intValue() == y.intValue())

or

if (x.equals(y))

The latter is slightly less efficient - there isn't an overload for Integer.equals(Integer) so it will have to do execution time type checking, whereas the first uses the fact that we already know that both objects are Integers.

Fortunately, compareTo knows about the types, so:

if (x.compareTo(y) < 0)

should still be efficient. Of course, this is micro-optimisation territory and you should use the code you find clearest - after making sure it's correct :)

As you say, for any comparison between a wrapper type (Integer, Long etc) and a numeric type (int, long etc) the wrapper type value is unboxed and the test is applied to the primitive values involved.

This occurs as part of binary numeric promotion (JLS section 5.6.2). Look at each individual operator's documentation to see whether it's applied. For example, from the docs for == and != (JLS 15.21.1):

If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).

and for <, <=, > and >= (JLS 15.20.1)

The type of each of the operands of a numerical comparison operator must be a type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs. Binary numeric promotion is performed on the operands (§5.6.2). If the promoted type of the operands is int or long, then signed integer comparison is performed; if this promoted type is float or double, then floating-point comparison is performed.

Note how none of this is considered as part of the situation where neither type is a numeric type.

Jon Skeet