【问题标题】:Equality comparison of `boolean` and `Object` allowed?允许“布尔”和“对象”的相等比较?
【发布时间】:2013-05-22 03:31:03
【问题描述】:

以下代码

public class TestComparison {
    public static void main(String[] args) throws Exception {
        boolean b = true;
        Object o = new Boolean(true);
        System.out.println("comparison result: "+ 
            (o == b)); // Eclipse complains about this expression
    }
}

使用javac V1.7.0_15 编译没有错误,并在运行时打印“false”。然而,Eclipse Juno 抱怨“不兼容的操作数类型 Object 和 boolean”。

显然 javac 将原始布尔值 b 自动装箱,然后通过对象相等性比较 o 和自动装箱的 b,产生 false,而 Eclipse 拒绝进行自动装箱。

根据 Java 语言规范,哪种行为是正确的?我应该在哪里提交错误?

注意:如果我将o 的类型更改为Boolean,事情会按预期工作:Eclipse 接受代码,并且代码打印“true”。

Runnable version on ideone.com

【问题讨论】:

  • 检查你的 Eclipse 设置,看看是否有什么奇怪的地方:项目属性 -> Java 编译器 -> 错误/警告 -> 潜在的编程问题
  • 取决于您的“预期” - 它应该框 b 并使用引用相等(打印为 false)还是取消框 o 并使用原始布尔相等(打印为 true)?
  • @IanRoberts:后者做不到; o 的静态类型是 Object
  • 在 java 6 中代码无法编译。似乎 java 6 和 7 之间的规范发生了一些变化,允许这种行为,请参阅此问题的答案:stackoverflow.com/questions/16119638/…。相关部分是:通过取消装箱转换,引用类型的表达式可以毫无错误地转换为原始类型。

标签: java eclipse javac autoboxing


【解决方案1】:

这是您的项目语言级别设置。您可能正在使用具有 Java 6 语义的 Java 7 编译器。我这里没有 Eclipse,但我在 IntelliJ 中复制了它,当语言级别为 Java 6 时它会出错,即使我使用的编译器是 7。我猜 Eclipse 也有。 This link 解释它。

【讨论】:

  • 这似乎是问题所在。我可以用javac -source 1.6 重现这个问题,所以看起来问题是由从 1.6 到 1.7 的更改引起的。但是,即使是“编译器合规级别 = 1.7”,Eclipse 也会显示错误。这可能是 Eclipse 编译器中的一个错误。
  • @sleske 我确认所有这些:/
【解决方案2】:

关于您的“注意”,当o 更改为Boolean 时,代码可以编译和工作:

这段代码:

public class Tester{
  public static void main(String args[]){
    Boolean one = new Boolean(true);
    Object two = new Boolean(true);
    boolean three = true;
    System.out.println("SAME 1:2 " + (one == two) + " 1:3 " + (one == three) + " 2:3 " + (two == three));
    System.out.println("EQUAL 1:2 " + (one.equals(two)) + " 1:3 " + (one.equals(three)) + " 2:3 " + (two.equals(three)));
  }
}

产生这个结果:

SAME 1:2 false 1:3 true 2:3 false
EQUAL 1:2 true 1:3 true 2:3 true

要了解这是为什么,我们需要考虑各种表达式的编译时类型:

  • one == two 比较 BooleanObject - 它们都是引用类型,所以测试是引用相等 (Java Language Specification, Java SE 7 edition, §15.21.3)
  • one == three 比较 Booleanboolean - 这被视为原始 boolean 值的比较 (§15.21.2); one 已拆箱并与 three 进行比较。
  • two == threeObjectboolean 进行比较 - 在​​这种情况下,boolean 通过强制转换转换为 Object§5.5,在这种情况下将 boolean 装箱到 Boolean 然后扩大BooleanObject),然后比较两者的引用相等性。

EQUAL 行要简单得多 - 所有三种情况都是对 Boolean.equals(Object other) 的调用,当参数为 three 时使用装箱。

【讨论】:

  • 感谢您的澄清。所以对于two==three,强制转换和装箱/拆箱都是必要的,Java 将首先自动装箱,然后进行强制转换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多