在下面的scala代码中,NullPointerException
将在第3个方法调用的入口处抛出。我检查了字节码。似乎在f(1, c=2)
中,编译器在f$default$2
的返回值上插入一个校验广播,将b
的类型转换为Nothing
。但在f(1)
中,编译器不进行此类转换。为什么呢?
import scala.reflect.ClassTag
import scala.reflect._
object test {
def f[T : ClassTag](a:T, b:T=null.asInstanceOf[T], c:Int=2)={ print("*"+classTag[T]+"*");println(a, b, c) }
def main(args: Array[String]) {
f(1)
f(1, 2)
f(1, c=3) //Null pointer!! But why f(1) is right?
}
}
答案 0 :(得分:0)
很难推断编译器何时执行或不执行运行时检查,我将留给一些编译器专家,但.asinstanceOf
很可能在类型参数应用Nothing
时发送错误没有界限。
一般规则 - 试图在所有可能的情况下摆脱.asInstanceOf
。
对于您的方法,一个合法的定义可能是
def f[T >: Null : ClassTag](a: T, b: T = null, c: Int = 2) = { ... }
答案 1 :(得分:0)
null.asInstanceOf
是一个坏主意,无论如何(永远不会抛出空值!)。
删除它,确实修复了NPE,但ClasTag变成 Nothing 。
看起来运行时试图在这种情况下使用第二个参数来提取ClassTag并且失败了。现在,为什么它在这种情况下这样做,但不是第一种情况f(1)
,我不知道。
有趣的是,f(1, null.asInstanceOf[Int], 3)
也有效,所以问题必须与解决默认参数的方式有关。
您也可以f[Int](1, c=3)
。这很有效。
更好的是,完全避免使用空值。这是scala。 null
引用有点像java中的goto
:你可以使用它,但真的,真的,真的不应该。