El polimorfismo estático es polimorfismo que ocurre en tiempo de compilación, y el polimorfismo dinámico es polimorfismo que ocurre en tiempo de ejecución (durante la ejecución de la aplicación).
Un aspecto del polimorfismo estático es la unión temprana. En el enlace temprano, el método específico para llamar se resuelve en tiempo de compilación. (JS++ también admite el enlace tardío a través de funciones virtuales que veremos más adelante). El enlace temprano es más rápido porque no hay sobrecarga de tiempo de ejecución. El enlace anticipado es el comportamiento predeterminado y más común para JS++. Si desea un enlace en tiempo de ejecución, debe especificarlo explícitamente. Nuevamente, cubriremos el enlace tardío en una sección posterior.
En nuestro código, especificamos el modificador ‘overwrite’ para nuestros métodos render() de clase ‘Cat’ y ‘Dog’. Este método habilitó la ocultación, pero especifica el enlace anticipado . Aquí está el código de Cat.jspp:
overwrite void render() { $element.attr("title", _name); super.render(); }
Más tarde, cuando cambiamos el tipo de nuestros gatos a ‘Animal’ en main.jspp, el tipo de nuestros gatos cambió de ‘Gato’ a ‘Animal’. Podría decir: «Sí, pero no obstante creamos una instancia de nuestros objetos gato usando la clase ‘Gato'». Si bien esto es cierto, también significa que nuestras variables cat ahora pueden aceptar datos de cualquier tipo que satisfagan la restricción ‘Animal’ (incluido ‘Animal’ en sí mismo si no especificamos un constructor protegido en ‘Animal’). Por ejemplo, esto ahora se convierte en un código completamente aceptable:
import System; import Animals; Animal cat1 = new Cat("Kitty"); if (Math.random(1, 10) > 3) { cat1 = new Dog("Fido"); } cat1.render();
Ignora la importación del ‘Sistema’, pero importa la función Math.random(). Se utiliza para ilustrar el ejemplo. También mantuve a propósito el nombre de nuestra variable como ‘cat1’ para ilustrar el punto. ‘cat1’ tiene el tipo ‘Animal’. Por lo tanto, todos los objetos de tipo ‘Animal’ se pueden asignar a ‘gato1’ (incluidos los objetos de tipo ‘Perro’).
Si realmente compila, ejecuta el código anterior y actualiza lo suficiente, notará que su «gato» a veces se representará como un perro.
Como puede observar, cuando tenemos un tipo ‘Animal’, los datos pueden ser ‘Gato’ en nuestro programa o también pueden convertirse aleatoriamente en ‘Perro’ según la generación de números aleatorios en tiempo de ejecución. Los números aleatorios no se generan en tiempo de compilación. Los números aleatorios se generan durante la ejecución de la aplicación (tiempo de ejecución). Por lo tanto, desde la perspectiva del compilador, si vamos a resolver el método ‘render’, lo resolveremos en el método ‘render’ del tipo especificado por el usuario, ‘Animal’, porque es el más correcto . Recuerde que en la subtipificación, todos los Gatos y Perros son Animales, pero no todos los Animales son Gatos y Perros.
Por lo tanto, esto debería ayudarlo a comprender el enlace temprano y el polimorfismo estático/en tiempo de compilación.
Aparte: tipos de datos como especificaciones
Los tipos de datos también son especificaciones. Estamos especificando lo que constituye un programa correcto . Por ejemplo, no especificaría una función ‘restar’ para aceptar dos parámetros de tipo ‘string’. En nuestro caso, si queríamos un gato, deberíamos haber especificado el tipo ‘Gato’ en lugar de generalizar a ‘Animal’. Si bien es deseable la capacidad de expresar algoritmos en términos más generales, es posible que no siempre sea correcta.
Técnicamente, el programa sigue siendo de tipo correcto . En ambos casos (‘Gato’ y ‘Perro’), tenemos un objeto de tipo ‘Animal’. Simplemente sucede que nuestro ‘Animal’ se llamó ‘cat1’, por lo que una posible solución para el código anterior puede ser cambiar el nombre de la variable a ‘animal’ o algo similar para expresar nuestra intención.
La otra solución potencial, si queremos que ‘gato1’ sea siempre un gato, es restringir el tipo de datos a ‘Gato’ en lugar de ‘Animal’. Si hace esto, obtendrá un error de compilación porque ‘Perro’ no es un subtipo de ‘Gato’:
JSPPE5000: Cannot convert `Animals.Dog' to `Animals.Cat' at line 6 char 8 at main.jspp
En el polimorfismo en tiempo de ejecución, el tipo se determina en tiempo de ejecución. Por ejemplo, podemos usar el operador ‘instancia de’ para verificar el tipo de datos de tiempo de ejecución. Cambie su archivo main.jspp y observe el resultado:
import System; import Animals; external $; Animal animal = new Cat("Kitty"); if (Math.random(1, 10) > 3) { animal = new Dog("Fido"); } if (animal instanceof Cat) { $("#content").text("We have a CAT."); } else { $("#content").text("We have a DOG."); }
Continúe actualizando y debería ver que a veces tenemos una instancia de ‘Gato’ y otras veces tenemos una instancia de ‘Perro’. Sin embargo, los tipos (y los mensajes resultantes) se determinan en tiempo de ejecución, no en tiempo de compilación.