关键词
伪泛型
针对引用的检查
类型擦除
协变
多态的冲突
介绍
java泛型是伪泛型,java文件编译时会进行类型擦除这样生成的class文件不再包含任何泛型信息。
泛型价值:增加约束,让代码优雅(无需显式的类型转化)。
原始类型
1 2 3 4 5 6 7 8 9 10 11 12 abstract class Math<T> { abstract T max(T t1, T t2); } -----字节码------ abstract max(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; abstract class Math2<T extends Number> { abstract T max(T t1, T t2); } ------字节码----- abstract max(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
Object 或者 Number 就是T 的原始类型。这是类型擦除的基础思路,也由此产生了多态冲突问题。
类型擦除
文字描述比较枯燥难懂,以下通过3个示例来介绍,类型擦除、针对引用有效、为什么叫做 伪泛型。
示例1
1 2 3 4 5 6 7 8 9 10 11 12 // 携带泛型的对象对应字节码完全一致。 List<String> strList = new ArrayList<String>(); List intList = new ArrayList(); ---------字节码------------ NEW java/util/ArrayList DUP INVOKESPECIAL java/util/ArrayList.<init> ()V ASTORE 1 NEW java/util/ArrayList DUP INVOKESPECIAL java/util/ArrayList.<init> ()V ASTORE 2
示例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /** * 约定泛型的list,可以通过反射成功添加 int类型数据进去,通过反射可以正常读取,直接读取时会提示类型转化异常。 */ @Test public void typeErasure() { try { List<String> strList = new ArrayList(); strList.getClass().getMethod("add", Object.class).invoke(strList, 123); System.out.println("strList'size :" + strList.size()); System.out.println(strList.getClass().getMethod("get", int.class).invoke(strList, 0)); System.out.println(strList.get(Integer.valueOf(0))); } catch (Exception e) { e.printStackTrace(); } }
示例3
1 2 3 4 泛型针对引用有效。 List<String> strList1 = new ArrayList();//有效果(阿里巴巴规范也提倡这么写) List<String> strList2 = new ArrayList<String>();//效果同上面 List strList3 = new ArrayList<String>();//无效果
由于 泛型仅仅生存到编译时期,所以称之为 伪泛型。
多态的冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 abstract class Math<T> { abstract T max(T t1, T t2); } -------二进制码--------- abstract max(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; class IntMath extends Math<Integer> { @Override Integer max(Integer t1, Integer t2) { return java.lang.Math.max(t1, t2); } } --------二进制码-------- max(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; synthetic bridge max(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; L0 LINENUMBER 28 L0 ALOAD 0 ALOAD 1 CHECKCAST java/lang/Integer ALOAD 2 CHECKCAST java/lang/Integer INVOKEVIRTUAL com/hardydou/jmm/IntMath.max (Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer; ARETURN
泛型子类重写不是简单的重写,而是重载+重写
实战
基本类型不可以作为泛型
List<int> list;//编译不通过
泛型不可以被实例化
1 2 3 4 class A<T> { T t=new T();//不可以被直接实例化 ....... }
泛型使用instanceOf
1 2 3 4 5 6 7 List<String> list1 = new ArrayList<>(); //可以 boolean s1 = (list1 instanceof ArrayList<?>); boolean s3 = (list1 instanceof ArrayList); //编译报错 boolean s2 = (list1 instanceof ArrayList<String>);