scala> def g[T] = 1.asInstanceOf[T]
g: [T]=> T
scala> g[String]
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
... 32 elided
scala> { g[String]; 1 }
res0: Int = 1
But:
scala> def f = 1.asInstanceOf[String]
f: String
scala> { f; 1 }
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at .f(<console>:7)
... 32 elided
What is the logic here? How do I trigger ClassCastException
in a type parametric function?
This warning answers my question:
scala> def g[T] = 1.isInstanceOf[T]
<console>:7: warning: abstract type T is unchecked since it is eliminated by erasure
def g[T] = 1.isInstanceOf[T]
^
So asInstanceOf[T]
is a compile-time cast. It has no effect at run-time. In the case where I got the ClassCastException
it was raised not by asInstanceOf[T]
but by the actual conversion that happened outside of the function.
The solution is to take a ClassTag
and use classTag[T].runtimeClass.cast
. This behaves slightly differently though: you can use asInstanceOf[Double]
on an Int
, but cast
will fail with a ClassCastException
. The solution to this problem then is to use Apache commons-lang
's ClassUtils.isAssignable
.