ProgramaciónDesarrollador Backend

Explique cómo funciona el orden de resolución de sobrecarga de métodos (method resolution order) en la herencia en Java, y qué trampas pueden surgir.

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

En Java, la resolución de sobrecarga (overloading) y sobrescritura (overriding) de métodos se lleva a cabo según ciertas reglas. En la sobrecarga (overloading), el compilador elige el método más adecuado entre todas las versiones en tiempo de compilación, según el tipo de argumentos en el lugar de la llamada.

Puntos importantes:

  • Cuando hay métodos sobrecargados en todas las clases y superclases, primero se buscan las coincidencias más altas en la clase actual, y luego en las superclases.
  • La elección del método se realiza en tiempo de compilación, no en tiempo de ejecución.
  • Las conversiones de tipo (widening, autoboxing, varargs) se aplican cuando es necesario.

Ejemplo:

class Super { void print(Number n) { System.out.println("Super Number"); } } class Sub extends Super { void print(Integer i) { System.out.println("Sub Integer"); } } ... Sub s = new Sub(); s.print(5); // Sub Integer s.print(5.0); // Super Number

Aquí, print(Integer) se llamará para el argumento de tipo Integer, y para el tipo Double, se llamará al método de la clase padre.

Pregunta capciosa.

Si en el heredero se sobrescribe (override) y se sobrecarga (overload) un método, ¿cuál de ellos se llamará en el polimorfismo?

Respuesta: En el polimorfismo, siempre se elige la versión del método basada en el tipo real del objeto para los métodos sobrescritos (overriding). Para los métodos sobrecargados, la elección se realiza en tiempo de compilación según el tipo de referencia.

class A { void test(Number n) { System.out.println("A:Number"); } } class B extends A { void test(Integer n) { System.out.println("B:Integer"); } @Override void test(Number n) { System.out.println("B:Number"); } } ... A obj = new B(); obj.test(1); // Llamará a B:Number, a pesar de que existe test(Integer)

Ejemplos de errores reales debido al desconocimiento de los matices del tema.


Historia

Un desarrollador agregó una versión sobrecargada del método en la subclase, esperando que se llamara para todos los herederos. En producción quedó claro que la llamada a través de la referencia de la clase padre llevaba a elegir el método según el tipo de referencia, no según el objeto. Como resultado, la lógica necesaria no se ejecutaba.


Historia

En un gran proyecto, se sobrecargó erróneamente el método equals(Object) con la firma equals(MyClass obj), pensando que sustituiría el equals estándar. Al comparar en colecciones HashSet, se utilizaba el equals(Object) por defecto, lo que llevaba a una discrepancia de lógica y pérdida de datos.


Historia

Al agregar una nueva versión del método con varargs en la jerarquía de clases, parecía que la versión correcta se llamaría para los arrays. Sin embargo, al pasar un array de forma explícita, el compilador eligió la sobrecarga incorrecta, por lo que el procesamiento no funcionaba correctamente y el error permaneció sin ser detectado durante mucho tiempo.