Search code examples
javawrapperautoboxingtype-promotion

What is the logic behind type conversion when comparing wrapper classes and primitives with == operator?


I read that compiler refuses to use auto boxing/unboxing when there is more than one operation needed in order to perform implicit conversion (int -> double -> Double or Integer -> int -> double). It's stil rather confusing

Integer i = 2;
Double d = 2.0;
System.out.println(i == d); // COMPILE TIME ERROR

// fix

System.out.println( (double) i == d); // OK: true

My understanding is that the compiler tries to unwrap i with Integer.intValue(). Since it takes more than one step to convert Integer to double (Integer -> int -> double) compiler refuses to do it implicitly, so we need to "help him" by using explicit type conversion, which will reduce the number of steps. Is it correct?

Integer i = 2;
double d = 2.0;
System.out.println(i == d); // OK: true

In this example it clearly takes more than one step for the compiler to perform conversion (Integer -> int -> double). How come it doesn't complain?

I'm aware that one must use equals() method over ==


Solution

  • The answer can be found in the Java Language Specification, in section 15.21. Equality Operators:

    The operators == (equal to) and != (not equal to) are called the equality operators.

    Section 15.21.1. Numerical Equality Operators == and != says:

    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).

    Section 15.21.3. Reference Equality Operators == and != says:

    If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.

    It is a compile-time error if it is impossible to convert the type of either operand to the type of the other by a casting conversion (§5.5). The run-time values of the two operands would necessarily be unequal (ignoring the case where both values are null).

    Without a cast, the i == d expression must follow the rules in section 15.21.3, because both i and d are reference types, not numeric types. Only the primitive types are numeric types (except boolean of course).

    Since an Integer cannot be cast to a Double, and a Double cannot be cast to an Integer, the compiler knows that it is impossible for the expression to be true (ignoring the case where both values are null), so a compile-type error occurs.

    When you do (double) i == d, then the left-hand side becomes a numeric type, and the rules specified in section 15.21.1 applies.