Java条件运算符?:结果types
我对有条件的操作符有点困惑。 考虑以下两行:
Float f1 = false? 1.0f: null; Float f2 = false? 1.0f: false? 1.0f: null;
为什么f1变成空,第二个语句抛出一个NullPointerException?
Langspec-3.0 para 15.25 sais:
否则,第二个和第三个操作数分别是S1和S2的types。 假设T1是将装箱转换为S1所得到的types,并设T2是将装箱转换为S2所得到的types。 条件expression式的types是将采集转换(§5.1.10)应用于lub(T1,T2)(§15.12.2.7)的结果。
那么对于false?1.0f:null
T1是Float,T2是nulltypes。 但是lub(T1,T2)
的结果是什么? 这段15.12.2.7只是有点太…
顺便说一句,我在Windows上使用1.6.0_18。
PS:我知道Float f2 = false? (Float) 1.0f: false? (Float) 1.0f: null;
Float f2 = false? (Float) 1.0f: false? (Float) 1.0f: null;
不扔NPE。
区别在于编译时expression式的静态types:
概要
E1: `(false ? 1.0f : null)` - arg 2 '1.0f' : type float, - arg 3 'null' : type null - therefore operator ?: : type Float (see explanation below) - therefore autobox arg2 - therefore autobox arg3 E2: `(false ? 1.0f : (false ? 1.0f : null))` - arg 2 '1.0f' : type float - arg 3 '(false ? 1.0f : null)' : type Float (this expr is same as E1) - therefore, outer operator ?: : type float (see explanation below) - therefore un-autobox arg3
详细说明:
这是我通过阅读规范和从你得到的结果倒退的理解。 它归结为f2 内部条件为空types的第三个操作数的types,而f2 外部条件的第三个操作数的types被认为是Float。
注意:重要的是要记住,确定的types和插入的装箱/拆箱代码是在编译时完成的。 装箱/拆箱代码的实际执行在运行时完成。
Float f1 = (false ? 1.0f : null); Float f2 = (false ? 1.0f : (false ? 1.0f : null));
f1条件和f2内部条件: (false?1.0f:null)
f1条件和f2内部条件是相同的: (false?1.0f:null) 。 f1条件和f2内部条件的操作数types为:
type of second operand = float type of third operand = null type (§4.1)
第15.25节中的大部分规则都已经过了,这个最终的评估确实适用:
否则,第二个和第三个操作数分别是S1和S2的types。 假设T1是将装箱转换为S1所得到的types,并设T2是将装箱转换为S2所得到的types。 条件expression式的types是将采集转换( §5.1.10 )应用于lub(T1,T2)( §15.12.2.7 )的结果。
S1 = float S2 = null type T1 = Float T2 = null type type of the f1 and f2 inner conditional expressions = Float
因为对于f1,赋值给一个Float引用variables,expression式(null)的结果被成功赋值。
对于f2外部条件: (false?1.0f:[f2内部条件])
对于f2外部条件,这些types是:
type of second operand = float type of third operand = Float
注意操作数types与直接引用空字符的f1 / f2内部条件( §4.1 )相比的区别。 由于具有2个数字可转换types的差异,因此来自§15.12.2.7的这个规则适用:
否则,如果第二个和第三个操作数的types是可转换的( §5.1.8 )到数字types,那么有几种情况:…
- 否则,对操作数types应用二进制数字提升(第5.6.2节 ),并且条件expression式的types是第二个和第三个操作数的提升types。 请注意,二进制数字提升会执行拆箱转换 ( §5.1.8 )和值集转换( §5.1.13 )。
由于对f2内部条件(空)的结果执行了拆箱转换,因此引发了NullPointerException。
当你试图给一个原语分配一个null时,下面将会抛出一个NPE
float f1 = false ? 1.0f: null;
我相信在第二个陈述中是什么造成了NPE。 因为第一个三元组返回一个真正的浮点数,所以它也试图将false转换为浮点数。
第一个语句将不会转换为null,因为所需的结果是一个Float
例如,这不会抛出一个NPE,因为它不再需要转换为原始的
Float f = false? new Float(1.0f): true ? null : 1.0f;
我认为重写代码使得解释更加清晰:
float f = 1.0f; Float null_Float = false? f : null; // float + null -> OK Float null_Float2 = false? (Float)f : null_Float; // Float + Float -> OK Float npe = false? f : null_Float; // float + Float -> NPE
因此,NPE是我们试图做如下事情的时候:
Float npe = false? 1.0f : (Float)null;
不pipe是不是,那就是问题。 🙂
编辑:实际上,仔细看来,这种情况下,实际上是哈姆雷特 (三元运算符和包装的整数types)和猫王 (自动拆箱null)益智游戏之间的混合。 无论如何,我只能推荐看video,这是非常教育和愉快的。
它看起来像JVM试图解开第二个空来浮动,而不是浮动 ,因此NullPointerException。 自己打一次。 我的意思是,第二个如果这样做,因为第一个真正的部分, 如果评估为浮动,而不是浮动。
经过一段时间的思考之后,我认为这是一种Java的方式告诉你,你正在做一些奇怪的事情。 只要不巢三元如果,你会没事的:-)