5

Ich versuche Methode Überlastung zu verstehen, und ich habe diese Methoden.Java-Methode Überlastung und varargs

public void method(int a){ 
    System.out.println("int a"); 
} 

//implementing interface method 
@Override 
public void method() { 
    System.out.println("interface"); 
} 

//varargs 
public void method(int ... a){ 
    System.out.println("int ... a"); 
} 

Nachdem sie mit diesen Parametern aufrufen,

int[] a = new int[5]; 
stack.method(); 
stack.method(1); 
stack.method(5,6); 
stack.method(null); 
stack.method(a); 

Ich habe diese Ergebnisse:

Schnittstelle
int a
int ... ein
int ... a
int ... a

Soweit ich weiß, kompiliert, sollte das Programm nicht, beacuse der Mehrdeutigkeit, aber es funktioniert trotzdem. Sollte der Compiler keinen Fehler ausgeben?

+1

int ist ein Basistyp, null ist für Objekte. Jeder Basistyp hat einen Standardwert (int = 0), wenn Sie keine angeben.Da ein Array per se ein Objekt ist, wird null als Vararg-Argument interpretiert, da Basistypen Arent-Referenzen sind und daher nicht Null sein können. So einfach ist das. –

Antwort

2

Die Überladungsauflösung hat drei Stufen. Die erste und zweite Stufe betrachten keine Methoden mit Varargs (auch Variable Arity-Methoden genannt) als Kandidaten, so dass der Compiler die Methode mit Varargs nur dann als Kandidaten betrachtet, wenn keine passende Methode ohne Varargs gefunden wird.

Daher wird in den ersten und zweiten Methodenaufrufen, Ihre void method(int ... a) wird ignoriert, und es gibt keine Zweideutigkeit.

15.12.2. Compile-Time Step 2: Determine Method Signature

Der zweite Schritt durchsucht die in dem vorherigen Schritt bestimmten Art für Element Methoden. Dieser Schritt verwendet den Namen der Methode und das Argument Ausdrücke Methoden zu finden, die sowohl zugänglich und anwendbar sind, das heißt, Erklärungen, die auf den gegebenen Argumente korrekt aufgerufen werden können.

Es kann mehr als ein solches Verfahren sein, in welchem ​​Fall der meisten spezifischen gewählt wird. Der Deskriptor (Signatur plus Rückgabetyp) von ist die spezifischste Methode, die zur Laufzeit verwendet wird, um den Methodenversand durchzuführen.

Verfahren ist anwendbar, wenn es von einem strengen Aufruf (§15.12.2.2) anwendbar ist, lose Invocation (§15.12.2.3) oder variable arity Invocation (§15.12.2.4).

Bestimmte Argument Ausdrücke, die implizit enthalten typisierten Lambda Ausdrücke (§15.27.1) oder ungenaue Methode Referenzen (§15.13.1) sind durch die Anwendbarkeit Tests ignoriert, weil ihre Bedeutung nicht bis Typ eines Ziels bestimmt werden soll, ausgewählt.

Obwohl der Methodenaufruf ein Poly-Ausdruck sein kann, beeinflussen nur seine Argumentausdrücke - nicht der Zieltyp des Aufrufs - die Auswahl der anwendbaren Methoden .

Der Prozess zur Bestimmung der Anwendbarkeit beginnt mit der Bestimmung der potenziell anwendbaren Methoden (§15.12.2.1).Der Rest des Prozesses ist in drei Phasen aufgeteilt, um Kompatibilität mit Versionen der Java-Programmiersprache vor Java SE 5.0 zu gewährleisten. Die Phasen sind:

  1. die erste Phase (§15.12.2.2) führt Überladungsauflösung ohne ermöglicht Boxen oder unboxing Umwandlung oder die Verwendung von variablen arity Methodenaufruf. Wenn kein anwendbares Verfahren in dieser Phase gefunden wird dann weiter in die zweite Phase der Verarbeitung. Dies garantiert, dass alle Aufrufe, die in der Programmiersprache Java vor Java SE 5.0 gültig waren, nicht als mehrdeutig als Ergebnis der Einführung von Variablenarity-Methoden, implizit Boxen und/oder Unboxing. Die Deklaration einer Variablenmethode (§8.4.1) kann jedoch die für eine bestimmte Methodenmethode Aufrufausdruck gewählte Methode ändern, da eine variable Arity-Methode in der ersten Phase als Fixed-Arity-Methode behandelt wird. Zum Beispiel deklariert m (Object ...) in einer Klasse, die bereits m (Object) deklariert, m (Object) nicht mehr für einige Aufrufausdrücke (wie als m (null)), als m (Object []) ist spezifischer.

  2. Die zweite Phase (§15.12.2.3) führt eine Überladungsauflösung durch, während Boxing und Unboxing erlaubt ist, aber die Verwendung der Variable Arity Methodenaufruf immer noch ausschließt. Wenn kein anwendbares Verfahren während dieser Phase gefunden wird, dann setzt sich die Verarbeitung in die dritte Phase. Dadurch wird sichergestellt, dass ein Verfahren niemals durch variable arity Methodenaufruf wird gewählt, wenn es fest anwendbar durch arity Methode Aufruf ist.

  3. die dritte Phase (§15.12.2.4) ermöglicht Überlastung mit variabler arity Methoden kombiniert wird, Boxen und unboxing.

+0

Vielen Dank für Ihre schnelle Antwort. – kunedgard

+1

@ j2hEhE nichts zu danken. Stackoverflow unterhält ein Reputationssystem. Wenn Sie eine hilfreiche Antwort gefunden haben, verwenden Sie die Upvote-Funktion neben dem Post, wenn Sie die Dinge, die Ihrer Meinung nach falsch sind, nicht kommentieren und ablehnen. Sie können (und sollten) auch eine Antwort als Lösung für Ihr Problem (oder Ihre Frage) akzeptieren, damit in Zukunft ähnliche Fragen auf die akzeptierte Lösung referenziert werden können –

+0

@Roman Vottner "keine Notwendigkeit zu danken ???" kein Verbot höflich zu sein :) – davidxxx

1

Verfahren mit einer Liste variable Argument wird vom Compiler, wenn alle anderen Möglichkeiten ausgeschöpft sind nur in Betracht gezogen.

diese „anderen Möglichkeiten“ werden in gewohnter Weise in Betracht gezogen.

daher in Ihrem Fall gibt es keine Zweideutigkeit und damit der Compiler emittieren keinen Fehler.

+0

Vielen Dank! – kunedgard

1

Nein es ist in Ordnung, gibt es keine Zweideutigkeit: passing "(5,6)" ist in Ordnung, da das Verfahren viele Zahlen expxects, vorbei "(a)" auch in Ordnung ist, weil a eine ganze Zahl Array passing"(null)" ist auch in Ordnung beacause null kann wie ein integer [] einen Referenztyp gegossen werden so kann es verwendet werden, wo Sie erwarten int [];

so all diese Anrufe rufen die dritte Methode

public void method(int ... a){ 
    System.out.println("int ... a"); 
} 

die ersten beiden Methodenaufrufe sind selbst sie Methoden aufrufen erläuternd

public void method(){ 
    System.out.println("interface"); 
} 

und

public void method(int a){ 
    System.out.println("int a"); 
} 

bzw.

+0

Vielen Dank für Ihre Antwort! – kunedgard

3

Eran und Bathseba haben bereits gesagt, warum die verschiedenen, die nicht null verwenden, ausgewählt wurden.

Der Rest der Frage ist: Warum kompiliert stack.method(null); sogar?

Die Antwort ist, dass es die Varargs-Signatur entspricht, da die Varargs method(int...) aus der Perspektive des Compilers effektiv die gleiche ist wie method(int[]). Da Arrays durch Referenzen referenziert werden, kann null verwendet werden, wenn ein int[] erwartet wird. So

:

stack.method(); 

Exact Match für die method() Signatur in der Schnittstelle. Nicht eindeutig mit method(int...), weil Varargs nur berücksichtigt werden, wenn andere nicht übereinstimmen.

stack.method(1); 

Spiele method(int). Nicht zweideutig aus dem gleichen Grund wie oben.

stack.method(5,6); 

Spiele method(int...) weil keiner der nicht-varargs diejenigen abgestimmt, aber die varargs tat.

stack.method(null); 

Siehe frühere Erklärung.

stack.method(a); 

Spiele match(int...) aus dem gleichen Grund method(null0 tut: Weil match(int...) effektiv die gleiche wie match(int[]) an den Compiler ist.

+1

Jetzt verstehe ich, danke! – kunedgard