在 Java 中使用 if 与 ternary opertator 时的“错误”返回类型

在以下类中,两个方法的返回类型与三元运算符的想法不一致:

return condition?a:b;

等效于

if(condition) {
    return a;
} else{ 
    return b;
}

第一个返回双精度,第二个返回多头:

public class IfTest {
    public static Long longValue = 1l;
    public static Double doubleValue = null;

    public static void main(String[] args) {
        System.out.println(getWithIf().getClass());// outpus Long
        System.out.println(getWithQuestionMark().getClass());// outputs Double
    }

    public static Object getWithQuestionMark() {
        return doubleValue == null ? longValue : doubleValue;
    }

    public static Object getWithIf() {
        if (doubleValue == null) {
            return longValue;
         } else {
            return doubleValue;
        }
    }
}

我可以想象这与编译器狭隘地转换返回类型有关,但是这种语言明智吗?这当然不是我所期望的。getWithQuestionMark()

任何见解最受欢迎!

编辑:下面有很好的答案。此外,@sakthisundar引用的以下问题探讨了三元运算符中发生的类型提升的另一个副作用:Java中的棘手三元运算符 - 自动装箱


答案 1

基本上,它遵循JLS第15.25节的规则,特别是:

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

  • [...]

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

因此,遵循第5.6.2节,这基本上将涉及拆箱 - 因此,这使您的表达式工作,就好像和分别属于类型和类型一样,并且加宽促销应用于获得整体结果类型。longValuedoubleValuelongdoublelongdouble

然后将其装箱,以便从该方法返回 。doubleObject


答案 2

除了@Jon的答案之外,看看你看到的字节码:

public static java.lang.Object getWithQuestionMark();
  Code:
   0:   getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   3:   ifnonnull       16
   6:   getstatic       #8; //Field longValue:Ljava/lang/Long;
   9:   invokevirtual   #9; //Method java/lang/Long.longValue:()J
   12:  l2d
   13:  goto    22
   16:  getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   19:  invokevirtual   #10; //Method java/lang/Double.doubleValue:()D
   22:  invokestatic    #11; //Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
   25:  astore_0
   26:  aload_0
   27:  areturn

然而,如果你告诉编译器你对数字不感兴趣:

public static Object getWithQuestionMark() {
    return doubleValue == null ? (Object)longValue : (Object)doubleValue;
}

你会得到你所追求的(字节码)

public static java.lang.Object getWithQuestionMark();
  Code:
   0:   getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   3:   ifnonnull       12
   6:   getstatic       #8; //Field longValue:Ljava/lang/Long;
   9:   goto    15
   12:  getstatic       #7; //Field doubleValue:Ljava/lang/Double;
   15:  areturn

输出:

$ java IfTest
class java.lang.Long
class java.lang.Long