Double a = null;
double b = 0;
Scanner in = new Scanner(System.in);
boolean t = in.next().equals("y");
System.out.println(t ? a : b);
执行上述代码, 如果t为true则会抛出NPE, 执行javap查看反编译结果如图
可以看到54行执行了一次拆箱操作, 所以以下两行代码是等价的
t ? a : b
t ? a.doubleValue() : b
所以如果a = null, 当t=true会报NPE.
那么为什么好好的要拆箱呢? 以下是三目运算符表达式返回结果的规则:
首先将操作数的类型分为四种: 基础类型, 包装类型, null类型, object类型(不包括包装类型和null类型).
- 如果操作数一个为基础类型, 一个为包装类型, 则表达式返回值必为基础类型. 以下几种情况都需要考虑拆箱的问题.
- 操作数一个是基础类型, 另一个是其包装类型, 则返回该基础类型, 如 double = boolean ? Double : double;
- 操作数一个是基础类型, 另一个是其他基础类型的包装类型, 则返回表示范围更大的基础类型, 如 double = boolean ? Doubel : long;
- 操作数A是byte, char, short, 或者其包装类型, 另一个是数字常量(int), 则返回值返回A的类型的基础类型, 如 char = boolean ? char : 11;
- 如果操作数一个为基础类型或者包装类型, 另一个为null类型, 则表达式返回值必为包装类型. 如 Long = boolean ? long : null; 如果使用基础类型去接返回值则需要考虑拆箱问题
- 如果操作数一个为object类型, 则表达式返回值必为object类型. object = boolean ? long : object;
注: 链接中的名词解释
bnp: bnp(..) means to apply binary numeric promotion; 我理解就是数字类型小范围像大范围的转换, 比如int -> double
T | bnp(..): The form "T | bnp(..)" is used where one operand is a constant expression of type int and may be representable in type T, where binary numeric promotion is used if the operand is not representable in type T
这里就是说, 如果一个操作数是常量的情况的话就取T, 否则按照bnp的规则处理.
lub: 解释文档 The least upper bound, or "lub", of a set of reference types is a shared supertype that is more specific than any other shared supertype (that is, no other shared supertype is a subtype of the least upper bound). This type, lub(U1, ..., Uk), is determined as follows.
If k = 1, then the lub is the type itself: lub(U) = U;
最小上界, lub(U1, U2) 结果就是U1和U2的公共父类中距离它俩最近的一个. 所以lub(U1) = U1, 特殊的null, lub(null, U1) = U1.