Here's the contrived experiments in 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
I know type parameter is quite limited due to type erasion, but still confused by the different behaviours between asInstanceOf and isInstanceOf here.
Wonder if someone has any insight about that? Thanks!
Well, you must know, that type parameters are not available at runtime, all information they carry can only be used by the compiler. Now, asInstanceOf
is just a cast, it is only needed to the compiler to enforce the type compatibility, and at runtime it doesn't do anything at all: a reference is a reference, regarding of the type of underlying object.
isInstanceOf
on the other hand is the opposite: compiler does not know anything about it, it's just a function call. It is executed at runtime to check whether the given object is of the expected type. But the type parameter is not available at runtime, so how would it know which type to check against? For this reason, it needs a real Class
argument.