public class Animal {
public void eat() {}
}
public class Dog extends Animal {
public void eat() {}
public void main(String[] args) {
Animal animal = new Animal();
Dog dog = (Dog) animal;
}
}
La asignación Dog dog = (Dog) animal;
no genera un error de compilación, pero en tiempo de ejecución genera un ClassCastException
. ¿Por qué el compilador no puede detectar este error?
java
casting
classcastexception
saravanan
fuente
fuente
Respuestas:
Al usar un elenco básicamente le estás diciendo al compilador "confía en mí. Soy un profesional, sé lo que estoy haciendo y sé que aunque no puedes garantizarlo, te estoy diciendo que esta
animal
variable es definitivamente va a ser un perro ".Dado que el animal no es en realidad un perro (es un animal, podrías hacerlo
Animal animal = new Dog();
y sería un perro), el VM lanza una excepción en tiempo de ejecución porque has violado esa confianza (le dijiste al compilador que todo estaría bien y es ¡no!)El compilador es un poco más inteligente que aceptar ciegamente todo, si intentas lanzar objetos en diferentes jerarquías de herencia (por ejemplo, lanzar un Perro a una Cadena), entonces el compilador te lo devolverá porque sabe que nunca podría funcionar.
Debido a que básicamente está evitando que el compilador se queje, cada vez que emite es importante verificar que no causará un
ClassCastException
al usarinstanceof
una declaración if (o algo por el estilo).fuente
Dog
se extiende desdeAnimal
!Porque teóricamente
Animal animal
puede ser un perro:En general, no es una buena idea abatir. Deberías evitarlo. Si lo usa, es mejor que incluya un cheque:
fuente
Para evitar este tipo de ClassCastException, si tiene:
Puede definir un constructor en B que tome un objeto de A. De esta manera podemos hacer el "lanzamiento", por ejemplo:
fuente
Elaborando la respuesta dada por Michael Berry.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Aquí le estás diciendo al compilador "Confía en mí. Sé
d
que realmente se refiere a unDog
objeto", aunque no lo es. Recuerde que el compilador se ve obligado a confiar en nosotros cuando hacemos un downcast .Entonces, cuando la JVM en el tiempo de ejecución descubre que en
Dog d
realidad se refiere a un objetoAnimal
y no a unDog
objeto, dice. Oye ... mentiste al compilador y arrojas una gran grasaClassCastException
.Entonces, si está abatido, debe usar la
instanceof
prueba para evitar arruinarlo.if (animal instanceof Dog) { Dog dog = (Dog) animal; }
Ahora una pregunta viene a nuestra mente. ¿Por qué el compilador del infierno está permitiendo el downcast cuando eventualmente lanzará un
java.lang.ClassCastException
?La respuesta es que todo lo que el compilador puede hacer es verificar que los dos tipos estén en el mismo árbol de herencia, por lo que, dependiendo del código que haya llegado antes del downcast, es posible que
animal
sea de tipodog
.Considere el siguiente fragmento de código:
Sin embargo, si el compilador está seguro de que el reparto no funcionaría, la compilación fallará. IE Si intenta convertir objetos en diferentes jerarquías de herencia
String s = (String)d; // ERROR : cannot cast for Dog to String
Dog d = new Dog(); Animal animal1 = d; // Works fine with no explicit cast Animal animal2 = (Animal) d; // Works fine with n explicit cast
Los dos cambios anteriores funcionarán bien sin ninguna excepción porque un perro es un animal IS-A, lo que un animal puede hacer, un perro puede hacer. Pero no es cierto, viceversa.
fuente
El código genera un error de compilación porque su tipo de instancia es un Animal:
Downcasting no está permitido en Java por varias razones. Ver aquí para más detalles.
fuente
Como se explicó, no es posible. Si desea utilizar un método de la subclase, evalúe la posibilidad de agregar el método a la superclase (puede estar vacío) y llame desde las subclases obteniendo el comportamiento que desea (subclase) gracias al polimorfismo. Por lo tanto, cuando llame a d.method (), la llamada tendrá éxito sin realizar la conversión, pero en caso de que el objeto no sea un perro, no habrá ningún problema
fuente
Para desarrollar la respuesta de @Caumons:
Ahora eche un vistazo a esta solución.
Ahora probamos la aplicación:
Y aqui esta el resultado :
Ahora puede agregar fácilmente nuevos campos a la clase padre sin tener que preocuparse de que se rompan los códigos de sus hijos;
fuente