2015-08-23 6 views
8

Hier ist ein CodesegmentWarum generische Version von Sammlung Parameter wird immer Anruf

public class HelloWorld{ 

    public static void main(String[] args) { 
     GenericClass<Integer> test = new GenericClass<Integer>(); 
     test.method(new ArrayList<Integer>()); 
    } 
} 
class GenericClass<T> { 
    public void overloadedMethod(Collection<?> o) { 
     System.out.println("overloadedMethod(Collection<?>)"); 
    } 
    public void overloadedMethod(List<Number> s) { 
     System.out.println("overloadedMethod(List<Number>)"); 
    } 
    public void overloadedMethod(ArrayList<Integer> i) { 
     System.out.println("overloadedMethod(ArrayList<Integer>)"); 
    } 

    public void method(List<T> t) { 
     overloadedMethod(t) ; // which method is called? 
    } 
} 

ich es erwarte würde überladene Methode mit Arraylist Parameter nennen, aber Collection warum genannt zu werden?

Antwort

5

Dieser genaue Code wird in Angelika Langer's webpage on java generics

ich die Erklärung für den Fall in einem Beispiel verwendet die Seite jemals geht werde nach:

Das Programm druckt:

overloadedMethod (Sammlung)

Man könnte erwarten, dass die Version für ArrayList aufgerufen wird, aber das ist wieder die falsche Erwartung. Lassen Sie uns sehen, worauf der Compiler die generische Klasse umsetzt.

Beispiel (nach Typ Löschung):

public final class GenericClass { 

    private void overloadedMethod(Collection o) { 
     System.out.println("overloadedMethod(Collection<?>)"); 
    } 
    private void overloadedMethod(List s) { 
     System.out.println("overloadedMethod(List<Number>)"); 
    } 
    private void overloadedMethod(ArrayList i) { 
     System.out.println("overloadedMethod(ArrayList<Integer>)"); 
    } 

    private void method(List t) { 
     overloadedMethod(t) ; 
    } 

    public static void main(String[] args) { 
     GenericClass test = new GenericClass(); 
     test.method(new ArrayList()); 
    } 
} 

Man könnte fälschlicherweise glauben, dass der Compiler, dass die Liste Version der überladenen Methode entscheiden, wäre die beste Übereinstimmung. 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.

In der Tat, wenn Sie die Sammlung Methode kommentieren Sie erhalten Sie einen Compiler-Fehler, weil die Liste und Arraylist zu spezifisch sind für alle möglichen <T> Typen zu passen.

4

Werfen Sie einen Blick auf Abschnitt 15.12 unter der Java documention mit dem Titel "Method Invocation Expressions". Insbesondere Abschnitt 15.12.2.5 Wahl der am besten spezifische Methode:

Wenn mehr als ein Mitglied Verfahren zugänglich und anwendbar auf einen Verfahren Aufruf ist, ist es notwendig, ein wählen den Deskriptor für die Laufzeit zur Verfügung zu stellen Methodenversand. Die Java-Programmiersprache verwendet die Regel, dass die am meisten spezifische Methode gewählt wird. Die informelle Intuition ist, dass eine Methode spezifischer ist als eine andere, wenn jeder Aufruf, der von der ersten Methode behandelt wurde, an die andere ohne einen Kompilierzeitfehler übergeben werden konnte. In Fällen wie einem explizit typisierten Lambda-Ausdruck Argument (§15.27.1) oder eine Variable Arity Aufruf (§15.12.2.4), ist es etwas Flexibilität erlaubt, eine Unterschrift auf die andere zu ändern.

Außerdem Abschnitt 8.4.9 genannt Overloadding heißt es:

Wenn eine Methode aufgerufen wird (§15.12), die Anzahl der tatsächlichen Argumente (und alle Argumente des expliziten Typs) und die Kompilierzeittypen der Argumente werden zur Kompilierzeit verwendet, um die Signatur der Methode zu bestimmen, die aufgerufen wird (§15.12.2). Wenn es sich bei der Methode, die aufgerufen werden soll, um eine Instanzmethode handelt, wird die tatsächlich zu aktivierende Methode zur Laufzeit mithilfe des dynamischen Methoden-Lookups (§15.12.4) ermittelt.

diese beiden Abschnitte Berücksichtigung, können wir feststellen, dass seit method ein List<T> Objekt übergeben wird, das spezifische Ziel Java feststellt, dass eine Wildcard ist Collections.

Beachten Sie, dass, auch wenn Sie das Argument zu ArrayList<T> als solche verändert hatte:

public void method(ArrayList<T> t) { 
    overloadedMethod(t) ; // which method is called? 
} 

Das gleiche Verfahren wird noch genannt werden, weil die spezifische Überlastung, die Arraylist akzeptiert zu spezifisch ist - ArrayList<Integer> vs. Ihr Argument, ist ArrayList<T> und somit bestimmt Java Collection<?> als die beste Übereinstimmung (Sie können natürlich umgehen, indem Sie entweder den Parametertyp von method ändern oder den Parameter overloadedMethod spezifischer machen).

Verwandte Themen