Consideremos un ejemplo del mundo real:
public class Dog extends Animal
Todos los perros son animales, pero no todos los animales son perros. Por lo tanto...
public class Cat extends Animal
Lanzar un animal a un perro solo se puede realizar si el animal en cuestión es realmente un perro. De lo contrario, forzaría al Universo a inferir propiedades únicas a un perro (moviendo la cola, ladrando, etc.) hacia un Animal. Ese animal bien podría ser un gato con propiedades únicas (ronroneo, régimen riguroso de autolimpieza, etc.). Si el lanzamiento no es posible, se lanza una ClassCastException en el tiempo de ejecución.
Nadie quiere un perro que ronronee.
((M) k) .getClass() da K. ¿Por qué es esto? ¡Fue lanzado a la M más general!
Has lanzado k a M, pero todas las clases tienen un método getClass(). La clase de k siempre es K, independientemente de a qué referencia le hagas o no M. Si lanzas un perro a un animal y le preguntas qué animal es, todavía responderá que es un perro.
De hecho, la conversión a una superclase es redundante. Un Perro ya es un Animal y tiene todos los métodos de un Animal además del propio. Muchas herramientas de Análisis de Código, como FindBugs, le notificarán de conversiones redundantes para que pueda eliminarlas.
Supongamos que tengo un método DOIT() implementado en ambos M y K. ejecución
((M) k) .doIt();
da doIt de M o K()?
K doIt() por las mismas razones que las anteriores. El yeso opera en la referencia; no transforma un objeto en un tipo diferente.
¿Puede dar un ejemplo de cuando la fundición (= perro (perro) myAnimal perro) tiene sentido?
Sure can. Imagine un método que recibe una lista de animales para su procesamiento. Todos los perros deben ser llevados a caminar, y todos los gatos deben jugarse con un juguete en forma de pájaro. Para hacer esto, llamamos al método takeForWalk()
que solo existe en Dog, o al método play()
que solo existe en Cat.
public void amuseAnimals(List<Animal> animals) {
for (Animal animal : animals) {
if (animal instanceof Dog) {
Dog doggy = (Dog)animal;
doggy.takeForWalk(new WalkingRoute());
} else if (animal instanceof Cat) {
Cat puss = (Cat)animal;
puss.play(new BirdShapedToy());
}
}
}
¿Por qué ejecuta K doIt? Le digo que se refiera a este objeto como M, no como K. Si el compilador lo trata como M, debería ejecutar los métodos de M. Estoy aún más confundido ahora. ¿Puedes dar un ejemplo de cuando lanzaste (Dog doggy = (Dog) myAnimal) tiene sentido? – ooboo
"Si el compilador lo trata como una M, debería ejecutar los métodos de M.". El compilador lo trata como una M por razones de tipeo. Si K no se puede escribir como M, se emite una ClassCastException. Se usan los métodos de K porque como una subclase K puede anular los métodos de M. Esto es lo que separa una K de una M y es una parte intrínseca de la Orientación del objeto. – banjollity