Java 用什么方法?扩展集合<;字符串>;不适用于Set<;字符串>;

Java 用什么方法?扩展集合<;字符串>;不适用于Set<;字符串>;,java,generics,Java,Generics,简短、自包含、不可编译的示例: public void test1() throws Exception { Map<String, Map<String, Set<String>>> a = Collections.singletonMap("One", Collections.singletonMap("Two", new HashSet<String>())); foo(a); } void foo(

简短、自包含、不可编译的示例:

public void test1() throws Exception {
    Map<String, Map<String, Set<String>>> a = Collections.singletonMap("One",
            Collections.singletonMap("Two", new HashSet<String>()));
    foo(a);
}

void foo(Map<String, Map<String, ? extends Collection<String>>> x) {
}
public void test1()引发异常{
Map a=Collections.singletonMap(“一”,
Collections.singletonMap(“两个”,新的HashSet());
傅(甲),;
}
void foo(地图x){
}
收益率(JavaC1.8.0_102):

错误:不兼容类型:无法将映射转换为映射
傅(甲),;
^
我希望
foo
可以采用
Collection
的任何子类型,比如
Set
List
。上面的代码有什么问题吗?

这将编译

void foo(Map<String, ? extends Map<String, ? extends Collection<String>>> x)
void foo(地图x)

按照您声明foo的方式,编译器需要一个确切类型的类型参数
Map
。您可以将foo设置为通用:

<C extends Collection<String>> void  foo(Map<String, Map<String, C>> x) {
}
void foo(地图x){
}

您的代码无法编译的原因与以下(更简单的)代码无法编译的原因相同:

List<Integer> l = Arrays.asList(1,2,3);
foo(l); //The method v(List<Object>) in the type Test is not applicable for the arguments (List<Integer>)

public void foo (List<Object> a){
...
}
这告诉编译器,
foo
将接受扩展对象的内容列表,这就是
List
的含义

在您的情况下,
Map
不会扩展
Map

即使您将
foo
更改为
void foo(Map x)
它也不会编译,因为
Map
不会扩展
Map
。他们是两种不同的类型


要使其工作,您可以将
foo
的签名更改为
void foo(Map x)

。想解释一下原因吗?事实上,其他用户(+1)已经给出了一个,重复它是徒劳的。泛型不变性有时会产生影响。请注意,类型参数在签名中仅使用一次。这反映了一个事实,即类型参数不用于表示参数的类型、返回类型和/或抛出类型之间的任何类型的相互依赖关系。在缺乏这种相互依赖性的情况下,泛型方法被认为是糟糕的风格,而通配符是首选。(c) jls-4.5。1@user2418306我不明白如何仅使用通配符来进行等效的方法声明。请注意,我的解决方案比使用
Map
更严格(更接近非编译代码)。例如,它不允许传递
Map
。但是,很可能您实际上想要更通用的仅通配符版本。
List<Integer> l = Arrays.asList(1,2,3);
foo(l); //The method v(List<Object>) in the type Test is not applicable for the arguments (List<Integer>)

public void foo (List<Object> a){
...
}
public void foo (List<? extends Object> a){
 ...
}