什么是类型擦除
Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除。Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。
问1:Java类型擦除是什么过程出现的?
Java泛型编译过程会擦除掉泛型信息。
/*** 比较两个ArrayList的类型比较* 1) 第一个ArrayList是ArrayList<String>,第二个是ArrayList<Integer>* 实际运行时获取的类型都是java.util.ArrayList** @author zhouronghua* @time 2022/1/10 4:15 下午*/@Testpublic void testGenericTypeCompare() {System.out.println("测试泛型类比较");// 第一个是字符串ArrayListArrayList<String> list1 = new ArrayList<>();list1.add("One");list1.add("Two");// 第二个是整形ArrayListArrayList<Integer> list2 = new ArrayList<>();list2.add(100);list2.add(200);// 比较两个ArrayList类型System.out.println("ArrayList Type compare: " + (list1.getClass() == list2.getClass()));// java.util.ArrayListSystem.out.println("ArrayList<String> Type: " + list1.getClass());// java.util.ArrayListSystem.out.println("ArrayList<Integer> Type: " + list2.getClass());}
编译后的类型进行了擦除,都是ArrayList,限定类型都已经擦除了。
我们通过查看字节码,就可以清晰的看到ArrayList的类型限定擦除了。添加元素的时候,
对象类型使用的是Object

2.类型擦除后保留的原始类型
原始类型 就是擦除去了泛型信息,最后在字节码中的类型变量的真正类型,无论何时定义一个泛型,相应的原始类型都会被自动提供,类型变量擦除,并使用其限定类型(无限定的变量用Object)替换。
问2:是否能够通过instanceof查询ArrayList的类限定类型(泛型信息)?
不能。
2.Java协变和逆变
因为泛型类型编译过程中会发生类型擦除,那么怎么将子类的发行模板的对象,传递给父类的泛型模板使用。
例如:Integer集成Number,根据里氏替代原则:
Number number = new Integer(100);
对象创建的时候,可以直接将Integer对象赋值给number。
如果泛型中也希望达到这种效果,将子类的泛型赋值给父类泛型使用,怎么处理呢?可以通过通配符进行类型限定,从而实现协变
// 采用通配符实现协变
ArrayList<? extends Number> list1 = new ArrayList<Integer>();
协变:将父类保持了子类型的继承关系。通过协变实现子类型的泛型类型可以赋值给父类型泛型。
逆变:逆转了子类型的关系。将父类型泛型赋值给子类型泛型。
不变:两种关系都不满足
3.Java逆变
怎么将ArrayList<Number>赋值给ArrayList<Integer>呢?
通过? super实现逆变
ArrayList<? super Integer> list2 = new ArrayList<Number>();
参考文案:
Java泛型中的类型擦除详解 - 知乎














