虚拟机没有泛型类型对象——所有对象都属于普通类。
类型擦除
类型擦除是一种机制,我们编写的泛型类型,最终会被编译器翻译为普通类,擦除类型变量,并替换为限定类型(无限定的变量用Object)。
编译器看到的代码:
public class Pair<T> {
private T first;
private T last;
public Pair(T first, T last) {
this.first = first;
this.last = last;
}
public T getFirst() {
return first;
}
public T getLast() {
return last;
}
}
虚拟机执行的代码:
// T没有限定,直接翻译为Object
public class Pair {
private Object first;
private Object last;
public Pair(Object first, Object last) {
this.first = first;
this.last = last;
}
public Object getFirst() {
return first;
}
public Object getLast() {
return last;
}
}
翻译泛型表达式
当我们使用泛型时,编译器会自动的进行强制类型转换:
// 编译器的语句
Pair<String> p = new Pair<>("Hello", "world");
String first = p.getFirst();
String last = p.getLast();
// 虚拟机实际执行:(因为在虚拟中进行了类型擦除)
Pair p = new Pair("Hello", "world");
String first = (String) p.getFirst();
String last = (String) p.getLast();
泛型的局限
类型参数T不能是基本类型。
例如int,因为实际类型是Object,Object类型无法持有基本类型。
运行时类型查询只适用于原始类型
虚拟机中的对象只有一个特定的非泛型类型。比如Pair<String>,在虚拟机中只有Pair。
,getClass方法总是返回原始类型:
Pair<String> stringPair = ...;
Pair<Interger> intergerPair = ...;
stringPair.getClass() ==intergerPair.getClass() // true
不能创建参数化类型的数组
不能实例化参数化类型的数组,例如:
Pair<String>[] table = new Pair<String>[10];
因为在类型擦除后,table的类型是Pair[],数组会记住它的元素类型,如果试图存储其他类型的元素,就会抛出一个Array-StoreException异常
不能实例化类型变量
不能使用像new T(...),new T[...]或T.class这样的表达式中的类型变量。
解决办法:
- Class.newInstance方法
- Supplier 函数式接口 (todo 还不理解)