JS++ | Upcasting y Downcasting

Ahora que entendemos tanto la subtipificación como el polimorfismo estático frente al dinámico, podemos aprender sobre el upcasting y el downcasting.

Upcasting y downcasting se basan en relaciones de tipo. En otras palabras, si tiene datos de tipo ‘Animal’, puede «bajarlos» a su subtipo ‘Perro’. Por el contrario, si tiene datos de tipo ‘Perro’, puede «elevarlos» a su supertipo ‘Animal’. Sin embargo, no puede convertir datos de ningún tipo a ‘int’ porque no existe una relación de tipo entre ‘int’ y ‘Animal’ o ‘Dog’.

Dado que ahora estamos equipados con una comprensión del polimorfismo en tiempo de compilación versus el tiempo de ejecución, y por qué y cómo el compilador resolvió el método ‘renderizar’ cuando el tipo de datos se especificó como ‘Animal’, restauremos nuestro código main.jspp:

import Animals;

Animal cat1 = new Cat("Kitty");
cat1.render();
Animal cat2 = new Cat("Kat");
cat2.render();
Animal dog = new Dog("Fido");
dog.render();
Animal panda = new Panda();
panda.render();
Animal rhino = new Rhino();
rhino.render();

Como recordará, este es el código que representó a todos nuestros animales, pero ya no tenemos los nombres de los animales al pasar el mouse sobre ellos. Una forma de remediar esto es con un abatimiento:

import Animals;

Animal cat1 = new Cat("Kitty");
((Cat) cat1).render();
Animal cat2 = new Cat("Kat");
((Cat) cat2).render();
Animal dog = new Dog("Fido");
((Dog) dog).render();
Animal panda = new Panda();
panda.render();
Animal rhino = new Rhino();
rhino.render();

La sintaxis para una conversión de tipo es:

(type) expression

Por ejemplo:

(int) 100

La razón por la que hay paréntesis adicionales en nuestro código main.jspp revisado es porque queremos que la conversión de tipo tenga prioridad para que la conversión ocurra antes de que se llame al método ‘render’. Consulte la tabla de precedencia de operadores de JS++ para obtener más detalles.

Si compila y ejecuta el código ahora, debería ver que los gatos y los perros vuelven a mostrar sus nombres cuando pasa el mouse sobre su ícono.

Para ilustrar el upcasting, también podemos convertir uno de nuestros gatos en el tipo ‘Animal’. Llamar al método ‘render’ en este gato significará que usa el método render() de la clase ‘Animal’ que no incluirá el nombre:

import Animals;

Animal cat1 = new Cat("Kitty");
((Cat) cat1).render();
Cat cat2 = new Cat("Kat");
((Animal) cat2).render();
Animal dog = new Dog("Fido");
((Dog) dog).render();
Animal panda = new Panda();
panda.render();
Animal rhino = new Rhino();
rhino.render();

Tenga en cuenta que cambié el tipo de ‘cat2’ de nuevo a ‘Cat’ para ilustrar el upcasting. A partir de ahí, elevo ‘cat2’ a ‘Animal’. Si compila el código ahora, notará que el primer gato («Kitty») tiene su nombre que se muestra al pasar el mouse, pero el segundo gato («Kat») no tiene el mismo comportamiento.

Si bien pudimos resolver el método de ‘renderización’ correcto mediante conversiones, esta no es la forma más elegante de resolver el método. Por ejemplo, si tuviéramos una array de objetos ‘Animal’, nuestro bucle estaría anidado con declaraciones ‘if’ que realizan comprobaciones de ‘instancia de’ y conversiones de tipos posteriores. Esto no es ideal y conduce a un código difícil de leer. Hay una forma más elegante: métodos virtuales.

Publicación traducida automáticamente

Artículo escrito por RogerPoon y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *