Java 条件运算符?:

一、引言       

            无意中在StackOverflow上看到有人提出的一个问题:  
          Float f1 = false? 1.0f: null;
          Float f2 = false? 1.0f: false? 1.0f: null;  
          为什么f1是null而第二个语句抛出NullPointerException?
          这就涉及到Java中常用的条件操作符?:。

二、背景知识

             条件运算符?:使用一个表达式的boolean值来决定应该计算另外两个表达式中的哪个表达式。它是右结合的即从右到左进行计算),因此a?b:c?d:e?f:g等同于a?b:(c?d:(e?f:g))

         条件运算符有3个操作数表达式。"?"出现在第一个和第二个表达式之间,而":" 出现在第二个和第三个表达式之间

         注意,第一个表达式必须是booleanBoolean类型否则会产生编译错误而且让第二个或第三个操作数表达式用一个void方法也产生编译错误。

         条件表达式的类型按照如下规则来确定:

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

         •   如果第二个和第三个操作数中的一个是基本类型T另一个是对T进行装箱的结果类型,那么条件表达式的类型就是T。

         •   如果第二个和第三个操作数的一个是空类型,另一个是引用类型,那么条件表达式的类型就是该引用类型

         •   否则如果第二个和第三个操作数中有可转换为数值类型的类型,那么就有这几种情形:

             ♦操作数之一是byteByte类型另一个shortShort类型那么条件表达式的类型就是short。

             ♦操作数之一是T类型,其中Tbyte、short或char另一个操作数是int类型的常量表达式其值可用类型T表示,那么条件表达式的类型是T。

             若操作数之一T类型,其中T是Byte、Short或Character,另一个操作数是int类型常量表达式,其值可用类型U表示,U是对T进行拆箱的结果,那么条件表达式的类型是U。

             ♦否则,二元数值提升(binary numeric promotion)会被应用于操作数类型条件表达式的类型是第二个和第三个操作数提升后的类型。注意,元数值提升执行值集转换且可能执行拆箱转换 。

         •   否则,第二个和第三个操作数的类型分别是S1和S2。T1是对S1进行装箱转换的结果类型,T2对S2进行装箱转换的结果类型 。条件表达式的类型就是对lub(T1, T2)进行捕获转换的结果。

         在运行期条件表达式的第一个操作数表达式首先进行计算。如有必要,会在结果上执行拆箝转换。随后计算所选择的操作数表达式,并且将结果转换为按上面指定规则所确定的条件表达式的类型。这个转换可能包括装箱或拆箱转换。

         声明:以上内容是本人翻译自《The Java® Language  Specification Java SE 7 Edition》2013-02-28这一版并截取了其中的一部分。

三、回归最开始的问题          

              首先要说明的是条件表达式结果类型的确定以及装箱/拆箱代码的插入是编译期完成的。装箱/拆箱代码的执行是在运行期完成的。
           我将上述两行代码编译后,然后进行反编译,结果如下:
Float localFloat1 = (Float)null;
Float localFloat2 = Float.valueOf(((Float)null).floatValue());
            很明显可以看到第二行中对null调用了拆箱方法floatValue(),所以抛出了NullPointerException。

        下面来仔细分析一下:

         (false ? 1.0f : null)这个表达式是第一个和第二个语句都有的,该表达式中第二个操作数的类型是float、第三个操作数的类型是null,所以可以应用下面这条规则:

否则,第二个和第三个操作数的类型分别是S1和S2。令T1是对S1进行装箱转换的结果类型,T2是对S2进行装箱转换的结果类型 。条件表达式的类型就是对lub(T1, T2)进行捕获转换的结果。
              所以:  S1 = float
                      S2 = null
                      T1 = Float
                      T2 = null

         那么条件表达式(false ? 1.0f : null)的类型 = Float 

         对于f1, 表达式的结果null成功赋值给一个Float引用变量。

         对于f2,现在第二个操作数的类型为float,第三个操作数的类型是Float(参见上述分析),所以接下来可对其应用如下规则: 

如果第二个和第三个操作数中的一个是基本类型T,另一个是对T进行装箱的结果类型,那么条件表达式的类型就是T。

         所以f2最终的类型为float,则先要对选择的第三个操作数(null)执行拆箱操作,然后再执行装箱操作,在拆箱过程中产生NullPointerException。

四、总结

         混合类型的计算会引起混乱,在条件运算符?:中表现的尤为明显,所以建议在条件表达式中保持第二个和第三个操作数的类型相同。

五、参考资料

      《The Java® Language  Specification Java SE 7 Edition》

        http://stackoverflow.com/questions/2615498/java-conditional-operator-result-type


转载于:https://my.oschina.net/jackieyeah/blog/207709

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值