lanzamiento explícito de superclase a subclase

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 comstackción, pero en el tiempo de ejecución genera una ClassCastException . ¿Por qué el comstackdor no puede detectar este error?

Al usar un elenco básicamente le estás diciendo al comstackdor “créeme. Soy un profesional, sé lo que estoy haciendo y sé que aunque no puedes garantizarlo, te digo que esta variable animal es definitivamente va a ser un perro “.

Como el animal no es realmente un perro (es un animal, puedes hacer Animal animal = new Dog(); y sería un perro) el VM lanza una excepción en el tiempo de ejecución porque has violado esa confianza (le dijiste el comstackdor todo estaría bien y no lo es!)

El comstackdor es un poco más inteligente que simplemente aceptar ciegamente todo, si intentas lanzar objetos en diferentes jerarquías de herencia (por ejemplo, lanzar un Perro a una cadena), el comstackdor se lo devolverá porque sabe que posiblemente nunca funcionará.

Debido a que esencialmente está evitando que el comstackdor se queje, cada vez que realice un colado es importante verificar que no cause una ClassCastException utilizando instanceof en una sentencia if (o algo por el estilo).

Porque teóricamente Animal animal puede ser un perro:

 Animal animal = new Dog(); 

En general, downcasting no es una buena idea. Debes evitarlo. Si lo usa, es mejor que incluya un cheque:

 if (animal instanceof Dog) { Dog dog = (Dog) animal; } 

Para evitar este tipo de ClassCastException, si tiene:

 class A class B extends A 

Puede definir un constructor en B que tome un objeto de A. De esta manera podemos hacer el “molde”, por ejemplo:

 public B(A a) { super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A // If B class has more attributes, then you would initilize them here } 

Dog d = (Dog)Animal; //Compiles but fails at runtime

Aquí le estás diciendo al comstackdor “Créeme. Sé que realmente se está refiriendo a un objeto Dog ” aunque no lo es. Recuerde que el comstackdor se ve obligado a confiar en nosotros cuando hacemos un downcast .

El comstackdor solo conoce el tipo de referencia declarado. La JVM en tiempo de ejecución sabe qué es realmente el objeto.

Entonces, cuando la JVM en el tiempo de ejecución se da cuenta de que el Dog d está refiriendo realmente a un objeto Animal y no a un Dog , dice. Oye … mentiste al comstackdor y arrojó una gran ClassCastException .

Por lo tanto, si está realizando un downcasting, debe usar la prueba instanceof para evitar atornillar.

if (animal instanceof Dog) { Dog dog = (Dog) animal; }

Ahora surge una pregunta en nuestra mente. ¿Por qué demonios el comstackdor está permitiendo el downcast cuando eventualmente lanzará java.lang.ClassCastException ?

La respuesta es que todo lo que el comstackdor puede hacer es verificar que los dos tipos estén en el mismo árbol de herencia, por lo que dependiendo de cualquier código que haya aparecido antes del downcast, es posible que el animal sea ​​de tipo dog .

El comstackdor debe permitir cosas que posiblemente funcionen en tiempo de ejecución.

Considere el siguiente código snipet:

 public static void main(String[] args) { Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :) d.eat(); } private static Animal getMeAnAnimal() { Animal animal = new Dog(); return animal; } 

Sin embargo, si el comstackdor está seguro de que el molde no funcionaría, la comstackción fallará. IE Si intentas lanzar objetos en diferentes jerarquías de herencia

String s = (String)d; // ERROR : cannot cast for Dog to String

A diferencia del downcasting, el upcasting funciona implícitamente porque cuando edificas, implícitamente estás restringiendo el número de métodos que puedes invocar, como opuesto a downcasting, lo que implica que más tarde, podrías invocar un método más específico.

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 upcast anteriores funcionarán bien sin excepción, porque un perro IS-A Animal, un animal que puede hacer, un perro puede hacerlo. Pero no es verdad vica-versa.

El código genera un error de comstackción porque tu tipo de instancia es un Animal:

 Animal animal=new Animal(); 

Downcasting no está permitido en Java por varias razones. Mira aquí para más detalles.

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 polymorphism. Por lo tanto, cuando llame a d.method () la llamada tendrá éxito sin moldear, pero en caso de que el objeto no sea un perro, no habrá un problema