为什么在Java 7中int与Object的比较是有效的,而在Java 8中不再有效?

61

以下代码,

private boolean compare(Object a, int b) {
    return a == b;
}

代码可以在Java 7中编译,但在Java 8中会出现以下错误:

不可比较的类型:int 和 Object

看一下这个问题:

在Java 7中比较Object和int

似乎Java 6和Java 8都不允许您比较intObject,而Java 7则可以。是否有任何文档介绍这一点?

我对决策背后的背景知识很感兴趣。似乎他们还没有做出最终决定。

我正在使用带有JDK 1.7.0.51的IntelliJ IDEA 14.1.4。


2
这个错误是在Eclipse中显示的(即使用ECJ时)还是由JDK编译器显示的?我猜这是ECJ中的一个错误... - Axel
2
如果是这样的话,我会认为Java 7犯了一个错误。 - dragon66
使用Oracle的Java 7,我得到了"Incompatible operand types: Object and int"的错误。您提供的代码是否是在Java 7中编译的准确代码? - Andy Thomas
@AndyThomas 我猜这取决于特定版本的1.7 JDK。llogiq无法使用jdk 1.7.0_75编译,而wero可以使用jdk 1.7.0_71编译它。也许在这些版本之间进行了错误修复? - SomeJavaGuy
编译失败,jdk 1.7.0_67 版本。 - algiogia
4个回答

30

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似乎将此视为引用比较,但仅当BOTH操作数为引用类型时才允许引用比较。
...
JLS第15.21节中的类型规则现在将由javac正确执行。自JDK5以来,javac接受了一些对象-基元比较的程序,这些程序根据JLS 15.21的规定类型不正确。这些比较现在将被正确地标识为类型错误。


22

JLS - Chapter 15. Equality Operators提到了三种不同的==运算符:数字布尔引用。由于没有任何==运算符可以在您的示例中发生,因此我们得出结论,该语句是非法的

让我们看看为什么在您的示例中无法应用 ==

现在假设它是合法的,并且编译器将该行更改为:

if (a == new Integer(b))

你希望的结果是什么?这个条件永远不会评估为true,所以修复了Java 8中的一个bug是有道理的。


19
自动装箱是使用Integer.valueOf实现的。由于Integer.valueOf有时会从池中返回值,因此结果可能为true - fabian
3
所以,从未真正以一个合理有用或直观的方式存在。 - Yakk - Adam Nevraumont
2
@MarounMaroun 嗯,对于答案中的代码,它肯定永远不会是真的。new Integer(b)总是创建一个对象,而Integer.valueOf(b)可能不会。 - user253751
正如其他评论者所说,这个答案是错误的。使用自动装箱,比较整数和对象是可以定义良好的。 - Navin

7

我无法使用javac 1.7.0_75或javac 1.8.0_60编译示例(修复bool→boolean),我没有JDK6,但我认为它在那里也不应该工作。也许它是早期ecj的不兼容性,如Axel所暗示的,或者是不同次要版本的javac中的错误。

无论如何,如果它能工作,那是由于自动装箱。这可能已经在为Java 8做准备时被削减了,因为流和自动装箱不太搭配。


5
根据JLS 7,它不应该编译通过。int类型可以与装箱数值类型(即Byte、Short、Character、Integer、Long、Float、Double)进行比较,但仅限于此。如果比较的是int和Float,Float将首先被拆箱,以便比较float和int。反过来做就没有意义了——将int装箱然后检查Integer的标识(还带有Float)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接