本文介绍 Java 中的泛型,可与 Kotlin 基础:泛型 配合食用。
一、为什么要有泛型
效率、成本
减少样板代码的编写
二、泛型的分类
泛型类
泛型方法
三、泛型的关键字
3.1 T
T 代表任意一个类型,可以为任意字符串,一般为:T、U、S、E、K、V。
T、U、S:任意类型
E:集合的元素类型
K、V:Map 的 key 和 value 类型
3.2 ?
? 是泛型通配符,代表任意一批类型。
四、泛型类、方法的定义
4.1 泛型类的定义
class AClass ...
class AClass ... //没有 T super BClass 这种写法复制代码
在类名后声明。在该类中,可以
使用 T 作为对象的类型声明
T a;
使用 T 作为泛型类型对象的类型参数
List list;
使用 T 作为方法返回类型前的声明(所以泛型类中的泛型方法可以省去返回类型前的 )
见泛型方法的定义
4.2 泛型方法的定义
public void ...
复制代码
在方法返回类型前声明。在该方法中,可以
使用 T 作为方法的返回类型
public T...
使用 T 作为方法的参数类型
public void doSomething(T t) ...
使用 T 作为方法的泛型参数的类型参数
public void doSomething(List listT)...
五、泛型类、方法的使用
5.1 泛型实现类
指类型参数指定为一个确定的单一类,如 String 对应 AClass,它表示:
一个泛型实现类,类型参数是 String(即 AClass,使用时 T 已经被指定为 String)
5.2 通配类
5.2.1 AClass>
它代表一批泛型实现类,类型参数可以是任何类。
5.2.2 AClass extends BClass>
它代表一批泛型实现类,这批实现类的特点是:
它们的类型参数只能是 BClass 的子类。
它们自己,都是 AClass extends BClass> 的子类。
这种泛型实现类与通配类的父子关系,和泛型实现类的类型参数与通配类的类型参数的父子关系相同的关系,称为协变。
当实现类转为 AClass extends BClass> 时:
可以 get 到 BClass,因为所有实现类的类型参数的共同上界就是 BClass。
不能 set 任何值,因为不确定实现类的类型参数是哪个 BClass 的子类。
5.2.3 AClass super BClass>
它代表一批泛型实现类,这批实现类的特点是:
它们的类型参数只能是 BClass 的父类。
它们自己,都是 AClass super BClass> 的子类。
这种泛型实现类与通配类的父子关系,和泛型实现类的类型参数与通配类的类型参数的父子关系相反的关系,称为逆变。
当实现类转为 AClass super BClass> 时:
不能 get 到 BClass,只能 get 到 Object,因为所有实现类的类型参数的共同上界只有 Object。
可以 set BClass 及其子类,因为一定是覆盖真正的实现类的类型参数的。
六、代码示例
public class ChangeJava{
class A{
}
class B extends A{
}
class C extends B{
}
class AClass{
private T mT;
void set(T u){
mT = u;
}
T get(){
return mT;
}
}
private void doSomething(){
AClass aClass = new AClass<>();
AClass aClass1 = new AClass<>();
aClass1 = aClass; // 报错
AClass aClassA = new AClass<>();
AClass aClassB = new AClass<>();
AClass aClassC = new AClass<>();
AClass extends B> aClassExtendB1 = aClassA; // 报错
AClass extends B> aClassExtendB2 = aClassB;
AClass extends B> aClassExtendB3 = aClassC;
B b2 = aClassExtendB2.get(); // 可以 get 到 B
aClassExtendB2.set(); // 报错,set 任何值都会报错
AClass super B> aClassSuperB1 = aClassA;
AClass super B> aClassSuperB2 = aClassB;
AClass super B> aClassSuperB3 = aClassC; // 报错
Object o = aClassSuperB1.get(); // 只能 get 到 Object
aClassSuperB1.set(new A()); // 报错,set 除 B 及其子类以外的类型就会报错
aClassSuperB2.set(new B());
aClassSuperB2.set(new C());
}
}
复制代码