Java三元运算符似乎不一致地将整数强制转换为整数

Dav*_*ant 9 java casting

我的一个学生在使用三元运算符时会得到空指针异常,有时会导致null.我想我理解这个问题,但似乎是因为类型推断不一致所致.换句话说,我觉得这里的语义不一致,错误应该可以避免,而不改变他的方法.

这个问题类似于,但与另一个关于三元运算符的问题不同.在那个问题中,null Integer必须强制为int,因为函数的返回值是int.但是,我学生的代码并非如此.

这段代码运行正常:

Integer x = (5>7) ? 3 : null;
Run Code Online (Sandbox Code Playgroud)

x的值为null.没有NPE.在这种情况下,编译器可以确定三元运算符的结果需要是Integer,因此它将3(一个int)转换为Integer而不是将null转换为int.

但是,运行此代码:

Integer x = (5>7) ? 3 : (5 > 8) ? 4 : null;
Run Code Online (Sandbox Code Playgroud)

导致NPE.发生这种情况的唯一原因是因为null被转换为int,但这并不是必需的,并且似乎与第一位代码不一致.也就是说,如果编译器可以推断第一个snipet三元运算符的结果是整数,为什么不能在第二种情况下这样做呢?第二个三元表达式的结果必须是整数,并且由于该结果是第一个三元运算符的第二个结果,因此第一个三元运算符的结果也应该是整数.

另一个snipet工作正常:

Integer three = 3;

Integer x = (5>7) ? three : (5 > 8) ? three+1 : null;
Run Code Online (Sandbox Code Playgroud)

在这里,编译器似乎能够推断出两个三元运算符的结果都是一个整数,所以不强制将null转换为int.

biz*_*lop 13

关键是条件运算符是右关联的.确定条件表达式的结果类型的规则非常复杂,但归结为:

  1. 首先(5 > 8) ? 4 : null进行评估,第二个操作数是一个int,第三个是null,如果我们在表中查找它,该表达式的结果类型是Integer.(换句话说:因为其中一个操作数是null,这被视为参考条件表达式)
  2. 然后我们必须(5>7) ? 3 : <previous result>进行评估,这意味着在上面链接的表中,我们需要查找第二个操作数int和第三个操作数的结果类型Integer:它是int.这意味着<previous result>需要取消装箱并失败NPE.

那么为什么第一个案例呢?

在那里,我们已经得到了(5>7) ? 3 : null;,因为我们已经看到了,如果第二个操作数int和第三个是null,结果类型为Integer.但是我们将它分配给一个Integer类型的变量,因此不需要拆箱.

但是这只发生在null文字中,下面的代码仍然会抛出一个NPE,因为操作数类型intInteger导致数字条件表达式:

Integer i = null;
Integer x = (5>7) ? 3 : i;
Run Code Online (Sandbox Code Playgroud)

总结一下:它有一种逻辑,但它不是人的逻辑.

  1. 如果两个操作数都是编译类型Integer,则结果为a Integer.
  2. 如果一个操作数是类型int而另一个是Integer,则结果是a int.
  3. 如果一个操作数是null类型(其唯一有效值是null引用),则结果为a Integer.