26

考虑以下代码段:

    int i = 99999999;
    byte b = 99;
    short s = 9999;
    Integer ii = Integer.valueOf(9); // should be within cache

    System.out.println(new Integer(i) == i); // "true"
    System.out.println(new Integer(b) == b); // "true"
    System.out.println(new Integer(s) == s); // "true"
    System.out.println(new Integer(ii) == ii); // "false"

很明显,为什么最后一行总是会打印"false":我们正在使用==引用标识比较,并且new对象永远不会==已经存在的对象相关。

问题是关于前 3 行:这些比较是否保证在原语int上,Integer自动拆箱?是否存在原语会被自动装箱并执行参考身份比较的情况?(那将是false!)

4

2 回答 2

21

是的。 JLS §5.6.2指定了二进制数字提升的规则。部分:

当运算符将二进制数字提升应用于一对操作数时,每个操作数都必须表示一个可转换为数字类型的值,以下规则按顺序应用,使用扩展转换(第 5.1.2 节)在必要时转换操作数:

如果任何操作数是引用类型,则执行拆箱转换(第 5.1.8 节)。

二进制数值提升适用于多个数值运算符,包括“数值相等运算符 == 和 !=”。

JLS §15.21.1(数值等式运算符 == 和 !=)指定:

如果相等运算符的操作数都是数字类型,或者一个是数字类型而另一个是可转换的(第 5.1.8 节)为数字类型,则对操作数执行二进制数字提升(第 5.6.2 节)。

相比之下,JLS §15.21.3(引用相等运算符 == 和 !=)提供:

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

这符合装箱和拆箱的普遍理解,只有在不匹配时才会这样做。

于 2010-05-14T05:10:35.420 回答
8

我将首先准确解释什么时候 ==是引用相等,以及什么时候是数值相等。引用相等的条件比较简单,所以先解释一下。

JLS 15.21.3 参考等式运算符==!=

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

这解释了以下内容:

System.out.println(new Integer(0) == new Integer(0)); // "false"

两个操作数都是Integer引用类型,这就是为什么==is 引用相等比较,两个new对象永远不会==相互,所以这就是它打印的原因false

==实现数值相等,至少有一个操作数必须是数值类型;这具体如下:

JLS 15.21.1 数值等式运算符==!=

如果相等运算符的操作数都是数字类型,或者一个是数字类型而另一个是可转换为数字类型,则对操作数执行二进制数字提升。如果操作数的提升类型是intor long,则执行整数相等测试;如果提升的类型是float or double`,则执行浮点相等测试。

请注意,二进制数字提升执行值集转换和拆箱转换。

因此,请考虑以下事项:

System.out.println(new Integer(0) == 0); // "true"

这会打印true,因为:

  • 右操作数数字int类型
  • 左操作数可通过拆箱转换为数字类型int
  • 因此==是数值相等运算

概括

  • 如果==和的两个操作数!=都是引用类型,它将始终是引用相等操作
    • 操作数是否可转换为数字类型并不重要
  • 如果至少有一个操作数是数值类型,则它始终是数值相等运算
    • 如有必要,将对一个(最多!)操作数进行自动拆箱

参考

相关问题

于 2010-05-14T06:07:47.270 回答