关键词
- 伪泛型
- 针对引用的检查
- 类型擦除
- 协变
- 多态的冲突
一、介绍
java泛型是伪泛型,java文件编译时会进行类型擦除这样生成的class文件不再包含任何泛型信息。
泛型价值:增加约束,让代码优雅(无需显式的类型转化)。
二、原始类型
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
// 携带泛型的对象对应字节码完全一致。
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
/**
* 约定泛型的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
泛型针对引用有效。
List<String> strList1 = new ArrayList();//有效果(阿里巴巴规范也提倡这么写)
List<String> strList2 = new ArrayList<String>();//效果同上面
List strList3 = new ArrayList<String>();//无效果
由于 泛型仅仅生存到编译时期,所以称之为 伪泛型。
四、多态的冲突
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
泛型子类重写不是简单的重写,而是重载+重写
五、实战
5.1、基本类型不可以作为泛型
List<int> list;//编译不通过
5.2、泛型不可以被实例化
class A<T> {
T t=new T();//不可以被直接实例化
.......
}
5.2、泛型使用instanceOf
List<String> list1 = new ArrayList<>();
//可以
boolean s1 = (list1 instanceof ArrayList<?>);
boolean s3 = (list1 instanceof ArrayList);
//编译报错
boolean s2 = (list1 instanceof ArrayList<String>);