Java泛型如何接受泛型参数中的任何派生类型
在下面的两行代码中Java泛型如何接受泛型参数中的任何派生类型,java,generics,Java,Generics,在下面的两行代码中 HashMap<Integer, ?extends Collection<String>> map= new HashMap<Integer, TreeSet<String>>(); map.put(1,new TreeSet<String>()); HashMap= 新的HashMap(); put(1,新树集()); 第2
HashMap<Integer, ?extends Collection<String>> map=
new HashMap<Integer, TreeSet<String>>();
map.put(1,new TreeSet<String>());
HashMap=
新的HashMap();
put(1,新树集());
第2行:HashMap>类型中的方法put(Integer,capture#1-of?extends Collection)不适用于参数(int,TreeSet)
第1行:这没有错误
为什么在第1行中允许相同的泛型类型(TreeSetHashMap<Integer, ?super Collection<String>> map=new HashMap(<Integer, TreeSet<String>>());
HashMap-map=newhashmap(());
但是
HashMap map=newhashmap();
put(1,新树集());
允许得到编译器错误的原因与不能向
列表添加狗的原因相同映射声明告诉编译器映射中的值是字符串的某个集合。在运行时,它可以是TreeSet
,但也可以是其他集合类型。因此,编译器不能允许放置TreeSet
,因为它实际上可能包含ArrayList
值
更一般地说,每当使用?
通配符使用绑定类型参数时,实际上只允许从映射中读取(例如,迭代其元素)。换句话说,您可以随时执行以下操作:
for(Iterator<? extends Collection<String>> iterator = map.values().iterator(); iterator.hasNext();) {
Collection<String> collection = iterator.next();
...
}
编译器说:
找不到适合put的方法(int、TreeSet)
put(1,新树集());
方法HashMap.put(整数,CAP#1)不适用
(无法通过方法调用转换将实际参数树集转换为CAP#1)
方法AbstractMap.put(整数,CAP#1)不适用
(实际参数树集无法通过方法调用转换转换为CAP#1),其中CAP#1是一个新类型变量:
第1章扩展了从捕获?扩展集合
我认为这是因为编译器的类型不明确,如前所述:
映射的声明告诉编译器
地图是一些字符串的集合。在运行时,它可能是一个
树集,但也可能是其他集合类型
如果编译器的类型是确定的,则代码将编译并运行而不会出现任何问题,例如,您可以按以下方式编写代码,从而成功编译并运行:
public <T extends Collection<String>> void someVoid(){
//...
//...
HashMap<Integer, T > map
= new HashMap<>();
map.put(1,(T) (new TreeSet<String>()));
//...
//...
}
public void someVoid(){
//...
//...
哈希映射
=新HashMap();
map.put(1,(T)(新树集());
//...
//...
}
在阅读了其他答案并对原始问题进行了更多思考(实际上是关于“”扩展部分与不扩展部分的比较),我提出了以下示例,应该更容易理解
假设我们有这个方法:
void doSomething(Collection<? extends Number> numbers) { ... }
在这种情况下,该方法可以向集合中添加任何数字,但是像doSomething(integers)
这样的调用会成为编译器错误,因为Integer
的集合只能接受整数。因此,编译器再次防止以后出现ClassCastException
s,确保代码是类型安全的。或者,如果映射必须接受任何类型的字符串集合,map map=new HashMap()代码>,可以简化为Map Map=newhashmap()代码>@JBNizet更好;我将把它添加到我的答案中。如果他将树集转换为集合,他可以将其放入mapAMap
不是一个Collection
,因此新HashMap…无论什么…
都不匹配?扩展集合
@achabahe No。它与调用put
时作为值传递的内容的类型无关,与通配符无关。
HashMap<Integer, Collection<String>> map =
new HashMap<Integer, Collection<String>>();
HashMap<Integer, ? super Collection<String>> map = new HashMap<Integer, TreeSet<String>>());
HashMap<Integer, ? super Collection<String>> map = new HashMap<>();
map.put(1, new TreeSet<String>());
for(Iterator<? extends Collection<String>> iterator = map.values().iterator(); iterator.hasNext();) {
Collection<String> collection = iterator.next();
...
}
HashMap<Integer, TreeSet<String>> map = new HashMap<>(); // In Java 7+, you can use the diamond operator when creating the HashMap
public <T extends Collection<String>> void someVoid(){
//...
//...
HashMap<Integer, T > map
= new HashMap<>();
map.put(1,(T) (new TreeSet<String>()));
//...
//...
}
void doSomething(Collection<? extends Number> numbers) { ... }
Collection<Integer> integers = asList(1, 2, 3);
Collection<Long> longs = asList(1L, 2L, 3L);
doSomething(integers);
doSomething(longs);
void doSomething(Collection<Number> numbers) { ... }