何时将对象和基元与'=='运算符进行比较是合法的?

时间:2013-09-11 01:56:06

标签: java operators autoboxing jls

以下(Java)代码是否合法?

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

它不会针对JDK 6编译,但在7+上似乎没问题。规格有变化吗?修复了一个错误吗?我一直在http://bugs.eclipse.org/bugs/show_bug.cgi?id=416950进行讨论,可以选择任何一种方式。

3 个答案:

答案 0 :(得分:3)

关于引用相等的JLS在java 6和&之间没有变化。 7:

Chapter 15.21.3: Reference Equality Operators == and !=

  

如果相等运算符的操作数都是引用   type或null类型,则操作是对象相等。

     

如果无法转换类型,则为编译时错误   通过转换转换将操作数转换为另一个的类型   (§5.5)。两个操作数的运行时值必然是   不相等的。

但是我发现Chapter 5.5: Casting Conversion有些变化。将布尔值转换为Object似乎在Java 7上被归类为装箱约定:

  

基本类型的表达式可以进行转换为a   引用类型没有错误,通过装箱转换。

enter image description here

⊡表示拳击转换

因此,由于原始true可以转换为Object,因此您的等式表达式可以在Java 7上被归类为引用相等,并且不会产生编译器错误

答案 1 :(得分:1)

事实证明,将基元与编译时类型“对象”的表达式进行比较是合法的。 JLS 15.21明确禁止它:

  

可以使用相等运算符来比较两个操作数   convertible(§5.1.8)到数字类型,或两个boolean类型的操作数   或布尔值,或两个操作数,每个操作数都是引用类型或   null类型。所有其他情况都会导致编译时错误。

无论Java版本如何,Eclipse编译器都会标记错误。对于Java 7,Oracle JDK和OpenJDK都错误地允许代码进行编译。 Oracle和Open JDK中的bug在版本8中得到了更正。

总之,根据规范,这种不稳定的比较是非法的,并且只会针对特定语言版本目标子集编译某些编译器子集。不会在Java 4或8+上工作。其他答案中提到的转换转换仅适用于'='运算符,而不适用于'=='。 15.21.3仅适用于两个参考操作数。

答案 2 :(得分:0)

这是参考的字节代码

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
}

编译

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)

似乎是将返回的String转换为未装箱的Boolean