在Java中混合嵌套类型参数和通配符

her*_*ung 14 java generics

为什么要尝试编译

public class GenericsFail {
    public static void main(String[] args) {
        accept(new HashMap<String, List<String>>());
    }

    public static void accept(Map<String, List<?>> multiMap) {}
}
Run Code Online (Sandbox Code Playgroud)

给出错误

GenericsFail.java:7: error: method accept in class GenericsFail cannot be applied to given types;
                accept(new HashMap<String, List<String>>());
                ^
  required: Map<String,List<?>>
  found: HashMap<String,List<String>>
  reason: actual argument HashMap<String,List<String>> cannot be converted to Map<String,List<?>> by method invocation conversion
Run Code Online (Sandbox Code Playgroud)

仅当通配符未嵌套在内时才允许使用通配符List.

Boh*_*ian 13

原因是?in List<?>可能是"任何东西",但每个条目中都有不同的 "任何东西" Map.也就是说,它会接受List<String>一个条目,一个条目接受另一个条目List<Integer>.

但是你传递的是每个条目Map中具有相同类型的类型List,因此类型不会以相同的方式或相同的自由度绑定.

"修复"是将类型锁定为特定类型,但仍然是"任何" - 通过键入方法,每个条目中的"任何*" 相同:

public static <T> void accept(Map<String, List<T>> multiMap) // complies
Run Code Online (Sandbox Code Playgroud)

或者如果您的方法确实不需要知道哪种类型,请使用通配符来包装类型:

public static void accept(Map<String, ? extends List<?>> multiMap) // compiles
Run Code Online (Sandbox Code Playgroud)

最后一个版本的工作原理是因为列表的类型虽然是通配符,但在调用时会固定为未知但一致的类型.


我发现键入的版本更容易阅读(和代码),如果您稍后决定您的方法需要知道类型,则可以使用该类型.