泛型
约 730 字大约 2 分钟
2025-06-29
工作原理
类型擦除
Java 中的泛型是「伪泛型」,其实现依靠 Java 中所有类的父类——Object 泛型的声明与使用形如
public class ArrayList<T> {}
ArratList<Integer> list = new ArrayList<>();这是一个指定了只能存放整型的集合,对于list添加其他类型的元素会触发编译时错误 但如果运行以下代码
ArratList<Integer> list1 = new ArrayList<>();
ArratList<String> list2 = new ArrayList<>();
System.out.print(list1.getClass() == list2.getClass());输出结果为 true
这是因为泛型只依靠编译时进行检查,而在运行时所有的泛型都被擦除为Object类型
上下界
//Lev 1
class Food{}
//Lev 2
class Fruit extends Food{}
class Meat extends Food{}
//Lev 3
class Apple extends Fruit{}
class Banana extends Fruit{}
class Pork extends Meat{}
class Beef extends Meat{}
//Lev 4
class RedApple extends Apple{}
class GreenApple extends Apple{}上界 (Extends)
该泛型只接受继承(Extends)了某个类的元素,即只能存储上界元素的子类 如:Plate<? extends Fruit>
对于上界,编译器只知道其中存放的类型为 Fruit 的子类,但究竟是 Apple, Banana 还是红绿苹果,不知道,子类(已有的泛型)对象不能指向父类(将要添加的对象)的引用,因此不可向其中添加数据 同样的,父类对象指向子类的引用,可以当作Fruit类读取
List<Integer> l1 = new ArrayList<>();
l1.add(1);
l1.add(2);
l1.add(3);
List<? extends Number> l2;
l2 = l1; // 能够传入
l2.add(1); // 不能向内添加值,因为编译器不知道 l2 中的泛型整型还是浮点型还是其他,编译时异常
l2.add(null); // 任何类型都能为 null,可以理解为所有类的子类(?)
Number i = l2.get(0); // 可以以上界类型读取其中的值,因为其中能存储的值肯定为上界或上界的子类
Integer i = l2.get(0); // 编译器无法保证 l2 中的类型是否为 Integer,编译时异常下界(Super)
与上界相反,该泛型只接受某个类型的基类的类 如:Plate<? super Fruit>
对于下界,编译器知道其中的泛型至少为 Fruit 的超类(父类),父类(已有的泛型)对象指向子类(添加的对象)引用,因此能够向内添加数据 但因为不知道其上界,子类(获取出的对象)对象无法指向父类(已有的泛型)的引用,故不能获取其中的数据
List<Integer> l1 = new ArrayList<>();
l1.add(1);
l1.add(2);
l1.add(3);
List<? super Integer> l2;
l2 = l1; // 能够传入
Number i1 = 1;
Integer i2 = 1;
l2.add(i1); // Integer(子类)无法指向 Number(父类) 的引用,编译时异常
l2.add(i2); // Number
Number i = l2.get(0); // l2 中的类型为 Integer 或 Integer 的父类,编译器不能判断 Number 一定不为 l2 中的子类,编译时异常
Object i4 = l2.get(0); // Object 为所有类的父类,它是个例外