在Java中使用if与三元opertator时,“错误”返回类型
在下面的类中,两种方法的返回类型与三元运算符的思想不一致:
return condition?a:b;
相当于
if(condition) { return a; } else{ return b; }
第一个返回一个Double,第二个返回Long:
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中的Tricky三元运算符 – 自动装箱
基本上它遵循JLS第15.25节的规则,具体来说:
否则,如果第二个和第三个操作数具有可转换的类型(第5.1.8节)到数字类型,则有几种情况:
[…]
否则,二进制数字提升(第5.6.2节)将应用于操作数类型,条件表达式的类型是第二个和第三个操作数的提升类型。
因此遵循5.6.2节 ,它基本上涉及拆箱 – 所以这使得你的表达式好像longValue
和doubleValue
分别是long
和double
类型,并且扩展促销应用于long
以获得double
的整体结果类型。
然后将该double
加框,以便从方法返回Object
。
除了@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