代码对象o = true? new Integer(0):new Long(1)返回值为0的Long。为什么?

时间:2016-11-28 13:04:14

标签: java

请考虑我们的代码如下:

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

4 个答案:

答案 0 :(得分:12)

这里发生的是

的结果
  • 二进制数字促销将您的Longlong类型转换为Integer,以用作应用于条件运算符表达式的公共类型
  • 取消装箱这些包装器对象
  • 然后装箱条件表达式的结果值

条件运算符的第二个和第三个操作数必须最终具有相同的类型,这是表达式的结果类型。当然,LongInteger不是同一类型。

但是,如JLS§15.25中所述,编译器在确定要应用于表达式的可能公共类型时将应用binary numeric promotion。该部分有一个方便的表15.25-D,告诉我们当第二个操作数的类型为Long且第三个操作数的类型为Integer,Long时,编译器将对{{1}进行二进制数字提升}。 Integer,Long上的二进制数字促销产生long。因此条件运算符表达式的结果是long

由于表达式的结果类型为long,因此IntegerLong必须取消装箱(然后在Integer的情况下进行投射)。

最后,您将其分配给强制装箱的Object,并将long包裹在Long中。因此,您最终得到的Long包含与您的输出相匹配的值0

如此有效,如果我们忽略了编译器将优化以下一半的事实,因为它处理一个常量表达式,这要归功于代码中的true(我已经使用过{在下面的{1}},代码最终是这样的:

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代表拳击结束。

答案 1 :(得分:4)

JLS - 15.25. Conditional Operator ? :

中详细说明了这种行为
  

条件运算符有三个操作数表达式。 第一个第二个表达式之间出现?第二个第三个​​之间出现: / em>表达。

     

[...]

     

条件表达式的类型确定如下:

     
      
  • [...]

  •   
  • 否则,如果第二个和第三个操作数具有可转换(§5.1.8)到数字类型的类型,则有几种情况:

         
        
    • [...]

    •   
    • 否则,二进制数字提升(§5.6.2)将应用于操作数类型,条件表达式的类型是第二个和第三个操作数的提升类型。

    •   
  •   

答案 2 :(得分:0)

实际上long可以存储整数的值,但是整数不能存储long的值(Concept正在加宽),而是将它存储在Object中,这就是它将它存储在Long中的原因。在内部,它也使用装箱和拆箱

可能的编译器代码:

Long obj = true ? new Integer(0) : new Long(1);

System.out.println(obj.getClass()+“\ nvalue =”+ obj);

不能正常工作的代码(无法编译):

 Integer obj = true ? new Integer(0) : new Long(1);

System.out.println(obj.getClass()+“\ nvalue =”+ obj);

自己检查并告诉我你是否对此有任何疑问。

答案 3 :(得分:0)

这与三元运算符的工作原理有关。

:两侧的操作数必须是兼容的类型,所以你不能这样:

true ? 1 : "Hello"

由于intString不能相互隐含地转换。

但是,在您的情况下,类型 兼容! int可以隐式转换为long。这就是编译器的作用!它看到了一个int和一个long,并决定表达式应该计算为long。它会将这两个值取消装箱,并将int隐含地转换为long。最后,它会将结果long打包,以便它变为Long并将其放入变量中。