2009-03-24 7 views
102

Ich benutze Eclipse, um mir zu helfen, etwas Code aufzuräumen, um Java-Generics richtig zu benutzen. Die meiste Zeit ist es eine ausgezeichnete Arbeit, um Typen zu folgern, aber es gibt Fälle, in denen der abgeleitete Typ so allgemein wie möglich sein muss: Objekt. Aber Eclipse scheint mir eine Option zu geben, zwischen einem Objekttyp und einem Typ "?" Zu wählen.Worin besteht der Unterschied? und Objekt in Java-Generics?

Also, was ist der Unterschied zwischen:

HashMap<String, ?> hash1; 

und

HashMap<String, Object> hash2; 
+1

Siehe das offizielle Lernprogramm zu [Wildcards] (http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html). Es erklärt es gut und gibt ein Beispiel dafür, warum es notwendig ist, einfach Object zu verwenden. –

Antwort

103

Eine Instanz HashMap<String, String> Matches Map<String, ?> aber nicht Map<String, Object>. Sagen Sie bitte, ein Verfahren schreiben möchten, die Karten von String s alles akzeptiert: Wenn Sie

public void foobar(Map<String, Object> ms) { 
    ... 
} 

Sie können keine HashMap<String, String> liefern schreiben würde. Wenn Sie schreiben

public void foobar(Map<String, ?> ms) { 
    ... 
} 

es funktioniert!

Eine Sache manchmal missverstanden in Java-Generika ist, dass List<String> ist kein Untertyp von List<Object>. (Aber String[] ist in der Tat ein Subtyp von Object[], das ist einer der Gründe, warum Generika und Arrays nicht gut mischen. (Arrays in Java sind kovariant, Generika sind nicht, sie sind Invariante)).

Probe: Wenn Sie eine Methode schreiben möchten, die List s von InputStream s und Subtypen von InputStream akzeptiert, dann würden Sie

public void foobar(List<? extends InputStream> ms) { 
    ... 
} 

Durch die Art und Weise schreiben: Joshua Bloch's Effective Java ist eine hervorragende Ressource, wenn Sie Ich würde gerne die nicht so einfachen Dinge in Java verstehen. (Ihre obige Frage ist auch in dem Buch sehr gut abgedeckt.)

+1

ist dieser richtige Weg zu ResponseEntity auf Controller-Ebene für alle meine Controller-Funktionen zu verwenden? – Purmarili

3

Sie können nichts sicher in Map<String, ?> setzen, weil Sie nicht wissen, welcher Typ die Werte sein sollen.

Sie können jedes Objekt in eine Map<String, Object> setzen, da der Wert bekanntermaßen Object ist.

+0

"Sie können nichts sicher in Karte " False. Du kannst, das ist sein Zweck. –

+0

Falsch, Ben. Dies führt zu "ungeprüften" Warnungen. Der Zweck von Platzhaltern besteht darin, Code zu schreiben, der mit einem beliebigen generischen Typ arbeiten kann. – erickson

+1

Ben ist falsch, der einzige Wert, den Sie in eine Sammlung des Typs eingeben können, ist null, während Sie alles in eine Auflistung des Typs einfügen können. –

7

Es ist leicht zu verstehen, wenn Sie sich erinnern, dass Collection<Object> ist nur eine generische Sammlung, die Objekte des Typs Object enthält, aber Collection<?> ist ein Super-Typ aller Arten von Sammlungen.

+1

Es muss gesagt werden, dass das nicht gerade einfach ist ;-), aber es ist richtig. –

23

Eine andere Möglichkeit, um dieses Problem zu denken, dass

HashMap<String, ?> hash1; 

zu

HashMap<String, ? extends Object> hash1; 

Paar dieses Wissen mit dem "Get und Put-Prinzip" in Abschnitt (2 entspricht.4) von Java Generics and Collections:

The Get und Put-Prinzip: Verwenden Sie ein Wildcard erstreckt, wenn Sie nur Werte aus einer Struktur erhalten, verwenden Super Platzhalter, wenn Sie nur Werte in eine Struktur setzen, und Verwenden Sie keinen Platzhalter , wenn Sie beide bekommen und setzen.

und die Platzhalterkarte kann hoffentlich mehr Sinn ergeben.

+0

Wenn "?" verwirrt Sie, "? extends Object" wird Sie wahrscheinlich mehr verwirren. Könnte sein. –

+0

Der Versuch, "Denkwerkzeuge" zu liefern, die es erlauben, über dieses schwierige Thema nachzudenken. Zusätzliche Informationen zum Erweitern von Platzhaltern. –

+1

Danke für die zusätzlichen Informationen. Ich verdaue es immer noch. :) – skiphoppy

1

Die Antworten oben Kovarianz den meisten Fällen Cover aber eine Sache vermissen: "?"

enthält "Objekt" in der Klassenhierarchie. Man könnte sagen, String ist eine Art von Objekt und Objekt ist ein Typ von?. Nicht alles stimmt mit Objekt überein, aber alles stimmt überein?

int test1(List<?> l) { 
    return l.size(); 
} 

int test2(List<Object> l) { 
    return l.size(); 
} 

List<?> l1 = Lists.newArrayList(); 
List<Object> l2 = Lists.newArrayList(); 
test1(l1); // compiles because any list will work 
test1(l2); // compiles because any list will work 
test2(l1); // fails because a ? might not be an Object 
test2(l2); // compiled because Object matches Object 
Verwandte Themen