Java 类型推断没有像我预期的那样工作

the*_*oop 5 java generics type-inference

我有这个方法(这是我原来问题的简化):

public List<AbstractMap.SimpleEntry<String, List<?>>> method(List<?> list) {
    return Collections.singletonList(new AbstractMap.SimpleEntry<>("", list));
}
Run Code Online (Sandbox Code Playgroud)

但是,这会导致编译错误:

Console.java:40: error: incompatible types
        return Collections.singletonList(new AbstractMap.SimpleEntry<>("", list));
                                        ^
  required: List<SimpleEntry<String,List<?>>>
  found:    List<SimpleEntry<String,List<CAP#1>>>
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
10 errors
Run Code Online (Sandbox Code Playgroud)

如果我尝试在顶级方法上指定类型实例化:

return Collections.<AbstractMap.SimpleEntry<String, List<?>>>singletonList(new AbstractMap.SimpleEntry<>("", list));
Run Code Online (Sandbox Code Playgroud)

我得到一个不同的错误:

Console.java:40: error: method singletonList in class Collections cannot be applied to given types;
return Collections.<AbstractMap.SimpleEntry<String, List<?>>>singletonList(new AbstractMap.SimpleEntry<>("", list));
                  ^
  required: T
  found: SimpleEntry<String,List<CAP#1>>
  reason: actual argument SimpleEntry<String,List<CAP#1>> cannot be converted to SimpleEntry<String,List<?>> by method invocation conversion
  where T is a type-variable:
    T extends Object declared in method <T>singletonList(T)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
10 errors
Run Code Online (Sandbox Code Playgroud)

只有当我在内部方法上指定类型参数时,它才能正常工作:

return Collections.singletonList(new AbstractMap.SimpleEntry<String, List<?>>("", list));
Run Code Online (Sandbox Code Playgroud)

我什至不假装了解这里发生了什么。我怀疑这与捕获转换有关(此处的相关问题),但我不知道为什么在外部方法上指定泛型不起作用,但在内部方法上指定。java 不使用返回类型来推断这样的嵌套调用的类型参数吗?这里发生了什么?

Bla*_*sui 0

问题是您无法使用通配符类型参数实例化任何类(例如,new ArrayList<?>();无法编译)。因此,编译器尝试为 CAP#1 推导现有类,这是不可能的,因为需要通配符。

解决方案是避免使用通配符。像这样向方法本身添加类型参数。

public <T> List<AbstractMap.SimpleEntry<String, List<T>>> method(List<T> list) {
    return Collections.singletonList(new AbstractMap.SimpleEntry<>("", list));
}
Run Code Online (Sandbox Code Playgroud)

除了编译器关闭之外,签名还可以更清楚地了解该方法实际返回的内容。