15

NullPointerException前几天,由于三元运算符中的意外类型转换,我遇到了一个非常奇怪的问题。鉴于此(无用的示例)功能:

Integer getNumber() {
    return null;
}

我期望以下两个代码段在编译后完全相同:

Integer number;
if (condition) {
    number = getNumber();
} else {
    number = 0;
}

对比

Integer number = (condition) ? getNumber() : 0;

.

事实证明, if conditionis trueif- 语句工作正常,而第二个代码段中的三元运算抛出NullPointerException. 似乎三元运算已决定在int将结果自动装箱回Integer!?! 事实上,如果我明确地将0to强制转换Integer,异常就会消失。换句话说:

Integer number = (condition) ? getNumber() : 0;

不一样:

Integer number = (condition) ? getNumber() : (Integer) 0;

.

因此,三元运算符和等效语句之间似乎存在字节码差异if-else(这是我没想到的)。这提出了三个问题:为什么会有差异?这是三元实现中的错误还是类型转换的原因?鉴于存在差异,三元运算的性能是否比等效的语句更高或更低if(我知道,差异不会很大,但仍然如此)?

4

3 回答 3

15

根据JLS:-

条件表达式的类型确定如下:

  • 如果第二个和第三个操作数的类型相同(可能是 null 类型),那么这就是条件表达式的类型。
  • 如果第二个和第三个操作数之一是原始类型 T,而另一个的类型是对
    T 应用装箱转换(第 5.1.7 节)的结果,则条件表达式的类型是 T。
于 2012-10-06T21:31:50.850 回答
11

问题是:

Integer number = (condition) ? getNumber() : 0;

强制对 getNumber() 的结果进行拆箱和重新装箱。这是因为三进制 (0) 的 false 部分是整数,因此它会尝试将 getNumber() 的结果转换为 int。而以下没有:

Integer number = (condition) ? getNumber() : (Integer) 0;

这不是错误,只是 Java 选择做事的方式。

于 2012-10-06T21:24:27.213 回答
2

这就是它应该如何工作的方式。三元运算符并不等同于常规if语句。if和的主体else语句,而和之后的部分?:表达式它们需要评估为相同的类型。

换句话说:a = b ? c : d不应该等同于if (b) a = c; else a = d;. 相反,b ? c : d它本身就是一个表达式,其结果的分配a不会影响结果。

于 2012-10-06T21:24:36.200 回答