Frage

Ich habe bemerkt, dass heute Auto-Boxen manchmal Mehrdeutigkeit in -Methodenüberladung Auflösung verursachen können. Das einfachste Beispiel scheint dies zu sein:

public class Test {
    static void f(Object a, boolean b) {}
    static void f(Object a, Object b) {}

    static void m(int a, boolean b) { f(a,b); }
}

Wenn kompiliert, es verursacht den folgenden Fehler:

Test.java:5: reference to f is ambiguous, both method
    f(java.lang.Object,boolean) in Test and method
    f(java.lang.Object,java.lang.Object) in Test match

static void m(int a, boolean b) { f(a, b); }
                                  ^

Das Update auf diesen Fehler ist trivial: nur explizite Auto-Boxen verwenden:

static void m(int a, boolean b) { f((Object)a, b); }

Welche korrekt die erste Überlastung ruft, wie erwartet.

Warum also nicht die Überladungsauflösung? Warum nicht der Compiler Auto-Feld das erste Argument, und akzeptieren normalerweise das zweite Argument? Warum habe ich ausdrücklich Auto-Boxen anfordern?

War es hilfreich?

Lösung

Wenn Sie das erste Argument werfen sich auf Objekt, wird der Compiler die Methode anzupassen, ohne Autoboxing (JLS3 15.12.2):

  

Die erste Phase (§15.12.2.2) führt   Überlastungs Auflösung ohne ermöglicht   Boxen oder Unboxing Umwandlung oder   Verwendung variabler arity Verfahren   Aufruf. Wenn keine anwendbare Methode ist   In dieser Phase fand dann   Verarbeitung weiter zu dem zweiten   Phase.

Wenn Sie es nicht explizit werfen, wird es in die zweite Phase gehen zu versuchen, eine passende Methode zu finden, so dass Autoboxing, und dann ist es in der Tat nicht eindeutig, weil Ihr zweites Argument kann durch boolean oder Objekt angepasst werden.

  

Die zweite Phase (§15.12.2.3) führt   Überladungsauflösung beim Erlauben   Boxen und Unboxing, aber immer noch   schließt die Verwendung von variablen arity   Methodenaufruf.

Warum, in der zweiten Phase, nicht der Compiler die zweite Methode wählen, da kein Autoboxing des boolean Argument ist notwendig? Denn nachdem er die beiden passenden Methoden gefunden hat, wird nur Subtyp Umwandlung verwendet, um die am meisten spezifische Methode der beiden, unabhängig von Boxen oder Unboxing zu bestimmen, die stattfand, sie in erster Linie entsprechen (§15.12.2.5).

Außerdem: der Compiler kann nicht immer die spezifische Methode wählen, basierend auf der Anzahl von Auto (un) Box benötigt. Es kann immer noch in Zweifelsfällen führen. Zum Beispiel ist dies noch nicht eindeutig:

public class Test {
    static void f(Object a, boolean b) {}
    static void f(int a, Object b) {}

    static void m(int a, boolean b) { f(a, b); } // ambiguous
}

Denken Sie daran, dass der Algorithmus ein Anpassungsverfahren für die Auswahl (Kompilierung-Schritt 2) festgelegt ist und in der JLS beschrieben. Sobald in Phase 2 gibt es keinen selektiven Autoboxing oder Unboxing. Der Compiler findet alle die Methoden, die zugänglich (in diesen Fällen beiden Methoden) und anwendbar (wieder die beiden Methoden), und nur wählt dann die spezifischste ohne Boxen / Unboxing zu suchen, das ist zweideutig hier.

Andere Tipps

Der Compiler hat Auto-Feld das erste Argument. Nachdem das erledigt war, dann ist es das zweite Argument, das nicht eindeutig ist, da es entweder als boolean oder Objekt zu sehen.

Diese Seite die Regeln für Autoboxing erklärt und Auswahlverfahren, das aufzurufen. Der Compiler versucht zunächst ein Verfahren zur Auswahl von ohne jede Autoboxing überhaupt mit , weil Boxen und Unboxing carry Leistungseinbußen. Wenn keine Methode kann, ohne auf Boxen ausgewählt werden, wie in diesem Fall, dann Box auf dem Tisch ist für alle Argumente zu dieser Methode.

Wenn Sie sagen, f (a, b ), der Compiler ist verwirrt darüber, welche Funktion sollte es verweisen.

Das liegt daran, a ist ein int , aber das Argument erwartet in f ist ein Objekt. So entscheidet der Compilers konvertieren ein zu einem Objekt. Nun das Problem ist, dass, wenn a kann in ein Objekt umgewandelt wird, kann so sein, b .

Das bedeutet, dass der Funktionsaufruf, um entweder Definitionen verweisen kann. Dies macht den Anruf nicht eindeutig.

Wenn Sie konvertieren a zu einem Objekt manuell, der Compiler sieht einfach für die nächste Übereinstimmung und dann bezieht sich auf es.

  

Warum nicht der Compiler wählen die   Funktion, die durch „tun erreicht werden kann   eine möglichst geringe Anzahl von   Boxen / Unboxing-Conversions "?

Sehen Sie im folgenden Fall:

f(boolean a, Object b)
f(Object a , boolean b)

Wenn wir wie f nennen (boolean a, boolean b) , welche Funktion sollte es wählen? Es mehrdeutig richtig? In ähnlicher Weise wird sich dies komplexes, wenn viele Argumente vorhanden sind. So dass der Compiler wählte stattdessen eine Warnung zu geben.

Da gibt es keine Möglichkeit zu wissen, welche eine der Funktionen der Programmierer wirklich beabsichtigt zu nennen, der Compiler einen Fehler gibt.

  

So tat, warum die Überladungsauflösung   Scheitern? Warum hat die Compiler Auto-Box   das erste Argument, und akzeptiert die   zweites Argument der Regel? Warum habe ich   haben Auto-Boxen beantragen   explizit?

Es hat nicht das zweite Argument akzeptieren normalerweise. Denken Sie daran, dass „boolean“ kann auch zu einem Objekt verpackt werden. Sie könnten sich ausdrücklich boolean Argument geworfen haben und auf Objekt, und es würde gearbeitet haben.

Siehe http: //java.sun. com / docs / Bücher / JLS / third_edition / html / expressions.html # 20448

Die Besetzung hilft, weil dann keine Boxen benötigt, um die Methode zu finden, anzurufen. Ohne die Besetzung ist der zweite Versuch Boxen zu ermöglichen, und dann kann auch die boolean eingerahmt werden.

Es ist besser, klar und verständlich Spezifikationen muss sagen, was passieren wird, als die Menschen erraten zu machen.

Die Java-Compiler lösen ladenen Methoden und Konstrukteuren in Phasen. In der ersten Phase [§15.12.2.2], identifiziert es anwendbare Methoden durch Subtypisierung [§4.10]. In diesem Beispiel ist keine Methode anwendbar, weil int kein Subtyp des Objekts ist.

In der zweiten Phase [§15.12.2.3] identifiziert der Compiler anwendbares Verfahren nach Methodenaufruf conversion [§5.3], die eine Kombination von Autoboxing und Subtypisierung ist. Das int-Argument kann in eine Ganzzahl umgewandelt werden, die ein Subtyp von Objekt ist, für beide Überlastungen. Das boolean Argument braucht keine Konvertierung für die erste Überlast und kann auf Boolean, ein Subtyp des Objekts umgewandelt werden, für die zweiten. Daher sind beide Verfahren anwendbar in der zweiten Phase.

Seit mehr als eine Methode anwendbar ist, muss der Compiler bestimmen, welche am meisten spezifisch ist [§15.12.2.5]. Er vergleicht die Parametertypen, nicht die Argumenttypen, und es ist AutoBox sie nicht. Objekt und boolean sind nicht verwandte Arten, so dass sie gleich genau betrachtet. Keine Methode ist präziser als die andere, so der Aufruf der Methode ist nicht eindeutig.

Eine Möglichkeit, die Mehrdeutigkeit aufzulösen wäre, die boolean Parameter ändern Boolean zu geben, die ein Subtyp von Object ist. Die erste Überlast würde immer genauer sein (wenn zutreffend) als die zweite.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top