我们在上面提到了, List> 中的元素只能使用 Object 来引用, 这样作肯定时不太方便的, 不过幸运的是, Java 的泛型机制允许我们对泛型参数的类型的上界和下界做一些限制, 例如 List extends Number> 定义了泛型的上界是 Number, 即 List 中包含的元素类型是 Number 及其子类. 而 List super Number> 定义了泛型的下界, 即 List 中包含的是 Number 及其父类. 当引入了泛型参数的上界和下界后, 我们编写代码相对来说就方便了许多, 不过也引入了新的问题, 即我们在什么时候使用上界, 什么时候使用下界, 以及它们的区别和限制到底时什么? 下面我来说说我的理解.
? extends T
? extends T 描述了通配符上界, 即具体的泛型参数需要满足条件: 泛型参数必须是 T 类型或它的子类, 例如:
List extends Number> numberArray = new ArrayList(); // Number 是 Number 类型的
List extends Number> numberArray = new ArrayList(); // Integer 是 Number 的子类
List extends Number> numberArray = new ArrayList(); // Double 是 Number 的子类
上面三个操作都是合法的, 因为 ? extends Number 规定了泛型通配符的上界, 即我们实际上的泛型必须要是 Number 类型或者是它的子类, 而 Number, Integer, Double 显然都是 Number 的子类(类型相同的也可以, 即这里我们可以认为 Number 是 Number 的子类).
我们不能添加 Number 到 numberArray 中, 因为 numberArray 有可能是List 类型
我们不能添加 Integer 到 numberArray 中, 因为 numberArray 有可能是 List 类型
我们不能添加 Double 到 numberArray 中, 因为 numberArray 有可能是 List 类型
即, 我们不能添加任何对象到 List extends T> 中, 因为我们不能确定一个 List extends T> 对象实际的类型是什么, 因此就不能确定插入的元素的类型是否和这个 List 匹配. List extends T> 唯一能保证的是我们从这个 list 中读取的元素一定是一个 T 类型的.
? super T
? super T 描述了通配符下界, 即具体的泛型参数需要满足条件: 泛型参数必须是 T 类型或它的父类, 例如:
// 在这里, Integer 可以认为是 Integer 的 "父类"
List super Integer> array = new ArrayList();
// Number 是 Integer 的 父类
List super Integer> array = new ArrayList();
// Object 是 Integer 的 父类
List super Integer> array = new ArrayList();
关于读取
对于上面的例子中的 List super Integer> array 对象:
我们不能保证可以从 array 对象中读取到 Integer 类型的数据, 因为 array 可能是 List 类型的.
我们不能保证可以从 array 对象中读取到 Number 类型的数据, 因为 array 可能是 List 类型的.
Producer extends: 如果我们需要一个 List 提供类型为 T 的数据(即希望从 List 中读取 T 类型的数据), 那么我们需要使用 ? extends T, 例如 List extends Integer>. 但是我们不能向这个 List 添加数据.
Consumer Super: 如果我们需要一个 List 来消费 T 类型的数据(即希望将 T 类型的数据写入 List 中), 那么我们需要使用 ? super T, 例如 List super Integer>. 但是这个 List 不能保证从它读取的数据的类型.
如果我们既希望读取, 也希望写入, 那么我们就必须明确地声明泛型参数的类型, 例如 List.
例子:
public class Collections {
public static void copy(List super T> dest, List extends T> src)
{
for (int i=0; i
上面的例子是一个拷贝数据的代码, src 是 List extends T> 类型的, 因此它可以读取出 T 类型的数据(读取的数据类型是 T 或是 T 的子类, 但是我们不能确切的知道它是什么类型, 唯一能确定的是读取的类型 is instance of T), , dest 是 List super T> 类型的, 因此它可以写入 T 类型或其子类的数据.
摘要:定义具有一个或多个类型变量的类,称之为泛型类。泛型类的继承创建对象的两种方式错误方式错误原因继承了泛型类,但并不是泛型类,所以不能这样创建对象。同样是泛型类,它的父类也是泛型类,它传递的是常量。
泛型类
public class A {
//在成员变量上使用泛型
private T t;
public A() {}
//构造参数类型上...