2009-05-16 21 views
6

Gibt es eine Möglichkeit, die folgende Implementierung typsicher zu machen?Java Generics setzen Karte <String,? extends Liste <String>>

public void myMethod(Map<String, ? extends List<String>> map) 
{ 
    map.put("foo", Collections.singletonList("bar"); 
} 

Die obige Implementierung funktioniert nicht. Es erfordert eine Map<String, ? super List<String>>, um die Methode map.put() korrekt zu kompilieren. Aber myMethod wird keinen Untertyp von List auf diese Weise akzeptieren. Also muss ich stattdessen Map<String, ? extends List<String>> verwenden. Wie kann ich dieses Problem typsicher lösen?

Antwort

20
public void myMethod(Map<String, List<String>> map) { 
    map.put("foo", Collections.singletonList("bar")); 
} 

Sie können keine List (den Rückgabetyp von Collections.singletonList() in eine Map von ? extends List setzen, da der tatsächliche Typ jede Implementierung von List. Zum Beispiel könnte, ist es nicht sicher ein generisches setzen List in ein Map<String,LinkedList> seit dem List kein LinkedList. Doch sein könnte, können wir leicht eine LinkedList in eine Map von <String,List> setzen.

ich glaube, Sie w Überdenken Sie Ihre Generika. Sie müssen ? extends nicht für eine nicht generische Klasse verwenden. Beispiel: List<Object> enthält eine beliebige Object, die ? extends wird nicht benötigt, um ein Objekt hinzuzufügen. A List<List<Foo>> nimmt nur List<Foo> Objekte und keine List<FooSubclass> Objekte [Generische Klassen erben nicht basierend auf ihren Parametern]. Hier kommt ? extends ins Spiel. Um sowohl als auch List<FooSubclass> zu List hinzuzufügen, muss der Typ List<List<? extends Foo>> lauten.

+2

+1 für eine gute Erklärung (jetzt, dass Ihre Generika sichtbar sind: P). –

+0

Hoppla. Ich denke immer daran, dass SOF-Filter trotzdem Text filtern, der das angulierte Bracket-Zeug fixiert. Naja... – KitsuneYMG

6

Würde nicht Map<String, List<String> arbeiten? Gibt es einen bestimmten Grund, warum du überhaupt eine Wildcard haben musst?

0

Stellen Sie sich vor, wenn Ihnen jemand eine Map<String, ArrayList<String>> übergeben hat. Der Wert, den Sie eingeben, ist das Ergebnis von Collections.singletonList, das nicht ein ArrayList ist.

Sie können keinen Subtyp von List in der Map akzeptieren und dann erwarten, dass Sie Ihren eigenen, möglicherweise inkompatiblen Subtyp hinzufügen können.

4

Es gibt ein sehr einfaches Prinzip, wenn Sie Collections und Generics zusammen verwenden. Es heißt "The Get and The Put-Prinzip":

Verwenden Sie ein "Extensions" Platzhalter, wenn Sie nur Werte aus einer Sammlung abrufen, verwenden Sie "Super" Platzhalter, wenn Sie nur Werte in eine Sammlung PUT und nicht verwenden irgendein Platzhalter, wenn Sie beide erhalten und setzen möchten.

Also, wie Sie sehen können, ist das erste Beispiel nach diesem Prinzip ungültig.

Verwandte Themen