如果Int不能为null,则null.asInstanceOf [Int]是什么意思?

时间:2012-05-25 05:39:07

标签: scala null

作为测试,我写了这段代码:

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,它不能为空......

我错过了什么?

4 个答案:

答案 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

但是,你会看到它在运行时爆炸。