# 什么是泛型擦除
- 怎么理解泛型擦除
Java 的泛型机制其实是伪泛型,因为它只作用于 Java 程序
编译
期间,(就是在你写代码的时候起作用); 在运行期间并不存在 < br > 编译器在编译期间会动态的将泛型T
擦除为 Object, 或者将T extends xxxClass
擦除为其限定类型xxxClass
# 举例说明
在我们创建不同类型的 List 时候,会放入不同的泛型,在进行 add 的时候,可以限制 add 的类型,但是它们的类在最终比较的时候确是相同的,这就是泛型擦除造成的
ArrayList<String> stringlist = new ArrayList<>(); | |
ArrayList<Integer> integerlist = new ArrayList<>(); | |
// 输出结果为:true | |
System.out.println(stringlist.getClass() == integerlist.getClass()); | |
// 输出结果为:class java.util.ArrayList | |
System.out.println(stringlist.getClass()); | |
// 输出结果为:class java.util.ArrayList | |
System.out.println(integerlist.getClass()); |
但是 add 的类型限制也并不是绝对的,我们在它运行时 (反射), 进行动态的传参,可以做到往 integerlist
中添加 String 类型的代码
ArrayList<Integer> integerlist = new ArrayList<>(); | |
integerlist.add(1); | |
// 通过反射将 integerlist 的集合对象中添加一个 Object 类型的元素,这里并不能添加什么 String 类型什么包装类的会报错的,因为 add 方法只能添加 Object 类型的元素 | |
Method add = integerlist.getClass().getDeclaredMethod("add",Object.class); | |
// 调用方法传入调用对象并进行赋值 | |
add.invoke(integerlist, "abc"); | |
// 打印结果 | |
System.out.println(integerlist); |
以上代码都能证明,泛型是在运行期间被擦除的
另外以下写法会报错,也是因为泛型擦除的存在,报错为 两种方法具有相同的擦除
public void run(ArrayList<String> list){ | |
} | |
public void run(ArrayList<Integer> list){ | |
} |
# 既然有泛型擦除,为什么还要使用呢,用 Object 代替不行?
- 使用泛型可以在编译期间进行类型检测,尽早发现问题
- 使用
Object
类型需要手动强制类型转换,而用泛型则可以节省了这个操作可以有效避免classCastException
代码可读性更高,出错率更低 - 提升性能,编译完成后,基本就确定了类型,节省了强制类型转换带来的性能消耗