Cuando defines métodos sobrecargados. ¿conoces cómo el compilador sabe que metodo llamar ?, ¿puedes adivinar cuál será la salida del siguiente código?

class Overloaded {
   
    public static void aMethod(int val) {
        System.out.println("int");
    }
   
    public static void aMethod(short val) {
        System.out.println("short");
    }
   
    public static void aMethod(Object val) {
        System.out.println("object");
    }
   
    public static void aMethod(String val) {
        System.out.println("String");
    }

    public static void main(String[] args) {
        byte b = 9;
        aMethod(b); // first call
        aMethod(9); // second call
        Integer i = 9;
        aMethod(i); // third call
        aMethod("9"); // fourth call
    }
}

Esto imprime

short
int
object
String

Así es como el compilador resuelve esas llamadas.

  • En la primera llamada a aMethod, es la sentencia aMethod(b) donde la variable b es un tipo byte. No hay una definición de un método que reciba un byte como argumento. El tipo más cercano en tamaño es short y no int, entonces el compilador resuelve la llamada aMethod(b) con la definición aMethod(short val).
  • En la segunda llamada a aMethod, es la sentencia aMethod(9). La constante con valor 9 es de tipo int. El que más se acerca el el método aMethod(int), por lo tanto el compilador resuelve la llamada aMethod(9) con la definición aMethod(int val).
  • La tercera llamada es de aMethod(i), donde la variable i es de tipo Integer. No hay un método que tome un Integer como argumento, pero el más cercano es el método aMethod(Object val), por lo tanto lo llama. ¿Por que no llama a aMethod(int val)?, el compilador por defecto hace implícitamente un upcast, no un downcast. Por lo tanto aMethod(int val) no es considerado.
  • Por último la llamada al método aMethod(“9”) es la más obvia, pasa un String como argumento y hay una definición exacta para este, por lo tanto la ejecuta.

Este proceso del compilador tratando de resolver la llamada al método dado varios métodos sobrecargados es conocido como overloading resolution. Para resolverlos primero el compilador mira cuales coinciden exactamente con las definiciones tomando en cuenta tipo y número de parámetros. Si no puede encontrar una coincidencia exacta, busca la coincidencia más cercana usando upcasting. Si no puede encontrar ninguna coincidencia entonces el compilador lanzará un error.
Aquí un ejemplo:

class OverloadingError {
   
    public static void aMethod(byte val) {
        System.out.println("byte");
    }
   
    public static void aMethod(short val) {
        System.out.println("short");
    }
   
    public static void main(String[] args) {
        aMethod(9);
    }
}

Aquí el error.

OverloadingError.java:6: error: no suitable method found for aMethod(int)
aMethod(9);
method OverloadingError.aMethod(byte) is not applicable
(argument mismatch; possible lossy conversion from int to byte)
method OverloadingError.aMethod(short) is not applicable
(argument mismatch; possible lossy conversion from int to short)
1 error

El tipo de la constante 9 es un int, pero no hay una coincidencia. Como puedes observar en la definición de overloading resolution, el compilador puede hacer upcast (ejemplo de byte a int) para encontrar el más cercano, pero nunca un downcast (ejemplo de int a byte). Por lo que el compilador no encuentra una coincidencia cercana y lanza un error.

Ahora, ¿Qué sucede si el compilador encuentra más de una coincidencia?

class AmbiguousOverload {
   
    public static void aMethod(long val1, int val2) {
        System.out.println("long, int");
    }
   
    public static void aMethod(int val1, long val2) {
        System.out.println("int, long");
    }
   
    public static void main(String[] args) {
        aMethod(9, 10);
    }
}

Here is the compiler error:
AmbiguousOverload.java:11: error: reference to aMethod is ambiguous
aMethod(9, 10);
^
both method aMethod(long,int) in AmbiguousOverload and method aMethod(int,long) in
AmbiguousOverload match
1 error

La constante 9 y 10 son enteros (int), y hay dos definiciones para aMethod: una es aMethod(long val1, int val2) y el otro es aMethod(int val1, long val2), pero no hay una definición exacta de aMethod(int val1, int val2), aunado a esto un int puede ser implícitamente convertido a long y a Integer, entonces ¿Cuál método debe escoger el compilador?, bueno a esto se le llama ambigüedad y el compilador lo sabe … y te lo hará saber.