1. 泛型类型变量不能使用基本数据类型
比如没有ArrayList,只有ArrayList.当类型擦除后,ArrayList的原始类中的类型变量(T)替换成Object,但Object类型不能存放int值。
public static void scene02() {
ArrayList<int> ints = new ArrayList<>();//不可以,会报错
ArrayList<Integer> integers = new ArrayList<>();//可以,不会报错
}
2. 不能使用instanceof运算符
因为擦除后,ArrayList只剩下原始类型,泛型信息String不存在了,所以没法使用instanceof
public static void scene03() {
ArrayList<String> strings = new ArrayList<>();
if(strings instanceof ArrayList<?>){
} //使用ArrayList<?>可以
if(strings instanceof ArrayList<String>){
} //不可以,因为擦除ArrayList<String>后String丢失了
}
3. 泛型在静态方法和静态类中的问题
因为泛型类中的泛型参数的实例化是在定义泛型类型对象的时候指定的,而静态成员是不需要使用对象来调用的,所有对象都没创建,如何确定这个泛型参数是什么
public class Test2<T> {
public static T one; //报错,因为泛型参数是要创建对象时确定
public static T test(T t){
} //报错,因为泛型参数是要创建对象时确定
//这里的泛型方法可以,因为这是泛型方法,此T非test2中的T
public static <T> T test01(T t){
return t;}
}
4. 泛型类型中的方法冲突
因为擦除后两个equals方法变成一样的了
//'equals(T)' clashes with 'equals(Object)'; both methods have same erasure
public boolean equals(T t) {
//会报错
return true;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
5. 没法创建泛型实例
因为类型不确定
class Test2 {
//你无法创建一个类型参数的实例。例如,下面代码就会引起编译时错误:
public static <E> void append(List<E> list){
E elem = new E(); // compile-time error Type parameter 'E' cannot be instantiated directly
list.add(elem);
}
//通过反射创建一个参数化类型的实例
public static <E> void append(List<E> list, Class<E> cls) throws Exception{
E elem = cls.newInstance(); //OK
list.add(elem);
}
}
6. 没有泛型数组
因为数组是协变,擦除后就没法满足数组协变的原则
public static <T> void scene04(){
// Plate<Apple>[] applePlates = new Plate<Apple>[10];//不允许
// T[] arr = new T[10]; //不允许
Apple[] apples = new Apple[10];
Fruit[] fruits = new Fruit[10];
System.out.println(apples.getClass());
//class [Lgeneric.Apple;
System.out.println(fruits.getClass());
//class [Lgeneric.Fruit;
fruits = apples;
//fruits[0] = new Banana(); //编译通过,运行报ArrayStoreException
//Fruit是Apple的父类,Fruit[]是Apple[]的父类,这就是数组的协变
//如果加入泛型后,由于擦除机制,运行时将无法知道数组的类型
Plate<?>[] plates = new Plate<?>[10];//这是可以的
}
Apple extends Fruit
Apple[] 父类是 Fruit[] (数组的协变)
擦除后不知道什么类型就没法协变