2016-04-13 23 views
3

ich eine Methode schreiben möchten, dass die Parameter annehmen können:Java generischer Typ mit Wildcard

Map<String, [the type here could be anything]> 

So, hier ist das, was ich codiert:

/** 
* Get list value from a map, empty list if there's no key matched 
*/ 
private List<? extends Object> getListValueFromMap(Map<String, List<? extends Object>> map, String key) { 
    List<? extends Object> list = map.get(key); 
    return list == null ? EMPTY_LIST : list; 
} 

Und die EMPTY_LIST wird wie folgt definiert:

Das Problem ist, dass, wenn ich diese Methode mit folgendem Code aufrufen, Eclipse sagt mir einen Fehler, dass die Der angegebene Parametertyp ist nicht anwendbar.

getListValueFromMap(cityNameMap, "key"); 

Und der Fehler ist:

The method getListValueFromMap(Map<String,List<? extends Object>>, String) in the type ChinaAreaResource is not applicable for the arguments (Map<String,List<City>>, String)

wo ich mit diesem falschen werde? Hier

ist die Definition von cityNameMap:

/** map city's name to city list */ 
private Map<String, List<City>> cityNameMap; 
+0

Wie ist 'citiNameMap' definiert? –

+0

Wie ** Map > cityNameMap = null; 'für mich funktioniert gut. –

+0

Was ist der Sinn von 'Collections.unmodiableList (new ArrayList ());'? Wenn Sie bereits von 'Collections' wissen, warum verwenden Sie' Collections.emptyList() 'nicht? – Holger

Antwort

4

Es ist wichtig zu beachten, was ? extends Object tatsächlich in Generika darstellt.

In seiner aktuellen Beschwörung ist es eine upper-bounded wildcard, die ihre obere Grenze als Object hat. Idealerweise würde dies bedeuten, dass Sie jede Liste daraus verwenden könnten, aber da Generika invariant sind, wäre das hier überhaupt nicht der Fall - Sie könnten nur Listen verwenden, die die gleiche Grenze haben.

Da sich der Inhaltstyp der Liste von Karte zu Karte ändern kann, legen Sie die Grenze für einen generischen Typ fest, um an die Liste zu gelangen, die Ihnen wichtig ist.

private <T> List<? extends T> getListValueFromMap(Map<String, List<T>> map, String key) { 
    List<? extends T> list = map.get(key); 
    return list == null ? EMPTY_LIST : list; 
} 

Seien Sie sicher, entsprechend Ihrer EMPTY_LIST Abhängigkeit zu aktualisieren; offensichtlich in diesem Zustand können Sie die mit Object gebundene Liste nicht zurückgeben.

Dies hat den Vorteil, dass Sie Ihre Liste mit jeden geliefert Typ passieren, und Sie werden nicht einfach sein können Elemente, um es hinzuzufügen, sobald Sie sie von der Karte aufgrund der Art und Weise des allgemeinen Arguments abrufen ist auf der Liste getan.

+0

Ich denke, ich verstehe Ihre Worte etwas, da der Compiler nicht den realen Typ von sagen kann, es nur T-Typ davon abgerufen ermöglichen. – bedew

+0

Das richtige Idiom für die leere Liste ist 'Collections. emptyList() ', die immer noch den Singleton' Collections.EMPTY_LIST' zurückgibt, aber jetzt ohne die Notwendigkeit, "ungeprüfte" Warnungen zu unterdrücken. Beginnend mit Java 8 können Sie die '' Datei verwenden und' Collections.emptyList() 'verwenden. Übrigens sind Generika nicht invariant in allen Fällen, so dass 'Map > 'als Parameter Typ würde das Problem auch lösen, aber den Typ Parameter' 'hinzufügen, um zu deklarieren, dass die zurückgegebene Liste den gleichen Elementtyp wie der' Map' Wert hat, ist der Typ viel besser. – Holger

+0

Übrigens gibt es keinen Vorteil bei der Umwandlung der Liste der Liste in eine Liste 'in dem Prozess. Sie können einfach 'List ' '... – Holger

0

Sie dies tun könnte:

private <T> List<T> getListValueFromMap(Map<String, List<T>> map, String key) { 
    // 
} 

Beide geben mir keine Probleme in meiner IDE (IntelliJ 2016.01.01), aber es könnte sein, dass deins unterschiedliche Einstellungen hat.

+0

Ja, das kann mein Problem beheben, nur kann ich die EMPTY_LIST nicht von der Methode zurückgeben, wenn ich den Rückgabetyp unverändert belasse, aber ich denke, der wahre Grund dafür ist, dass es einige Designprobleme gibt, nur eine Singleton-Instanz von List zurückzuliefern Egal, welcher Anrufer mir welche Art von Liste in Parameter Map – bedew

+0

gibt Und immer noch bin ich sehr kariös über den Grund, warum ich die Methode ursprünglich nicht aufrufen kann ~ – bedew

+0

public static final Liste EMPTY_LIST = new ArrayList(); funktioniert gut für mich – delucasvb