《Java架构筑基》从Java基础讲起——泛型擦除
就是指编译器编译带类型说明的集合时会去掉“类型”信息
二. 泛型擦除案例泛型是提供给javac编译器使用的,限定集合的输入类型,编译器编译带类型说明的集合时会去掉“类型”信息。
public class GenericTest { public static void main(String[] args) { new GenericTest().testType(); } public void testType(){ ArrayList<Integer> collection1 = new ArrayList<Integer>(); ArrayList<String> collection2= new ArrayList<String>(); System.out.println(collection1.getClass()==collection2.getClass()); //两者class类型一样,即字节码一致 System.out.println(collection2.getClass().getName()); //class均为java.util.ArrayList,并无实际类型参数信息 }}
输出
truejava.util.ArrayList
为何会返回true
这是因为不管为泛型的类型形参传入哪一种类型实参,对于Java来说,它们依然被当成同一类处理,在内存中也只占用一块内存空间。从Java泛型这一概念提出的目的来看,其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。在静态方法、静态初始化块或者静态变量的声明和初始化中不允许使用类型形参。由于系统中并不会真正生成泛型类,所以instanceof运算符后不能使用泛型类。使用反射可跳过编译器,往某个泛型集合加入其它类型数据。
只有引用类型才能作为泛型方法的实际参数例子:public class GenericTest { public static void main(String[] args) { swap(new String[]{"111","222"},0,1);//编译通过 //swap(new int[]{1,2},0,1); //编译不通过,因为int不是引用类型 swap(new Integer[]{1,2},0,1);//编译通过 } /*交换数组a 的第i个和第j个元素*/ public static <T> void swap(T[]a,int i,int j){ T temp = a[i]; a[i] = a[j]; a[j] = temp; }}
但注意基本类型有时可以作为实参,因为有自动装箱和拆箱。
例子(编译通过了):public class GenericTest { public static void main(String[] args) { new GenericTest().testType(); int a = biggerOne(3,5); //int 和 double,取交为Number Number b = biggerOne(3,5.5); //String和int 取交为Object Object c = biggerOne("1",2); } //从x,y中返回y public static <T> T biggerOne(T x,T y){ return y; }}
同时,该例还表明,当实参不一致时,T取交集,即第一个共同的父类。另外,如果用Number b = biggerOne(3,5.5);改为String c = biggerOne(3,5.5);则编译报错:
Error:(17, 29) java: 不兼容的类型: 推断类型不符合上限 推断: java.lang.Number&java.lang.Comparable<? extends java.lang.Number&java.lang.Comparable<?>> 上限: java.lang.String,java.lang.Object
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。