为什么Java 7中有一个int-to-Object比较有效,但在Java 8中却不行?
以下代码,
private boolean compare(Object a, int b) { return a == b; }
在Java 7中编译,但在Java 8中导致以下错误:
无法比拟的类型:int和Object
Java 7将自动装箱应用于int。
private boolean compare(java.lang.Object, int); Code: 0: aload_1 1: iload_2 2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 5: if_acmpne 12 8: iconst_1 9: goto 13 12: iconst_0 13: ireturn
我用这个创建了这个 build 1.7.0_71-b14
这种行为被Oracle认定为错误: JDK-8013357:Javac接受错误的二进制比较操作
相关的JLS部分是15.21。Javac似乎将此视为参考比较,但仅当两个操作数是参考类型时才允许参考比较。 ... JLS Section 15.21中的二进制比较类型规则现在将由javac正确执行。从JDK5开始,javac已经接受了一些程序的Object-primitive比较,这些比较根据JLS 15.21错误地输入。现在这些比较将被正确识别为类型错误。
所述JLS -第15章相等运算提到3个不同的==
操作符:数值,布尔和参考。您的示例中没有一个==
操作员可以发生,因此我们认为该声明是非法的。
让我们来看看为什么==
不能在你的例子中应用:
- 15.21.2。布尔相等运算符==和!= 无需提及为什么它不相关..
- 15.21.3。参考平等操作符==和!= 如果等于运算符的操作数既是引用类型又是空类型,那么操作就是对象相等。 如果不可能通过转换转换(第5.5节)将任一操作数的类型转换为另一操作数的类型,则会出现编译时错误。两个操作数的运行时间值必然不相等。
- 15.21.1。数值相等运算符==和!= 如果等于运算符的操作数都是数字类型,或者一个是数字类型,另一个是可转换的(第5.1.8节)为数字类型,则对操作数执行二进制数字升级(第5.6.2节)。
现在让我们假设它是合法的,编译器将该行更改为:
if (a == new Integer(b))
你期望的结果是什么?该条件永远不会评估true
,所以它是一个在Java 8中修复的bug。