2016-05-19 28 views
11

Betrachten Sie das folgende Beispiel-Code:Java Überlastung: Referenz nennen mehrdeutig

public class TestClass { 

    public void doSth(String str, String l, Object... objects) { 
     System.out.println("A"); 
    } 

    public void doSth(String str, Object... objects) { 
     System.out.println("B"); 
    } 

} 

Wenn ich jetzt new TestClass().doSth("foo", "bar") nenne ich das erwartete Ergebnis A bekommen. Aber wenn ich die Methode Signatur des ersten Verfahrens ändern, indem chaging die Parameter l auf eine primitive Art:

public class TestClass { 

    public void doSth(String str, long l, Object... objects) { 
     System.out.println("A"); 
    } 

    public void doSth(String str, Object... objects) { 
     System.out.println("B"); 
    } 

} 

Aufruf new TestClass().doSth("foo", 2L) werden ergeben einen reference to call ambiguous Kompilierung Fehler.

Ich dachte schon seit einiger Zeit darüber nach und konsultierte auch this stackoverflow question, aber ich konnte nicht verstehen, warum das passiert. Meiner Meinung nach ist die doSth("foo", 2L) spezifischer für die doSth(String string, long l, Object... obj) Signatur und sollte dem Compiler erlauben, ebenfalls zu dieser Schlussfolgerung zu kommen.

+0

Offensichtlich können Primitive auch Objekte sein? –

+0

@blahfunk, ja, sie können verpackt werden – Andrew

+0

Die einzige Erklärung, die in den Sinn kommt, ist [Autoboxing] (https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html), aber das sollte sein ein Konvertierungsschritt "weiter" entfernt als die primitive Version der Methode. – Turing85

Antwort

5

In diesem Fall verursacht Auto-Boxen Sie Trauer. Ironischerweise haben Sie vorher Recht - die "lange" Version wäre leicht auszusuchen.

Grundsätzlich weiß der Compiler, dass er aus Ihrem Wert ein Long erstellen kann, das natürlich ein Objekt ist. Es ist also immer noch verwirrt, da entweder die Long- oder Long-Version verwendet werden kann. Ist einer "besser" als der andere? Vielleicht, aber es ist eine ziemlich feine Linie.

+1

Nun, [Phase 1] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-15. html # jls-15.12.2) in der JLS spezifiziert explizit * führt eine Überladungsauflösung durch, ohne eine Box- oder Unboxing-Umwandlung zu erlauben *. In dieser Phase wird kein Autoboxing durchgeführt. Es sieht aus wie 'doSth (String str, long l, Object ... Objekte)' sollte in dieser Phase gewählt werden. Fehle ich etwas? – Tunaki

+0

Das ist lustig. Warum verursacht das keinen Schaden, wenn es nur einen Parameter gibt, d. H. "DoSth (long l)" und "doSth (Object o)"? – Turing85

+3

@Tunaki Phase 1 und 2 schließen auch variable Arity-Methoden aus, so dass keine der OP-Methoden bis Phase 3 berücksichtigt wird. Seltsamerweise wird 'doSth (" foo ", 2L, null)' kompilieren wegen der kursiv geschriebenen Note unter der ersten Kugel (in Ihrem Link). – Radiodef

1

In diesem Zustand kann ich nur meine Beobachtung melden, nicht die genaue Argumentation, WARUM Java sich verhält, wie es tut.

Erstens, die Änderung der Methoden

void doSth(long l) {...} 
void doSth(Object o) {...} 

wird das Problem beseitigen, das heißt doSth(2L); wird das erwartete Ergebnis ergeben.

einen Schritt weiter, Ändern des Verfahrensparameters

void doSth(long... ls) {...} 
void doSth(Object... os) {...} 

zusammen mit dem Aufruf doSth(2l); ergibt den gleichen Übersetzungsfehler varargs wie von OP berichtet.

Mein Vorschlag in diesem Stadium ist, dass die Einbeziehung des Parameters in ein Array zusammen mit Autoboxing die Verwüstung verursacht. Mein Wissen über die JLS ist nicht fest genug, um dies richtig zu erklären.