简体   繁体   中英

Java generic type with wildcard

I want to write a method that can accept the parameter:

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

So, here is what I coded:

/**
 * 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;
}

And the EMPTY_LIST is defined as below:

List<Object> EMPTY_LIST = Collections.unmodifiableList(new ArrayList<Object>());

The problem is that when I call this method with following code, Eclipse tells me a error that the given parameter's type is not applicable.

getListValueFromMap(cityNameMap, "key");

And the error is:

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

Where am I going wrong with this?

Here is the definition of cityNameMap :

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

It's important to take note of what ? extends Object ? extends Object actually represents in generics.

In its current incantation, it is an upper-bounded wildcard which has its upper bound as Object . Ideally, this would imply that you could use any list from it, but since generics are invariant, that wouldn't be the case here at all - you could only use lists which have the same bound.

Since the containing type of the list may change from map to map, set your bound on a generic type to get at the list you care about instead.

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;
}

Be sure to update your EMPTY_LIST dependency accordingly; obviously in this state, you can't return the list bounded with Object .

This has the advantage of allowing you to pass your list in with any supplied type, and you won't be able to simply add elements to it once you retrieve them from your map due to the way the generic argument is done on the list.

You could do this:

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

Both don't give me any issues in my IDE (IntelliJ 2016.1.1), but it could be that yours has different settings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM