Si intento convertir a String
a a java.util.Date
, el compilador de Java detecta el error. Entonces, ¿por qué el compilador no marca lo siguiente como un error?
List<String> strList = new ArrayList<>();
Date d = (Date) strList;
Por supuesto, la JVM lanza un ClassCastException
en tiempo de ejecución, pero el compilador no lo marca.
El comportamiento es el mismo con javac 1.8.0_212 y 11.0.2.
java
casting
compiler-errors
javac
Mike Woinoski
fuente
fuente
List
aquí.Date d = (Date) new Object();
strList
fuera una instancia de una clase que implementa List.Respuestas:
El reparto es técnicamente posible. Javac no puede demostrar fácilmente que no es así en su caso y el JLS en realidad define esto como un programa Java válido, por lo que marcar un error sería incorrecto.
Esto se debe a que
List
es una interfaz. Por lo tanto, podría tener una subclase de unaDate
que realmente implementeList
disfrazada comoList
aquí, y luego lanzarlaDate
estaría perfectamente bien. Por ejemplo:Y entonces:
La detección de este escenario podría no ser siempre posible, ya que requeriría información de tiempo de ejecución si la instancia proviene, por ejemplo, de un método. E incluso si, requeriría mucho más esfuerzo para el compilador. El compilador solo evita los lanzamientos que son absolutamente imposibles debido a que no hay forma de que el árbol de clases coincida en absoluto. Que no es el caso aquí, como se ve.
Tenga en cuenta que JLS requiere que su código sea un programa Java válido. En 5.1.6.1. Conversión de referencia de estrechamiento permitida dice:
Entonces, incluso si el compilador pudiera descubrir que su caso es realmente imposible, no está permitido marcar un error porque el JLS lo define como un programa Java válido.
Solo se le permitiría mostrar una advertencia.
fuente
myDate = (Date) myString
fallar. Usando la terminología JLS, la declaración intenta convertir deS
(theString
) aT
(theDate
). Aquí,S
no es un tipo de interfaz, por lo que no se aplica la condición JLS citada anteriormente. Como ejemplo, intente enviar un Calendario a una Fecha y obtendrá un error de compilación aunque ninguna de las clases sea final.Date & List
es inhabitable , no es suficiente para demostrar que está deshabitado actualmente (podría estarlo en el futuro).Consideremos una generalización de su ejemplo:
Estas son las razones principales por las
Date d = (Date) strList;
que no se trata de un error de compilación.La razón intuitiva es que el compilador no (en general) conoce el tipo preciso del objeto devuelto por esa llamada al método. Es posible que además de ser una clase que implementa
List
, es también una subclase deDate
.La razón técnica es que la Especificación del lenguaje Java "permite" la conversión de referencia de estrechamiento que corresponde a este tipo de conversión . De acuerdo con JLS 5.1.6.1 :
En un lugar diferente, JLS también dice que se puede lanzar una excepción en tiempo de ejecución ...
Tenga en cuenta que la determinación de JLS 5.1.6.1 se basa únicamente en los tipos declarados de las variables involucradas en lugar de los tipos de tiempo de ejecución reales. En el caso general, el compilador no conoce ni puede conocer los tipos de tiempo de ejecución reales.
Entonces, ¿por qué el compilador de Java no puede resolver que el elenco no funcionará?
En mi ejemplo, la
someMethod
llamada podría devolver objetos con una variedad de tipos. Incluso si el compilador pudo analizar el cuerpo del método y determinar el conjunto preciso de tipos que podrían devolverse, no hay nada que impida que alguien lo cambie para devolver diferentes tipos ... después de compilar el código que lo llama. Esta es la razón básica por la que JLS 5.1.6.1 dice lo que dice.En su ejemplo, un compilador inteligente podría descubrir que el elenco nunca puede tener éxito. Y está permitido emitir una advertencia en tiempo de compilación para señalar el problema.
Entonces, ¿por qué no se le permite a un compilador inteligente decir que esto es un error de todos modos?
Porque el JLS dice que este es un programa válido. Período. Cualquier compilador que haya llamado a esto un error no sería compatible con Java.
Además, cualquier compilador que rechace los programas de Java que JLS y otros compiladores dicen que es válido, es un impedimento para la portabilidad del código fuente de Java.
fuente
5.5.1. Tipo de referencia de fundición:
List<String>
esS
yDate
esT
en tu caso.fuente