请考虑我们有以下代码:
Object obj = true ? new Integer(0) : new Long(1);
System.out.println(obj.getClass() + "\nvalue = " + obj);
结果是:
class java.lang.Long
value = 0
代替:
class java.lang.Integer
value = 0
有人能解释一下为什么我们在 Java 中有这样的功能吗?这对我来说很奇怪。
您有任何有用的示例吗?
更新:
这是一段字节码,我们可以看到那里发生了什么
NEW java/lang/Integer
DUP
LDC "0"
INVOKESPECIAL java/lang/Integer.<init> (Ljava/lang/String;)V
INVOKEVIRTUAL java/lang/Integer.intValue ()I
I2L
INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;
ASTORE 1
这里的结果是
- 将您的
Integer
和 Long
类型转换为 long
的二进制数字提升,用作应用于条件运算符表达式的通用类型<
- 拆箱那些包装器对象
- 然后对条件表达式的结果值进行装箱
条件运算符的第二个和第三个操作数最终必须具有相同的类型,即表达式的结果类型。 Integer
和 Long
当然不是同一类型。
但是,如 JLS§15.25 中所述,编译器将应用 binary numeric promotion在确定可能的通用类型以应用于表达式时。该部分有方便的表 15.25-D,它告诉我们当第二个操作数是 Integer
类型并且第三个操作数是 Long
类型时,编译器将执行二进制数字Integer,Long
上的提升。 Integer,Long
上的二进制数字提升产生 long
。所以条件运算符表达式的结果是long
。
由于表达式的结果类型是 long
,Integer
或 Long
必须被拆箱(然后转换,在整数
).
最后,您将它分配给一个 Object
,它强制装箱,并将 long
包装在 Long
中。因此,您最终得到一个包含值 0
的 Long
,这与您的输出匹配。
如此有效,如果我们忽略编译器将优化以下一半的事实,因为它正在处理常量表达式,这要归功于代码中的 true
(我使用了 flag
而不是下面),该代码最终是这样的:
Object obj = Long.valueOf(flag ? (long)(new Integer(0)).intValue() : (new Long(1)).longValue());
System.out.println(obj.getClass() + "\nvalue = " + obj);
(long)(new Integer(0)).intValue()
表示拆箱 Integer
并将其转换为 long
所以它匹配表达式结果类型。
(new Long(1)).longValue()
表示拆箱 Long
,因此它匹配表达式结果类型。<
Long.valueOf
表示最后的装箱。