他们所约定的含义如下所示:
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
?表示不确定的 java 类型
public static void printList(List<?> list) {
for (Object o : list) {
/* 方法体 */
}
}
注:因为你不知道集合是哪种类型,所以只能够对集合进行读操作,并且只能把读取到的元素当成 Object 实例来对待。可参考:《Java泛型(类型擦除)》
在阅读下面的内容之前我们需要了解以下知识。
——预备知识
协变:能在使用父类型的场景中改用子类型
逆变:能在使用子类型的场景中改用父类型
不变:不能做到以上两点
更加详细的解释可参考文章:《几个搞不太懂的术语:逆变、协变、不变》
数组的协变性可参考文章:《数组的协变性》
在知道上述技术术语的解释后,下面通过具有协变性质的数组进一步引出为什么泛型要设计成非协变的。
/* Person是Man和Woman的父类 */
Person[] person = new Man[4];
person[0] = new Man();
person[1] = new Woman();
由于数组是协变的,而Man
和Woman
是Person
的子类,那么Person[ ]
就可以接收Man[ ]
和Woman[ ]
,换句话说就是基础类型具备父子关系,那么对应的容器类型也具备,因此这段代码将会通过编译,但是person[0]
实际上是引用了Man
,可是Man
IS-NOT_A Woman
。这样就会产生类型混乱,当代码运行时就会抛出ArrayStoreException
异常。
List extends A> 代表的是一个可以持有 A及其子类(如B和C)的实例的List集合。
public static double sum(List<? extends Number> list) {
double sum = 0.0;
for (Number i : list) {
sum += i.doubleValue();
}
return sum;
}
-------------测试---------------
List<Integer> list1 = Arrays.asList(4, 5, 6, 7);
System.out.println("Total sum is:" + GenericDemo.sum(list1));
List<Double> list2 = Arrays.asList(4.1, 5.1, 6.1);
System.out.print("Total sum is:" + GenericDemo.sum(list2));
-------------输出---------------
Total sum is:22.0
Total sum is:15.299999999999999
当您想要放宽对变量的限制时可以使用该通配符,例如要编写一个适用于 List
、List
和 List
的方法,则可以使用上限通配符执行此操作。
对于上限通配符需要注意的一点就是使用上限通配符只能从结构中获取值而不能将值放入结构中。例如
(同样假设Person
类是Man
和Woman
的父类)对于下面的方法,当我们将List
、List
和List
类型的变量传入方法中时是完全合法的,此时从集合里读出元素并把它强制转换为Person
是安全的,但是我们不能给传入的list插入任何元素,因为你不知道list中是什么元素(如不能给List
中插入Woman
)。
public void show(List<? extends Person> list){
for(Person a : list){
System.out.println(a.sex());
}
}
public static void printOnlyIntegerClassOrSuperClass(List<? super Integer> list) {
System.out.println(list);
}
-------------测试---------------
List<Integer> list1 = Arrays.asList(4, 5, 6, 7);
GenericDemo.printOnlyIntegerClassOrSuperClass(list1);
-------------输出---------------
[4, 5, 6, 7]
对于下限通配符同样需要注意的一点就是使用下限通配符只能将值放入结构中或者将读取结果转换为Object。同样观察下面的例子我知道list中要么是Person
要么是Person
的父类,而Man
和Woman
继承与Person
那么Person
的父类也就是Man
和Woman
的父类,因此我们可以向其中添加Person
以及Person
的子类(Man
和Woman
)是合法的。
public void show(List<? super Person> list){
list.add(new Person());
list.add(new Man());
list.add(new Woman());
}
在使用上述通配符时:
对于泛型存在限制的原因可参考《Java泛型(类型擦除)》
end