2012-12-20 15 views
9

Ich habe diese von einem Google I/O Puzzler sprechen gegeben von Joshua Bloch. Hier ist der CodeJava Generics Typ Löschung der Methode Parameter

public class Glommer<T> { 
     String glom(Collection<?> obj){ 
     String result = ""; 
     for(Object o : obj){ 
       result += o; 
     } 
     return result; 
     } 

     int glom(List<Integer> ints){ 
      int result = 0; 
      for(int i : ints){ 
       result += i; 
      } 
      return result; 
     } 

     public static void main(String args[]){ 
      List<String> strings = Arrays.asList("1", "2", "3"); 
      System.out.println(new Glommer().glom(strings)); 
     } 

diese Haupt Methode löst eine Ausnahme, weil new Glommer eine rohe Art ist und somit alle Generika in Glommer gelöscht wird, so es endet Aufruf int glom(List<Integer> ints) statt String glom(Collection<?> obj).

Meine Frage ist, auch wenn ich glom() als new Glommer<Integer>().glom(strings) sollte nicht nennen es die int glom(List<Integer> ints) Methode genannt, da aufgrund Löschen geben, ist diese Methode effektiv int glom(List ints) und strings ist vom Typ List nicht Collection?

Antwort

7

Die aufgerufene Methode wird zur Kompilierzeit definiert, nicht zur Laufzeit.

Wenn Sie Ihrem Konstruktoraufruf einen Parameter hinzufügen, verfügt der Compiler über genügend Informationen, um zu wissen, dass er die erste Methode aufrufen muss. Ansonsten ist es so, als ob es keine Generika gäbe. In beiden Fällen bleibt die aufgerufene Methode zur Laufzeit immer gleich.

EDIT Manche Leute zu zweifeln scheinen, also hier ein weiteres Beispiel:

public class Test { 

    private static void test(Object object) { 
     System.out.println("Object method"); 
    } 

    private static void test(Integer integer) { 
     System.out.println("Integer method"); 
    } 

    public static void main(String[] args) { 
     Object object = Integer.valueOf(0); 
     test(object); 
    } 

} 

Das Ergebnis ist:

Object method 

Sie einen Integer auf Ihre Methode übergeben, aber alles, was der Compiler weiß, bei der Kompilierung Zeit ist, dass es ein Objekt ist. Der jvm ändert den Methodenaufruf nicht automatisch, obwohl das Objekt tatsächlich eine Ganzzahl ist. Grundsätzlich rohe Typen sind für die Verwendung von Legacy-Code, fast alles, was in einer rohen Klasse

+0

Ich würde sagen, dass der Compiler die Signatur der auszuführenden Methode bestimmt, aber eine Methode zur Ausführung wird zur Laufzeit unter Verwendung des tatsächlichen Objekttyps gewählt. – tcb

+0

@tcb Ich habe ein Beispiel hinzugefügt, probieren Sie es aus. – WilQu

+0

Ich verstehe, was Sie sagen möchten und in diesem Beispiel sind Sie richtig, aber meine Worte waren über einen allgemeinen Fall, in dem Sie eine abgeleitete Klasse mit überschriebenen Methoden haben können. – tcb

0

Dies ist, weil, wenn new Glommer() ohne Generics die Generic<Type>() aufgerufen wird, alle Typübereinstimmungen aus der Klasse entfernt werden.

Als Strings Variable ist ein List, ob es einen generischen <Type> nicht hat, dann wird es die glom(List ints) entsprechen. Die Typprüfung wird erst später durchgeführt.

Wenn wir new Glommer<AnyType> erstellen, sind die Typen alle an Ort und Stelle, wenn wir also unsere strings Variable übergeben, wird die Typüberprüfung durchgeführt. Der Compiler kann nun prüfen, ob es sich um eine List<Integer> handelt, was nicht der Fall ist, sondern an die glom(Collection<?> obj)-Methode übergeben wird.

Hoffe, dass dies hilft, bitte fragen Sie nach Klärung, wenn Sie brauchen!

+0

Zum Compiler geändert. –

1

Sie können mehr über Raw Types lesen es

vollständig zu verstehen, wird roh selbst werden in diesem Fall diese zwei Methoden.

Also, wenn es roh ist es ein Verfahren ist, das so sein die List ein, wenn sie nicht roh genannt List und einen für Collection bekommt, sind die Verfahren auch nicht roh und es wird das Collection man das so nennen, weil es das ist zusätzliche Information

Verwandte Themen