Resolución de sobrecarga, qué método se llama

8

Supongamos que tengo una ComponentBaseclase, de quien es hijo ObjectContextDecoratory nieto ObjectContext.

public class ComponentBase extends ObjectContextDecorator {
}

public class ObjectContextDecorator extends ObjectContext {

    public void set(String objectTypePath, String characteristicName, Object value) {
        //...
    }
}

public class ObjectContext {
    public void set(String characteristicName, Object value, boolean forced) {
       //...
    }
}

Los setmétodos en ObjectContextDecoratory ObjectContextson muy similares. Considere este código de muestra:

ComponentBase base = new ComponentBase();
base.set(""OTM4E_EFFLEVEL"", ""IE1 / STD"", true);

Las firmas de ambos métodos se ajustan a la que se llama correctamente. No puedo cambiar las firmas de los métodos ya que no es mi código.

¿Cómo sabe el compilador a qué método pretendía llamar?

Sé que en el IDE puedes señalar a qué método realmente quieres llamar, pero en esta situación, estoy usando un cargador de clases para cargar una clase que tiene un método que contiene el código de muestra.

Gabriel Robaina
fuente
Son similares, pero diferentes: no hay ambigüedad si pasas String, String, boolean. Se llamará al método más específico. Todo esto está en el JLS.
Dave Newton
¿Cuál es el más específico? A mi entender, ambos son igualmente específicos.
Gabriel Robaina
3
Consulte JLS§15.12.2. Tiempo de compilación Paso 2: Determine la firma del método donde se describen en detalle las reglas para esto. Especialmente 15.12.2.5. Elegir el método más específico .
Zabuzard
1
Dicho esto, incluso si el compilador y los IDE pueden descubrir cuál se llama, las reglas son complejas y es muy difícil para un humano descubrirlo. Así que cambiaría el nombre de uno de los métodos para hacerlo obvio.
JB Nizet
2
Nota al margen, las cadenas de Java usan solo una comilla doble (como "this")
OscarRyz

Respuestas:

2

¿Cómo sabe el compilador a qué método pretendía llamar?

Comprueba los argumentos y determina cuál es más específico siguiendo las reglas descritas. JLS §15.2

En su caso, la llamada:

base.set("OTM4E_EFFLEVEL", "IE1 / STD", true)

los argumentos son String, String,boolean

Que coincide con la primera clase (los nombres de los parámetros cambiaron por brevedad )

public class ObjectContext {
    public void set(String s, Object o, boolean b){
       //...
    }
}

La segunda clase no se invoca porque el tercer parámetro es un Object:

public class ObjectContextDecorator extends ObjectContext {

    public void set(String s, String ss, Object thisOneRightHere) {
        //...
    }
}

y aunque el valor booleano truepuede coincidir si está en caja automática, el primero es más específico. La regla que se aplica aquí es:

La primera fase (§15.12.2.2) realiza la resolución de sobrecarga sin permitir la conversión de unboxing o unboxing

Pero, por ejemplo, si usa el contenedor de objetos Booleanen la firma:

public class ObjectContext {
    public void set(String s, Object o, Boolean b){ //<-- third param changed from boolean to Boolean
       //...
    }
}

Luego ambos coincidirán, y el compilador le informará con el siguiente mensaje:

> A.java:25: error: reference to set is ambiguous
>     base.set("OTM4E_EFFLEVEL", "IE1 / STD", true);
>         ^   both method set(String,Object,Boolean) in ObjectContext and method set(String,String,Object) in ObjectContextDecorator match

Pero ese no es el caso en su ejemplo.

OscarRyz
fuente
4

Todo se explica en el JLS §15.2 expresiones de invocación del método . Le informa todo sobre cómo se elige el método correcto para llamar. Y tenga en cuenta que esto no siempre tiene éxito.

En su caso específico, los dos métodos son sobrecargas entre sí, por lo que se aplica el §15.2.2 "Paso 2 del tiempo de compilación: determinar la firma del método": qué sobrecarga para llamar se determina en el momento de la compilación. Este paso se divide en 3 fases.

La primera fase (§15.12.2.2) realiza la resolución de sobrecarga sin permitir la conversión de boxing o unboxing, o el uso de la invocación del método de arity variable. Si no se encuentra ningún método aplicable durante esta fase, el procesamiento continúa a la segunda fase.

En la primera fase, el compilador intenta encontrar métodos aplicables sin permitir conversiones de boxeo. En su caso, para llamar a la sobrecarga que toma una Object, se necesita una conversión de boxeo para convertirla boolean trueal tipo Object, de modo que la sobrecarga no se elija en la primera fase.

Si no se encuentra ningún método aplicable por invocación estricta, la búsqueda de métodos aplicables continúa con la fase 2 (§15.12.2.3).

De lo contrario, el método más específico (§15.12.2.5) se elige entre los métodos que son aplicables por invocación estricta.

Bueno, nosotros hemos encontrado exactamente un método, por lo que nos limitaremos a elegir ese método. No hay ambigüedad.

Barrendero
fuente