Java 代码对象o=true?新整数(0):新的Long(1)返回值为0的Long。为什么? 请考虑下面的代码: Object obj = true ? new Integer(0) : new Long(1); System.out.println(obj.getClass() + "\nvalue = " + obj);

Java 代码对象o=true?新整数(0):新的Long(1)返回值为0的Long。为什么? 请考虑下面的代码: Object obj = true ? new Integer(0) : new Long(1); System.out.println(obj.getClass() + "\nvalue = " + obj);,java,Java,其结果是: 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/Str

其结果是:

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
newjava/lang/Integer
重复
最不发达国家“0”
调用特殊的java/lang/Integer。(Ljava/lang/String;)V
INVOKEVIRTUAL java/lang/Integer.intValue()I
I2L
INVOKESTATIC java/lang/Long.valueOf(J)Ljava/lang/Long;
阿斯托尔1号

实际上,long可以存储整数的值,但integer不能存储long的值(概念正在扩展),您将其存储在Object中,这就是为什么它将其存储在long中。在内部,它也使用装箱和拆箱

可能的编译器代码:

Long obj = true ? new Integer(0) : new Long(1);
System.out.println(obj.getClass()+“\n值=”+obj)

不工作代码(无法编译):

System.out.println(obj.getClass()+“\n值=”+obj)


你自己检查一下,如果有任何疑问,请告诉我。

这里发生的事情是由于

  • 二进制数字提升将
    整数
    Long
    类型转换为
    Long
    ,用作应用于条件运算符表达式的常用类型
  • 取消包装那些包装器对象
  • 然后装箱条件表达式的结果值
条件运算符的第二个和第三个操作数必须具有相同的类型,即表达式的结果类型<代码>整数和
当然不是同一类型

但是,如中所述,编译器将在确定应用于表达式的可能公共类型时应用。该部分有一个方便的表15.25-D,它告诉我们,当第二个操作数的类型为
Integer
,第三个操作数的类型为
Long
,编译器将对
Integer,Long
进行二进制数字升级。对
整数、长
进行二进制数字升级将产生
。因此,条件运算符表达式的结果是
long

由于表达式的结果类型是
long
,因此必须取消对
Integer
long
的装箱(如果是
Integer
,则必须进行强制转换)

最后,将其指定给一个
对象
,该对象强制装箱,并将
包装为
。因此,您将得到一个
Long
,其中包含与您的输出相匹配的值
0

因此,有效地说,如果我们忽略编译器将优化以下内容的一半这一事实,因为由于代码中的
true
(我在下面使用了
flag
),它将处理一个常量表达式,那么代码最终将是这样的:

Object obj = Long.valueOf(flag ? (long)(new Integer(0)).intValue() : (new Long(1)).longValue());
System.out.println(obj.getClass() + "\nvalue = " + obj);
  • (long)(新整数(0)).intValue()
    表示取消对
    整数的装箱,并将其强制转换为
    long
    ,以便与表达式结果类型匹配
  • (新的Long(1)).longValue()
    表示取消对
    Long
    的装箱,因此它与表达式结果类型匹配
  • Long.valueOf
    表示最后的装箱

这一行为在以下章节中得到了很好的解释:

条件运算符有三个操作数表达式<代码>?
出现在第一个和第二个表达式之间,而
出现在第二个和第三个表达式之间

[……]

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

  • [……]

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

    • [……]

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


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

两侧的操作数必须是兼容类型,因此您不能有以下操作数:

true ? 1 : "Hello"
因为
int
String
不能相互隐式转换


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

要使三元语句有效,双方应返回相同的值type@PeterLawrey
objecto=false?新长(0):新整数(1)
还将返回
类java.lang.Long
1
。这不是最后一个论点的类型,而是一种可以通过扩大范围来接受的类型。我喜欢研究不好的问题得到很多赞成票。但如今,阅读JLS的要求太高了……澄清一下,这是另一本的复制品,而不是另一本。另请参阅并稍微相关
true ? 1 : "Hello"