Java中使用盒装类型的三元条件的奇怪行为

时间:2015-05-16 18:12:51

标签: java ternary-operator

我的应用程序(简化版)中有这段代码:

Object result;
if (check)
    result = new Integer(1);
else
    result = new Double(1.0);
System.out.println(result);
return result;

然后我决定将if-else语句重构为三元条件表达式,以便我的代码更简洁:

Object result = check ? new Integer(1) : new Double(1.0);
System.out.println(result);
return result;

事实证明,如果检查是true,则两个版本会打印出不同的结果:

1

或:

1.0

不是三元条件等价于相应的if-else?

5 个答案:

答案 0 :(得分:25)

if / else和条件(三元)表达式不完全等同于。条件表达式的结果必须具有类型。

您正在观察数字类型提升(或类型强制)的效果。

以下是语言规范的摘录(参见here),来自描述条件表达式返回值的部分:

  

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

最后这种情况是(我在这里省略了其他情况):

  

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

以下是与二进制数字促销相关的其他规范:

  

应用扩展基元转换(第5.1.2节)来转换以下规则指定的一个或两个操作数:

     
      
  • 如果任一操作数的类型为double,则另一个操作数将转换为double。
  •   

这是第一种情况(以下案例省略)。 double总是胜利。

因此,无论条件表达式中第2和第3个操作数的顺序如何,表达式的返回类型都将提升为double

答案 1 :(得分:6)

简而言之,三元运算符与其他涉及数字类型提升的运算符没有区别。

当你有System.out.println(1 + 1.0)之类的东西时,你希望它打印2.0,因为输出中使用的操作数受数字类型提升的影响。

与三元运算符完全相同:System.out.println(true ? 1 : 1.0)在执行与1.0表达式相同的数字类型提升后将打印1 + 1.0

它的工作方式非常简单:运算符结果的类型应该在编译时知道,而实际结果是在运行时确定的。

答案 2 :(得分:4)

简短回答

第一个示例明确键入为Object,导致向上播放。

第二个示例隐式输入为Double,这会导致数字扩展。

答案很长

Object的示例中,没有值转换,只有转发,并且打印了1。

Object result;
if (1 == 1)
    result = new Integer(1);
else
    result = new Double(1.0);

如果您使用Double声明,则会扩大并打印1.0。

Double result;
if (1 == 1)
    result = new Integer(1);
else
    result = new Double(1.0);

由于存在明确的类型,因此这些非常简单。

然而,三元表达式没有明确的类型,规则也不重要。

  

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

     
      
  • 如果第二个和第三个操作数具有相同的类型(可能是null类型),那么这就是条件表达式的类型。

  •   
  • 如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是将装箱转换(第5.1.7节)应用于T的结果,那么条件表达式的类型是吨。

  •   
  • 如果第二个和第三个操作数之一是null类型而另一个操作数的类型是引用类型,则条件表达式的类型是该引用类型。

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

         
        
    • 如果其中一个操作数的类型为字节或字节,另一个操作数的类型为short或Short,则条件表达式的类型很短。

    •   
    • 如果其中一个操作数是T类型,其中T是byte,short或char,另一个操作数是int类型的常量表达式(第15.28节),其值可以在类型T中表示,那么条件表达式的类型是T.

    •   
    • 如果其中一个操作数是T类型,其中T是Byte,Short或Character,另一个操作数是int类型的常量表达式(第15.28节),其值可以在类型U中表示。是将取消装箱转换应用于T的结果,则条件表达式的类型为U.

    •   
    • 否则,二进制数字提升(第5.6.2节)将应用于操作数类型,条件表达式的类型是第二个和第三个操作数的提升类型。请注意,二进制数字促销执行值集转换(第5.1.13节)并可执行拆箱转换(第5.1.8节)。

    •   
  •   
  • 否则,第二个和第三个操作数分别为S1和S2类型。设T1是将拳击转换应用于S1所产生的类型,让T2为应用到S2的装箱转换所产生的类型。条件表达式的类型是将捕获转换(第5.1.10节)应用于lub(T1,T2)(§15.12.2.7)的结果。

  •   

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25

数字IntegerDouble的“推广类型”是Double

答案 3 :(得分:2)

除了@ pb2q回答

您可以将其验证为

public class test {
    public static void main(String[] args) {
    Object result;
    Boolean check = true;

        if (check)
            result = new Integer(1);
        else
            result = new Double(1.0);
        System.out.println(result);
        result = check ? new Integer(2) : new Double(1.0);
        System.out.println(result);
    }
}

由于数字促销,它将打印2.0而不是2

答案 4 :(得分:1)

除了现有答案之外,您还可以通过特定的方式转换为所需类型来避免此问题:

Object result = args.length < 100 ? (Object)2 : (Object)1.0;

将整数作为整数转换为Object,将双精度转换为双精度。 &#34;:&#34;两侧的表达式然后都是Object类型,因此编译器不需要生成任何进一步的转换。