6

下面的(Java)代码合法吗?

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

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

4

3 回答 3

3

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

第 15.21.3 章:引用相等运算符 == 和 !=

如果相等运算符的操作数既是引用类型又是 null 类型,则该操作是对象相等。

如果无法通过强制转换(第 5.5 节)将任一操作数的类型转换为另一个操作数的类型,则会出现编译时错误。两个操作数的运行时值必然不相等。

但是我注意到第 5.5 章有一些变化:铸造转换。将布尔值转换为 Object 似乎被归类为 Java 7 上的装箱约定:

原始类型的表达式可以通过装箱转换无错误地转换为引用类型。

在此处输入图像描述

⊡ 表示拳击转换

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

于 2013-09-11T02:13:44.273 回答
1

事实证明,将原语与编译时类型“Object”的表达式进行比较是不合法的。JLS 15.21明确禁止:

相等运算符可用于比较两个可转换(第 5.1.8 节)为数值类型的操作数,或布尔或布尔类型的两个操作数,或引用类型或空类型的两个操作数。所有其他情况都会导致编译时错误。

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

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

于 2013-09-12T03:39:54.507 回答
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装箱的。

于 2013-09-11T02:12:42.937 回答