从根本上说,
List<List<?>>
和
List<? extends List<?>>
事实上,一个是另一个的子类型,但首先让我们了解它们各自的含义。
理解语义差异
一般来说,通配符
?
表示一些“缺失信息”。意思是
. 因为我们不知道它是什么,所以限制了我们如何使用任何引用特定类型参数的东西。
List
而不是
Map
-
列表<列出<&燃气轮机&燃气轮机;
具有任何类型参数的任何类型的列表
List<List<?>> theAnyList = new ArrayList<List<?>>();
// we can do this
theAnyList.add( new ArrayList<String>() );
theAnyList.add( new LinkedList<Integer>() );
List<?> typeInfoLost = theAnyList.get(0);
// but we are prevented from doing this
typeInfoLost.add( new Integer(1) );
我们可以把任何
在里面
theAnyList
但是这样做我们就失去了对
他们的元素
.
-
当我们使用
? extends
,的
持有
一些特定的子类型列表,但我们不知道它是什么了
List<? extends List<Float>> theNotSureList =
new ArrayList<ArrayList<Float>>();
// we can still use its elements
// because we know they store Float
List<Float> aFloatList = theNotSureList.get(0);
aFloatList.add( new Float(1.0f) );
// but we are prevented from doing this
theNotSureList.add( new LinkedList<Float>() );
再加上任何东西都不安全了
theNotSureList
,因为我们不知道其元素的实际类型(
它最初是一个
List<LinkedList<Float>>
List<Vector<Float>>
? 我们不知道。)
-
列出<?扩展列表<&燃气轮机&燃气轮机;
. 我们不知道是什么类型的
它已经在里面了,我们不知道它的元素类型
列表
List<? extends List<?>> theReallyNotSureList;
// these are fine
theReallyNotSureList = theAnyList;
theReallyNotSureList = theNotSureList;
// but we are prevented from doing this
theReallyNotSureList.add( new Vector<Float>() );
// as well as this
theReallyNotSureList.get(0).add( "a String" );
我们失去了信息
二者都
关于
theReallyNotSureList
以及
元素的元素类型
它在里面。
分配
任何类型的
清单持有清单
去吧……)
所以要分解它:
// â applies to the "outer" List
// â¼
List<? extends List<?>>
// â²
// â applies to the "inner" List
地图
// â Map K argument
// â â Map V argument
// â¼ â¼
Map<?, ? extends List<?>>
// â²
// â List E argument
为什么?
是必要的
"concrete"
泛型类型具有
,也就是说,
List<Dog>
is not a subtype of
List<Animal>
即使
class Dog extends Animal
协方差
,也就是说,
列表<狗>
是
一种
List<? extends Animal>
.
// Dog is a subtype of Animal
class Animal {}
class Dog extends Animal {}
// List<Dog> is a subtype of List<? extends Animal>
List<? extends Animal> a = new ArrayList<Dog>();
// all parameterized Lists are subtypes of List<?>
List<?> b = a;
所以把这些想法应用到一个嵌套的
列表
-
Map<Integer, List<String>>
接受
列表<字符串>
作为一种价值观。
-
Map<?, List<?>>
接受
任何
作为一种价值观。
-
地图<整数,列表<字符串>&燃气轮机;
和
是具有不同语义的不同类型。
-
一个不能转换为另一个,以防止我们以不安全的方式进行修改。
-
Map<?, ? extends List<?>>
Map<?, ? extends List<?>>
â± â²
Map<?, List<?>> Map<Integer, List<String>>
泛型方法的工作原理
通过在方法上使用类型参数,我们可以断言
列表
static <E> void test(Map<?, List<E>> m) {}
这个特别声明要求
列表
他在房间里
地图
具有相同的元素类型。我们不知道那是什么类型的
是
,但我们可以抽象地使用它。这使我们能够执行“盲”操作。
例如,这种声明可能对某种积累有用:
static <E> List<E> test(Map<?, List<E>> m) {
List<E> result = new ArrayList<E>();
for(List<E> value : m.values()) {
result.addAll(value);
}
return result;
}
put
在
m
密钥类型
价值观
因为我们知道他们都是
列表
同样的
元素类型
只是为了好玩
列表
:
static <E> void test(Map<?, ? extends List<E>> m) {}
我们可以用类似
Map<Integer, ArrayList<String>>
E
.
static <K, E, L extends List<E>> void(Map<K, L> m) {
for(K key : m.keySet()) {
L list = m.get(key);
for(E element : list) {
// ...
}
}
}
米
以及里面的一切。
另请参见