En Java, el mecanismo de enlace dinámico (dynamic binding) determina qué método será llamado en el momento de la ejecución (runtime), y no en el momento de la compilación. La principal diferencia con el enlace estático (static binding) es que métodos como private, static, final y los métodos que no son sobreescritos en tiempo de ejecución se vinculan estáticamente (el enlace ocurre en el momento de la compilación), mientras que los métodos de instancia normales (incluyendo los sobreescritos) se vinculan dinámicamente. Esto hace posible el polimorfismo.
Ejemplo:
class Animal { void makeSound() { System.out.println("Algún sonido"); } } class Dog extends Animal { void makeSound() { System.out.println("Guau"); } } public class Test { public static void main(String[] args) { Animal a = new Dog(); a.makeSound(); // Imprimirá: Guau (enlace dinámico) } }
Aquí el método makeSound() se vincula dinámicamente; la JVM determina qué variante llamar solo durante la ejecución.
Pregunta: "Si declaras una variable del tipo de una interfaz o una clase abstracta y le asignas una instancia de una clase hija, ¿qué método será llamado al acceder al método sobreescrito? ¿Cómo lo determina el compilador?"
Error común: muchos piensan que se llama al método según el tipo de referencia en el momento de la compilación, pero esto lo hace la JVM en el momento de la ejecución.
Respuesta correcta: La JVM utiliza el tipo del objeto real para llamar al método (enlace dinámico), y no el tipo de referencia.
Shape s = new Circle(); s.draw(); // se llamará a draw() de Circle, no de Shape
Historia
En un gran proyecto bancario, un desarrollador sobreescribió los métodos toString() y equals(), pensando que si declaraba una variable a través de la interfaz, se llamaría al método de la interfaz. Esto provocó que la comparación de objetos fuera incorrecta — se comparaban referencias, no valores, lo que llevó a una lógica errónea al comparar clientes en busca de duplicados.
Historia
En un proyecto de comercio electrónico, un desarrollador creó una clase base Product y una clase derivada ElectronicProduct. En un array Product[] se guardaron objetos de ambos tipos. Al imprimir un producto a través de un método sobreescrito en ElectronicProduct, solo se mostraba la información de la clase base, ¡porque se llamó a un método estático! El error fue notado antes de la publicación.
Historia
En un proyecto de modelado de transporte se utilizó el patrón Factory. El desarrollador no se dio cuenta de que estaba trabajando con campos y no con métodos: acceder a un campo de la clase derivada devolvía el valor de la clase base y no el sobreescrito, ¡ya que los campos no son polimorfos! El sistema calculaba incorrectamente las rutas, mostrando a todos los objetos el tipo "Transport".