When is it legal to compare Objects and primitives with '==' operator?
Asked Answered
C

3

6

Is the below (Java) code legal?

class Test {
  Object foo() {return "";}
  boolean bar() {return foo() == true;}
}

It won't compile against JDK 6 but seems fine on 7+. Did the spec change? Was a bug fixed? I've been discussing at http://bugs.eclipse.org/bugs/show_bug.cgi?id=416950 and could go either way on this one.

Circumjacent answered 11/9, 2013 at 1:56 Comment(1)
check this previous post , difference in autoboxing java6 and java7Windgall
C
1

As it turns out, it is not legal to compare a primitive with an expression of compile-time type 'Object'. JLS 15.21 expressly forbids it:

The equality operators may be used to compare two operands that are convertible (§5.1.8) to numeric type, or two operands of type boolean or Boolean, or two operands that are each of either reference type or the null type. All other cases result in a compile-time error.

The Eclipse compiler flags the error regardless of Java version. For Java 7, both Oracle JDK and OpenJDK erroneously allow the code to compile. This bug in Oracle and Open JDKs is corrected in version 8.

In summary, this wonky comparison is illegal according to the spec and will only compile on some subset of compilers for a particular subset of language version targets. Won't ever work on Java 4- or 8+. The casting conversions referred to in other answers apply only to the '=' operator, not to '=='. 15.21.3 applies only to two reference operands.

Circumjacent answered 11/9, 2013 at 1:56 Comment(0)
A
3

JLS about reference equality doesn't change between java 6 & 7:

Chapter 15.21.3: Reference Equality Operators == and != :

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.

However I noticed some change on Chapter 5.5: Casting Conversion. Casting boolean to Object appears to be classified as boxing convention on Java 7:

An expression of a primitive type may undergo casting conversion to a reference type without error, by boxing conversion.

enter image description here

⊡ signifies boxing conversion

Hence since the primitive true can be casted to Object, your equality expression can be classified as reference equality on Java 7, and doesn't yield compiler error

Agger answered 11/9, 2013 at 2:13 Comment(0)
C
1

As it turns out, it is not legal to compare a primitive with an expression of compile-time type 'Object'. JLS 15.21 expressly forbids it:

The equality operators may be used to compare two operands that are convertible (§5.1.8) to numeric type, or two operands of type boolean or Boolean, or two operands that are each of either reference type or the null type. All other cases result in a compile-time error.

The Eclipse compiler flags the error regardless of Java version. For Java 7, both Oracle JDK and OpenJDK erroneously allow the code to compile. This bug in Oracle and Open JDKs is corrected in version 8.

In summary, this wonky comparison is illegal according to the spec and will only compile on some subset of compilers for a particular subset of language version targets. Won't ever work on Java 4- or 8+. The casting conversions referred to in other answers apply only to the '=' operator, not to '=='. 15.21.3 applies only to two reference operands.

Circumjacent answered 11/9, 2013 at 1:56 Comment(0)
G
0

Here's the byte code for reference

class Test {
  Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":
       4: return

  java.lang.Object foo();
    Code:
       0: ldc           #2                  // String
       2: areturn

  boolean bar();
    Code:
       0: aload_0
       1: invokevirtual #3                  // Method foo:()Ljava/lang/Object;
       4: iconst_1
       5: invokestatic  #4                  // Method java/lang/Boolean.valueOf:
       8: if_acmpne     15
      11: iconst_1
      12: goto          16
      15: iconst_0
      16: ireturn
}

Compiled with

java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)

It seems to be converting the returned String into a Boolean that gets unboxed.

Gervais answered 11/9, 2013 at 1:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.