【问题标题】:Why is Scala asIstanceOf seemingly ignored?为什么 Scala asIstanceOf 似乎被忽略了?
【发布时间】:2016-03-19 08:56:06
【问题描述】:

试试这个:

object Box {
  val stuff:Any = "something"
  def foo[T]():T = {
    val z = stuff
    println(s"z = $z   class = ${z.getClass.getName}")
    val y = z.asInstanceOf[T]
    println(s"y = $y   class = ${y.getClass.getName}")
    y
  }
}

println(Box.foo[Boolean]())

运行时我得到输出:

z = something   class = java.lang.String
y = something   class = java.lang.String

所以即使 stuff 是 Any 类型,它确实知道 z(从 stuff 分配)是一个字符串。我显然试图将其转换为 T,这显然是我的 println 语句中的布尔值。这怎么不炸?为什么它认为 y 是一个字符串?

如果我将 foo() 中的 T 硬连接到布尔值,我会得到预期的失败输出:

z = something   class = java.lang.String
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
    at scala.runtime.BoxesRunTime.unboxToBoolean(BoxesRunTime.java:85)
    ...

就好像它完全忽略了我的 .asInstanceOf[T]。为什么?

【问题讨论】:

  • 由于部分类型擦除,.asInstanceOf[T] 不可能做任何事情。转换为泛型类型在 Java 中也不起作用。这是JVM的限制。编译器不会在那一行给你一个警告吗?
  • 2.12.0-M3 上,当用Boolean 替换val y = z.asInstanceOf[T]T 时,我得到<console>:18: error: type mismatch; found : y.type (with underlying type Boolean) required: T y ^

标签: scala


【解决方案1】:

正如 Chris Martin 所说,这是因为类型擦除而发生的。然而,在 Scala 中,可以使用ClassTag 告诉编译器保存已擦除的类型

作为示例,我稍微修改了您的代码,如果您运行它,您将得到 ClassCastException

object Box {
  val stuff: Any = "something"
  def foo[T](implicit ev: ClassTag[T]): T = {
    val z = stuff
    println(s"z = $z   class = ${z.getClass.getName}")
    val y = ev.runtimeClass.cast(z)
    println(s"y = $y   class = ${y.getClass.getName}")
    z.asInstanceOf[T]
  }
}
println(Box.foo[Boolean])

【讨论】:

    猜你喜欢
    • 2021-09-09
    • 2021-10-28
    • 2016-09-30
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 2013-02-27
    • 1970-01-01
    • 2017-12-05
    相关资源
    最近更新 更多