为什么三元运算符意外地转换整数?

我看到在某处讨论过,下面的代码导致成为 ,但它从左侧打印。objDouble200.0

Object obj = true ? new Integer(200) : new Double(0.0);

System.out.println(obj);

结果:200.0


但是,如果您在右侧放置一个不同的对象,例如 ,则类型是应该的。BigDecimalobjInteger

Object obj = true ? new Integer(200) : new BigDecimal(0.0);

System.out.println(obj);

结果: 200


我推测这样做的原因与将左侧投射到与/比较和计算相同的方式上有关,但是在这里,左侧和右侧不会以这种方式相互作用。doubleintegerdouble

为什么会发生这种情况?


答案 1

您需要阅读 Java 语言规范的第 15.25 节

特别:

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

  • 如果其中一个操作数的类型是 byte 或 Byte 类型,而另一个是 short 或 Short 类型,则条件表达式的类型为 short。
  • 如果其中一个操作数是 T 类型,其中 T 是字节、短整型或字符型,而另一个操作数是 int 类型的常量表达式,其值在类型 T 中是可表示的,则> - 条件表达式的类型是 T。
  • 如果其中一个操作数是 Byte 类型,而另一个操作数是 int 类型的常量表达式,其值可以用 byte 类型表示,则条件表达式的类型是 byte。
  • 如果其中一个操作数是 Short 类型,而另一个操作数是 int 类型的常量表达式,其值在 short 类型中是可表示的,则条件表达式的类型为 short。
  • 如果其中一个操作数是类型;字符和另一个操作数是 int 类型的常量表达式,其值在 char 类型中是可表示的,则条件表达式的类型是 char。
  • 否则,二进制数值提升 (§5.6.2) 将应用于操作数类型,条件表达式的类型是第二和第三个操作数的升级类型。请注意,二进制数字升级会执行拆箱转换 (§5.1.8) 和值集转换 (§5.1.13)。

因此,应用二进制数字提升,其开头为:

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

  • 如果任何操作数属于引用类型,则执行取消装箱转换 (§5.1.8)。然后:
  • 如果任一操作数的类型为双精度型,则另一个操作数将转换为双精度型。

这正是这里发生的事情 - 参数类型分别转换为 和第二个操作数(原始表达式中的第三个)是 类型 ,因此整体结果类型为 。intdoubledoubledouble


答案 2

条件运算符中的数字转换 ?:

在条件运算符 abc 中,如果 bc 都是不同的数值类型,则在编译时应用以下转换规则,以使其类型按顺序相等?:

  • 这些类型将转换为其相应的基元类型,这称为“取消装箱”。

  • 如果一个操作数是一个常量(而不是在取消装箱之前),其值在另一个类型中是可表示的,则该操作数将转换为另一个类型。intIntegerint

  • 否则,较小的类型将转换为下一个较大的类型,直到两个操作数具有相同的类型。转换订单是:
    byte -> short -> int -> long -> float -> double
    char -> int -> long -> float -> double

最终,整个条件表达式获得其第二和第三操作数的类型。

示例:
如果与 结合使用,表达式将变为 。
如果与 组合使用,表达式将变为 。
如果与 组合,表达式将变为 。
如果与 组合使用,表达式将变为 。charshortintIntegerIntegerIntegerfinal int i = 5Charactercharshortfloatfloat

在问题的示例中,200 从 转换为 ,0.0 从 into 取消装箱,整个条件表达式变为最终被装箱,因为 is 是类型。IntegerdoubleDoubledoubledoubleDoubleobjObject


推荐