Scala:为什么asInstanceOf可以接受类型参数但isInstanceOf不能接受?

时间:2015-12-10 12:59:29

标签: scala type-parameter

以下是REPL(scala 2.11)中的人为实验:

scala> class Foo[T] {
     |   def as(x: Any) = x.asInstanceOf[T]
     | }

defined class Foo

scala> val foo = new Foo[String]
foo: Foo[String] = Foo@65ae6ba4

scala> val x: Any = 123
x: Any = 123

scala> foo.as(x)  // expected
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
  ... 33 elided

scala> val y: Any = "abc"
y: Any = abc

scala> foo.as(y)
res1: String = abc


scala> class Bar[T] {
     |   def is(x: Any) = x.isInstanceOf[T]
     | }

<console>:12: warning: abstract type T is unchecked since it is eliminated by erasure
         def is(x: Any) = x.isInstanceOf[T]
                                        ^
defined class Bar

scala> val bar = new Bar[String]
foo: Foo[String] = Foo@1753acfe

scala> val x: Any = 123
x: Any = 123

scala> bar.is(x)  // unexpected
res2: Boolean = true

scala> val y: Any = "abc"
y: Any = abc

scala> bar.is(y)
res3: Boolean = true

我知道类型参数由于类型擦除而非常有限,但仍然被asInstanceOf和isInstanceOf之间的不同行为所迷惑。

想知道是否有人对此有任何见解?谢谢!

1 个答案:

答案 0 :(得分:4)

嗯,您必须知道,类型参数在运行时不可用,它们携带的所有信息只能由编译器使用。现在,asInstanceOf只是一个强制转换,只需要编译器强制执行类型兼容性,并且在运行时它根本不做任何事情:引用是一个引用,关于底层对象的类型

另一方面,

isInstanceOf则相反:编译器对此一无所知,它只是一个函数调用。它在运行时执行以检查给定对象是否是预期类型。但是类型参数在运行时不可用,那么它如何知道要检查哪种类型?因此,它需要一个真正的Class参数。