【问题标题】:Code Object o = true ? new Integer(0) : new Long(1) returns Long with value 0. Why? [duplicate]代码对象 o = true ? new Integer(0) : new Long(1) 返回值为 0 的 Long。为什么? [复制]
【发布时间】:2017-04-12 05:15:58
【问题描述】:

请考虑我们有以下代码:

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

【问题讨论】:

标签: java


【解决方案1】:

实际上 long 可以存储整数的值,但整数不能存储 long 的值(概念正在扩大),并且您将其存储在 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);

自行检查,如果您对此有任何疑问,请告诉我。

【讨论】:

    【解决方案2】:

    这里发生的事情是

    • 二进制数值提升将您的 IntegerLong 类型转换为 long 以用作应用于条件运算符表达式的通用类型
    • 拆箱这些包装对象
    • 然后将条件表达式的结果值装箱

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

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

    由于表达式的结果类型是longIntegerLong 必须被取消装箱(然后在Integer 的情况下进行强制转换)。

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

    如此有效,如果我们忽略编译器将优化以下一半的事实,因为它正在处理一个常量表达式,这要归功于代码中的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 代表最后的拳击。

    【讨论】:

      【解决方案3】:

      JLS - 15.25. Conditional Operator ? : 中很好地解释了这种行为:

      条件运算符具有三个操作数表达式。 ? 出现在 firstsecond 表达式之间,: 出现在 secondthird 表达式之间.

      [...]

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

      • [...]

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

        • [...]

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

      【讨论】:

        【解决方案4】:

        这与三元运算符的工作方式有关。

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

        true ? 1 : "Hello"
        

        由于intString 不能相互隐式转换。

        但是,在您的情况下,类型 兼容! int 可以隐式转换为 long。这就是编译器所做的!它看到了一个 int 和一个 long 并决定表达式应该评估为 long。它将这两个值拆箱,并将int 隐式转换为long。最后,它将生成的long 装箱,使其变为Long 并将其放入变量中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-09-15
          • 1970-01-01
          • 2020-08-20
          • 1970-01-01
          • 2015-06-21
          • 1970-01-01
          • 2013-04-10
          • 2021-11-29
          相关资源
          最近更新 更多