La razón para el primer resultado es que el método getClass
tiene la siguiente firma en Java
public final Class<?> getClass()
que hereda Scala. Si bien sabemos que si llamamos getClass
en una referencia de tipo T de la firma podría ser
public final Class<? extends T> getClass()
el compilador no lo hace. Se podría imaginar alguna extensión del lenguaje para proporcionar un tipo especial que representa el tipo estático del receptor que permita
public final Class<? extends Receiver> getClass()
o algún tipo de carcasa especial en el compilador para getClass
. De hecho, parece que Snoracle Java de hecho casos especiales getClass
, pero no estoy seguro de que sea requerido por la Especificación del lenguaje Java. Sin embargo, si tiene una referencia de algún tipo estático particular T, no hay razón por la que no pueda hacer el equivalente T.class
(java) o classOf[T]
(scala). En otras palabras, tal extensión no aportaría mayor poder expresivo, pero complicaría la implementación del lenguaje.
En cuanto al "lanzamiento del tiempo de compilación" frente al "lanzamiento estático", en realidad no hay diferencia. Sería correcto para un compilador desugar x.asInstanceOf[T]
a classOf[T].cast(x)
.
Cualquier lenguaje con subtipificación tendrá la posibilidad de que el tipo de referencia estáticamente conocido sea menos específico que el tipo del valor al que hace referencia. Los lenguajes con sistemas de tipo estático que no tienen subtipos generalmente no tienen un concepto de tipos de tiempo de ejecución ya que solo hay un tipo real que habita un nombre de tipo dado. En estos idiomas, los tipos se borran en el tiempo de ejecución, de la misma manera que los parámetros de tipo se borran en la JVM.
Espero que esto ayude a su comprensión de los tipos estáticos de referencias en comparación con el tipo de valores de tiempo de ejecución.