编写 if-else 编译器时会抱怨,但简而言之却没有,为啥? [复制]
Posted
技术标签:
【中文标题】编写 if-else 编译器时会抱怨,但简而言之却没有,为啥? [复制]【英文标题】:When writing if-else compiler complains but for shorthand it does not, why? [duplicate]编写 if-else 编译器时会抱怨,但简而言之却没有,为什么? [复制] 【发布时间】:2015-03-17 16:42:03 【问题描述】:当我这样写时在 Java 中
public int method(boolean b)
if (b)
return null;
else
return 0;
编译器抱怨incompatible types
,但如果用速记代替它
public int method(boolean b)
return (b ? null : 0);
编译器不会报错,而且会有NPE
。
所以我的问题是
-
为什么编译器不抱怨
为什么是
NPE
?
【问题讨论】:
2. NPE 因为 Integer.intValue() 在 null 上调用。原始类型 int 不能为 null, 【参考方案1】:这是由自动拆箱和类型推断共同造成的。
在这两种情况下,从类型签名中可以清楚地看出该方法必须返回一个int
。
在您的第一种情况下,您显式返回null
,它不能分配给int
,因此编译器正确地抱怨这是一个错误。
在第二种情况下,您正在创建一个匿名值(括号中的位),因此编译器必须推断它的类型。事实证明,0
和 null
最具体的常见超类型是 Integer
- 这是正确的。因此,您的 return 语句返回了 Integer
类型的东西——并且这个 与 int
兼容,它只是在运行时自动拆箱。当 VM 尝试将空引用转换为 int
时,正是这种自动拆箱引发了 NPE。
如果它可以帮助您更好地对其进行可视化,那么您的第二个示例与以下示例基本相同:
public int method(boolean b)
Integer tmp = (b ? null : 0);
return tmp;
因此编译器没有什么可抱怨的(这两行本身都很好)。
这里的错误,如果有的话,是自动拆箱,并默默地假装Integer
与int
是同一类型。不是,正是因为这个原因。
【讨论】:
啊,这就解释了为什么第一个示例中的return (Integer) null;
使编译错误消失了,但在运行时保留了 NPE。
更像return tmp.intValue()
。
@OldCurmudgeon return tmp;
工作正常,您不需要显式调用 intValue()
,因为 Java 会自动拆箱而不会抱怨。
@azurefrog - 正确 - 但它更清楚地展示了 NPE 的来源。
第二种情况与“匿名值”无关。使用的ternary operator rule 是:“第 2/3 个操作数之一是原始类型 T,另一个的类型是对 T 应用装箱转换的结果,则类型 ... 是 T i>":因此它将三元的结果评估为int
,可以返回(§14.17),因为它可以分配给int
。这就是该方法编译的原因。然后将字节码编译为Integer.intValue()null
(不幸的是,先装箱然后再拆箱0),这会在运行时抛出NPE。【参考方案2】:
问题在于您要返回的类型。 您不能将 null 分配给原始类型。 这是一个半答案我不知道为什么它在速记版本中没有抱怨。
【讨论】:
字符串不是原始类型。 真的!我有点心烦意乱,因为工作太多。我会更正答案。以上是关于编写 if-else 编译器时会抱怨,但简而言之却没有,为啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为啥 sip 在使用 char * 时会抱怨意外类型“str”?