Überlastungsauflösung, welche Methode aufgerufen wird

8

Nehmen wir an, ich habe eine ComponentBaseKlasse, die ein Kind ObjectContextDecoratorund ein Enkel von ist 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) {
       //...
    }
}

Die setMethoden auf ObjectContextDecoratorund ObjectContextsind sehr ähnlich. Betrachten Sie diesen Beispielcode:

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

Die Signaturen beider Methoden passen zu der, die korrekt aufgerufen wird. Ich kann die Signaturen der Methoden nicht ändern, da dies nicht mein Code ist.

Woher weiß der Compiler, welche Methode ich aufrufen wollte?

Ich weiß, dass Sie in der IDE angeben können, welche Methode Sie tatsächlich aufrufen möchten, aber in dieser Situation verwende ich einen Klassenlader, um eine Klasse zu laden, deren Methode den Beispielcode enthält.

Gabriel Robaina
quelle
Sie sind ähnlich, aber unterschiedlich - es gibt keine Mehrdeutigkeit, wenn Sie vorbeikommen String, String, boolean. Die spezifischste Methode wird aufgerufen. Das ist alles in der JLS.
Dave Newton
Welches ist das spezifischste? Nach meinem Verständnis sind beide gleich spezifisch.
Gabriel Robaina
3
Bitte beachten Sie JLS§15.12.2. Kompilierungszeit Schritt 2: Bestimmen Sie die Methodensignatur, in der die Regeln hierfür ausführlich beschrieben werden. Insbesondere 15.12.2.5. Auswahl der spezifischsten Methode .
Zabuzard
1
Das heißt, selbst wenn der Compiler und die IDEs herausfinden können, welche aufgerufen werden, sind die Regeln komplex und es ist für einen Humarn ziemlich schwierig, dies herauszufinden. Also würde ich eine der Methoden umbenennen, um es offensichtlich zu machen.
JB Nizet
2
Nebenbei bemerkt, Java-Strings verwenden nur ein doppeltes Anführungszeichen (wie "this")
OscarRyz

Antworten:

2

Woher weiß der Compiler, welche Methode ich aufrufen wollte?

Es prüft nach den Argumenten und bestimmt, welches spezifischer ist, gemäß den in JLS §15.2 beschriebenen Regeln

In Ihrem Fall ist der Anruf:

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

die Argumente String, String,boolean

Welches der ersten Klasse entspricht ( Parameternamen wurden der Kürze halber geändert )

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

Die zweite Klasse wird nicht aufgerufen, da der dritte Parameter ein Object:

public class ObjectContextDecorator extends ObjectContext {

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

und während der boolesche Wert trueübereinstimmen kann, wenn er autoboxed ist, ist der erste spezifischer. Die hier geltende Regel lautet:

In der ersten Phase (§15.12.2.2) wird eine Überlastungsauflösung durchgeführt, ohne dass eine Boxing- oder Unboxing-Konvertierung zulässig ist

Wenn Sie beispielsweise den Objekt-Wrapper Booleanin der Signatur verwenden:

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

Dann stimmen beide überein, und der Compiler teilt Ihnen die folgende Meldung mit:

> 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

In Ihrem Beispiel ist dies jedoch nicht der Fall.

OscarRyz
quelle
4

Dies alles wird in den JLS §15.2 Methodenaufrufausdrücken erläutert . Hier erfahren Sie alles darüber, wie die richtige Methode zum Aufrufen ausgewählt wird. Und beachten Sie, dass dies nicht immer erfolgreich ist.

In Ihrem speziellen Fall handelt es sich bei den beiden Methoden um gegenseitige Überladungen. Daher gilt §15.2.2 "Kompilierungszeit Schritt 2: Bestimmen der Methodensignatur" - welche aufzurufende Überlastung zur Kompilierungszeit bestimmt wird. Dieser Schritt ist weiter in 3 Phasen unterteilt.

In der ersten Phase (§15.12.2.2) wird eine Überlastungsauflösung durchgeführt, ohne dass eine Boxing- oder Unboxing-Konvertierung oder die Verwendung eines Methodenaufrufs mit variabler Arität zulässig ist. Wenn während dieser Phase keine anwendbare Methode gefunden wird, wird die Verarbeitung zur zweiten Phase fortgesetzt.

In der ersten Phase versucht der Compiler, geeignete Methoden zu finden, ohne Box-Konvertierungen zuzulassen. In Ihrem Fall ist zum Aufrufen der Überlastung, die eine benötigt Object, eine Boxkonvertierung erforderlich, um die boolean truein den Typ zu konvertieren Object, damit in der ersten Phase keine Überlastung ausgewählt wird.

Wird keine durch strengen Aufruf anwendbare Methode gefunden, wird die Suche nach anwendbaren Methoden mit Phase 2 (§15.12.2.3) fortgesetzt.

Andernfalls wird die spezifischste Methode (§15.12.2.5) unter den Methoden ausgewählt, die durch strikten Aufruf anwendbar sind.

Nun, wir haben genau eine Methode gefunden, also werden wir nur diese Methode wählen. Es gibt keine Mehrdeutigkeit.

Kehrmaschine
quelle