作为测试,我写了这段代码:
object Ambig extends App {
def f( x:Int ) { println("Int" ) }
def f( x:String ) { println("String") }
f( null.asInstanceOf[Int ] )
f( null.asInstanceOf[String] )
f(null)
}
我希望在最后一次调用f()时遇到错误,说这是不明确的。编译器接受了它,并产生了这个输出:
Int
String
String
现在我猜这与Int不是AnyRef的事实有关,因此f(null)的唯一f版本是f(x:String)。但是,如果Int不能为null,则null.asInstanceOf [Int]是什么意思? repl表示它的类型为Int:
scala> :type null.asInstanceOf[Int]
Int
但我真的不知道它是如何运作的。毕竟,如果我尝试将一个String转换为一个Int,那么所有的地狱都会崩溃:
scala> "foo".asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source)
...
当然这是预期的 - “foo”不能成为Int。但是两者都不能为null,那么为什么将int转换为Int工作呢?大概是以某种形式装箱,但是类型仍然是Int,它不能为空......
我错过了什么?
答案 0 :(得分:48)
将null
投射到Int
的行为取决于完成它的上下文。
首先,如果你将null
转换为Int
,它实际上意味着一个盒装整数,其值为null
。如果将表达式放在期望类型为Any
的上下文中(在场景后面转换为Object
,因为在JVM字节码中,无法引用基本类型和引用类型具有相同的引用),然后不会进一步转换此值 - 这就是println(null.asInstanceOf[Int])
打印null
的原因。
但是,如果在期望基元Int
(Java int
)的上下文中使用相同的盒装整数值,则它将转换为基元,null
为(作为引用类型的默认值)转换为0
(基本类型的默认值)。
如果通用方法执行此操作,则自然会得到null
。
但是,如果此方法是专用的,则其返回类型为Int
(在本例中为原始整数),因此必须将null: Any
值转换为基元,如前所述
因此,运行:
object Test extends App {
println(null.asInstanceOf[Int])
def printit(x: Int) = println(x)
printit(null.asInstanceOf[Int])
def nullint[T] = null.asInstanceOf[T]
println(nullint[Int])
def nullspecint[@specialized(Int) T] = null.asInstanceOf[T]
println(nullspecint[Int])
}
产生
null
0
null
0
答案 1 :(得分:20)
这就是事情:asInstanceOf
没有意义。这个方法的作用是告诉编译器STOP MAKING SENSE,并相信你在说什么。
现在,如果你想知道为什么它会返回0,那是因为asInstanceOf
适用于AnyRef
,而不是AnyVal
。应用于AnyVal
时,它将使用装箱版本,装箱null
的值为0。
答案 2 :(得分:4)
看起来它只是自动将其转换为零:
scala> null.asInstanceOf[Int]
res0: Int = 0
当然,与null不同,0可以是Int
。
答案 3 :(得分:0)
首先,我们都同意,我们无法将null
分配给http://www.scala-lang.org/api/current/index.html#scala.Null
scala.Int
第二,为什么当我们println(null.asInstanceOf[Int])
时,它会给null
?
这是因为println的实现。它最终调用java String.valueOf
方法,即
return (obj == null) ? "null" : obj.toString();
如果在shell中执行null.asInstanceOf[Int] == null
,它将返回true,但它会发出相反的警告:“使用`=='比较Int和Null类型的值将始终产生false”。我认为这可能是scala类型擦除中的一个问题。
执行println
只需要scala.Any类型,因此null.asInstanceOf[Int]
的转换实际上还没有发生。所以我们只需要记住,当你将null.asInstanceOf[Int]
分配给Int时,基于Scala的擦除语义在运行时进行转换,并为它分配0。
顺便说一句,你仍然可以在没有任何编译错误的情况下执行f(null),因为scala正在为你进行隐式转换
null -> java.lang.Integer -> scala.Int
但是,你会看到它在运行时爆炸。