【问题标题】:If an Int can't be null, what does null.asInstanceOf[Int] mean?如果 Int 不能为 null,那么 null.asInstanceOf[Int] 是什么意思?
【发布时间】:2012-05-31 17:12:39
【问题描述】:

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

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 也不能,那么为什么将 null 转换为 Int 工作呢?大概是某种形式的装箱,但是类型还是Int,不能为null……

我错过了什么?

【问题讨论】:

标签: scala null


【解决方案1】:

看起来它只是自动将其转换为零:

scala> null.asInstanceOf[Int]
res0: Int = 0

当然,0 与 null 不同,它可以是 Int

【讨论】:

  • 非常有趣。我很尴尬,当我向 repl 询问 null.asInstanceOf[Int] 的 type 时,我从未想过要询问它的 value,这是我愚蠢地假设的为空。谢谢!不过,这种转换让我有点吃惊——嗯。
  • 这也让我感到惊讶。我不知道这是否是预期的行为,但对我来说似乎是错误的。
  • 这是预期的行为——您从var x: X = _ 获得的值与从var x = null.asInstanceOf[X] 获得的任何X 的值相同。
【解决方案2】:

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

【讨论】:

  • 我没有意识到 Int 是一个原始类型
【解决方案3】:

事情是这样的:asInstanceOf 不一定有意义。这个方法的作用是告诉编译器停止制造意义,并相信你所说的。

现在,如果您想知道它返回 0 的原因,那是因为 asInstanceOf 适用于 AnyRef,而不适用于 AnyVal。当应用于 AnyVal 时,它将使用盒装版本,而盒装 null 的值为 0。

【讨论】:

    【解决方案4】:

    首先,我们都同意不能将null 分配给scala.Int,如http://www.scala-lang.org/api/current/index.html#scala.Null 中所述

    第二,为什么当我们做println(null.asInstanceOf[Int])时,它会给出null
    这是因为 println 的实现。最终调用javaString.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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-28
      • 2011-06-05
      • 1970-01-01
      • 1970-01-01
      • 2016-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多