[英]Java conditional operator ?: result type
我对条件运算符有点疑惑。 请考虑以下两行:
Float f1 = false? 1.0f: null;
Float f2 = false? 1.0f: false? 1.0f: null;
为什么f1变为null而第二个语句抛出NullPointerException?
Langspec-3.0 para 15.25 sais:
否则,第二和第三操作数分别是S1和S2类型。 设T1是将拳击转换应用于S1所产生的类型,让T2为应用到S2的装箱转换所产生的类型。 条件表达式的类型是将捕获转换(第5.1.10节)应用于lub(T1,T2)(第15.12.2.7节)的结果。
那么对于false?1.0f:null
T1是Float而T2是null类型。 但是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。
区别在于编译时表达式的静态类型:
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 内部条件的第三个操作数的类型是null类型,而f2 外部条件的第三个操作数的类型被认为是Float。
注意:重要的是要记住,类型的确定和装箱/拆箱代码的插入是在编译时完成的。 装箱/拆箱代码的实际执行是在运行时完成的。
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内部条件中的操作数类型是:
type of second operand = float
type of third operand = null type (§4.1)
§15.25中的大多数规则都已通过,最终的评估确实适用:
否则,第二和第三操作数分别是S1和S2类型。 设T1是将拳击转换应用于S1所产生的类型,让T2为应用到S2的装箱转换所产生的类型。 条件表达式的类型是将捕获转换(第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引用变量,表达式(null)的结果被成功分配。
对于f2外条件:( 假?1.0f:[f2内条件])
对于f2外部条件,类型是:
type of second operand = float
type of third operand = Float
注意操作数类型与直接引用空文本的f1 / f2内部条件(第4.1节 )相比的差异。 由于具有2个数字可转换类型的这种差异, §15.12.2.7中的此规则适用:
由于对f2内部条件(null)的结果执行了拆箱转换,因此引发了NullPointerException。
当您尝试将null分配给基元时,以下内容将抛出NPE
float f1 = false ? 1.0f: null;
我认为这是在第二个声明中引起NPE的原因。 因为第一个三元组为float返回一个float,所以它也尝试将false转换为float。
第一个语句不会转换为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;
是或不是,这就是问题。 :)
编辑:实际上,看起来更接近似乎这个案例实际上是哈姆雷特 (三元运算符和包裹的整数类型)和猫王 (自动拆箱无效)益智游戏之间的混合。 无论如何,我只能推荐观看视频,这是非常有教育意义和愉快的。
看起来JVM试图将第二个空值解包到float而不是Float ,因此NullPointerException。 自己打一次。 我的看法是第二个如果它是因为第一个的真实部分if评估为浮点数,而不是浮点数。
再考虑一下,我认为这是一种Java告诉你,你正在做一些奇怪的事情。 只是不要嵌套三元ifs你会没事的:-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.