Dieser genaue Code wird in einem Beispiel in Angelika Langers Webseite zu Java-Generika
Ich werde die Erklärung posten, falls die Seite jemals untergeht:
%Vor%Das Programm druckt:
overloadedMethod (Sammlung)
Man hätte erwarten können, dass Version für ArrayList aufgerufen wird, aber das ist wiederum die falsche Erwartung. Lassen Sie uns sehen, worauf der Compiler die generische Klasse umsetzt.
Beispiel (nach dem Typ löschen):
Man könnte fälschlicherweise glauben, dass der Compiler entscheiden würde, dass die Listenversion der überladenen Methode die beste Übereinstimmung ist. Aber das wäre natürlich falsch. Die Listenversion der überladenen Methode war ursprünglich eine Version, die eine Liste als Argument verwendet, aber beim Aufruf wird eine Liste übergeben, wobei T ein beliebiger Typ sein kann und keine Zahl sein muss. Da T ein beliebiger Typ sein kann, ist die einzige durchführbare Version der überladenen Methode die Version für Collection.
Wenn Sie die Collection-Methode auskommentieren, erhalten Sie einen Compiler-Fehler, weil die List- und ArrayList zu spezifisch für alle möglichen <T>
-Typen sind.
Sehen Sie sich Abschnitt 15.12 im Java-Dokument mit dem Titel "Method Invocation Expressions" an ". Genauer gesagt Abschnitt 15.12.2.5 Auswählen der spezifischsten Methode :
Wenn mehrere Methoden gleichzeitig verfügbar und auf eine Methode anwendbar sind Aufruf, ist es notwendig, einen zu wählen, um den Deskriptor für die Laufzeit bereitzustellen Methodenversand Die Java-Programmiersprache verwendet die Regel, die am meisten spezifische Methode wird gewählt.
Die informelle Intuition ist, dass eine Methode spezifischer ist als ein anderer, wenn irgendein Aufruf, der von der ersten Methode behandelt wurde, übergeben werden könnte auf die andere ohne einen Kompilierzeitfehler. In Fällen wie einem explizit eingegebenes Lambda-Ausdruckargument (§15.27.1) oder eine Variable Arity-Aufruf (§15.12.2.4), etwas Flexibilität ist erlaubt anzupassen eine Unterschrift für die andere.
Darüber hinaus heißt es in Abschnitt 8.4.9 Überladung :
Wenn eine Methode aufgerufen wird (§15.12), die Anzahl der tatsächlichen Argumente (und alle explizite Typargumente) und die Kompilierungszeittypen der Argumente verwendet werden, zur Kompilierzeit, um die Signatur der Methode zu ermitteln, die aufgerufen wird (§15.12.2). Wenn die Methode, die aufgerufen werden soll, eine Instanzmethode ist, die tatsächliche Die Methode, die aufgerufen werden soll, wird zur Laufzeit unter Verwendung der dynamischen Methodensuche ermittelt (§15.12.4).
Unter Berücksichtigung dieser beiden Abschnitte können wir feststellen, dass, da method
ein List<T>
-Objekt übergeben wird, das spezifischste Java-Ziel das eines Platzhalters Collections
ist.
Beachten Sie, dass Sie das Argument selbst dann in ArrayList<T>
geändert haben:
Dieselbe Methode wird immer noch aufgerufen, da die spezifische Überladung, die ArrayList akzeptiert, zu spezifisch ist - ArrayList<Integer>
vs. Ihr Argument ist ArrayList<T>
und Java bestimmt Collection<?>
als beste Übereinstimmung (Sie können von Natürlich umgehen Sie es, indem Sie entweder den Parametertyp von method
ändern oder den Parameter overloadedMethod
spezifischer machen.