# 什么是泛型擦除

  • 怎么理解泛型擦除

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);

以上代码都能证明,泛型是在运行期间被擦除的

另外以下写法会报错,也是因为泛型擦除的存在,报错为 两种方法具有相同的擦除

image_2022-11-27-21-21-22

public void run(ArrayList<String> list){
    }
    public void run(ArrayList<Integer> list){
    }

# 既然有泛型擦除,为什么还要使用呢,用 Object 代替不行?

  1. 使用泛型可以在编译期间进行类型检测,尽早发现问题
  2. 使用 Object 类型需要手动强制类型转换,而用泛型则可以节省了这个操作可以有效避免 classCastException 代码可读性更高,出错率更低
  3. 提升性能,编译完成后,基本就确定了类型,节省了强制类型转换带来的性能消耗