一、泛型的几个术语:
对于List<User> 和List<T>
整个List<T> 泛型类型
List<T>中的T 类型参数
整个List<User> 参数化类型
List<User>中的User 实际类型参数
<> 为 typeof
注意的地方:
参数化类型没有实际类型参数的继承关系!
List<Integer> list = new List<Object>(); //报错,反之亦然
参数化类型与原始类型的兼容性:
- 参数化类型可以引用一个原始类型的对象,编译时编译器会报警告,例如:Collection<String> c = new Vector();
- 原始类型可以引用一个参数化类型的对象,编译时编译器会报警告,例如:Collection c = new Vector<String>();
二、泛型的通配符
泛型引用和创建两端泛型变量必须相同
重载时只有泛型变量无法完成,因为泛型擦除后参数是相同的
此问题主要是由于兼容老版本引起的,使用的是假的泛型
于是,通配符就出现了 List<? extends Object> list,这里的问号?就是通配符
通配符只能出现在引用一端,而new那端不能用,只能用在左边,而不能用在右边
?表示一个不确定的值,只会在调用时进行确定,当然可以简写成List<?>
通配符的局限就出来了:
当使用通配符时,对泛型类中参数为泛型的方法起了副作用:无法使用此方法(如无法使用add()方法等)
返回值为泛型类型时也无法使用
好处就是形参带泛型时可以更加通用
?通配符还有边界的概念(上下边界,父类子类边界)
如:List<? extends Number> list 只能传递Number及其子类型
List<? super Number> list2 只能传递Number及其父类型
也就是分为三种:无界通配、子类通配、父类通配
三、自定义泛型接口、类、方法
泛型类:类名后面加<T>
class Box<T>{ }
泛型方法:返回值前加<T>
public <T> void box(T t){ }
四、继承关系
定义一个父类:
package cn.test; public class Father<T> { T text;//成员变量 //get方法 public T getText() { return text; } //无参构造器 public Father() { } //有参构造器 public Father(T text) { super(); this.text = text; } }
1.最正常的继承,子类的泛型参数和父类的参数是一致的
public class Child<T> extends Father<T>{
2.子类增加了一个泛型参数,父类的泛型参数不能遗漏,所以仍然要定义
public class Child<T,E> extends Father<T>{
3.继承时不指定父类的泛型参数,会有警告信息:
Father is a raw type. References to generic type Father<T> should be parameterized
public class Child extends Father{
4.继承时指定父类的泛型参数,子类就不用再写泛型参数,如果写了,那就是子类自己新增加的
public class Child extends Father<String>{ public Child(){ super("我是子类"); } public void print(){ System.out.println(text); } }
调用如上print方法正常输出 我是子类
5. 父类指定了类型,子类又增加了,这时子类的只是新增加的泛型参数,跟父类没有关系
public class Child<E> extends Father<String>{