2021.6.15:泛型与反射、类型擦除

Java的部分反射API也是泛型。

例如:Class<T>就是泛型:

//compile warninig:
Class cls = String.class;
String str = (String) cls.newInstance();

//no warning:
Class <String> cls = String.class;
String str = cls.newInstance();

调用ClassgetSuperclass()方法返回的Class类型Class<? super T>

Class<? super String> sup = String.class.getSuperclass();

构造方法Constructor<T>也是泛型:

Class <Integer> cls = Integer.class;
Constructor <Integer> cons = cls.getConstructor(int.class);
Integer i = cons.newInstance(123);

我们可以声明带泛型的数组,但是不能用new操作符创建带泛型数组

Pair <String> [] ps = null; //ok
Pair <String> [] ps = new Pair<String> [2];//error

必须通过强制转型实现带泛型的数组:

@SuppressWarnings("unchecked")
Pair<String>[] ps = (Pair<String>[]) new Pair[2];

 

一个错误使用泛型数组的例子:

Pair [] arr = new Pair[2];
Pair <String> [] ps = (Pair<String>[]) arr; //错误根源,这两个变量实际指向同一个数组

ps[0] = new Pair<String>("a","b");
arr[1] = new Pair<Integer>(1,2);

//ClassCastException:
Pair<String> p = ps[1];
String s = p.getFirst();

使用泛型数组时要小心,因为数组在运行时没有泛型的,编译器可以强制检查变量ps,因为它的类型是泛型数组

但是编译器不会检查变量arr,因为它不是泛型数组。因为这两个变量实际上指向同一个数组,所以,操作arr导致从ps获取元素报错

 

要安全的使用泛型数组,必须扔掉arr引用

@SuppressWarnings("unchecked")
Pair <String>[] ps = (Pair<String>[]) new Pair[2];

上边的代码中,由于拿不到原始数组的引用,就只能对泛型数组ps进行操作,这种操作就是安全的。

带泛型的数组实际上是编译器的类型擦除

Pair [] arr = new Pair[2];
Pair <String> [] ps = (Pair<String>[]) arr;

System.out.println(ps.getClass() == Pair[].class);//true

String s1 = (String) arr[0].getFirst();
String s2 = ps[0].getFirst();

所以我们不能直接创建泛型数组T[ ],因为擦拭后代码变为Object[ ]

//compile error:
public class Abc<T> {
    T[] createArray() {
        return new T[5];
    }
}

必须借助Class<T>来创建泛型数组:

T[] createArray(Class<T> cls){
    return (T[]) Array.newInstance(cls , 5);
}

我们还可以利用可变参数创建泛型数组T[ ]

public class ArrayHelper{
    @SafeVarargs
    static <T> T[] asArray(T ... objs){
        return objs;
    }
}

String [] ss = ArrayHelper.asArray("a","b","c");
Integer[] ns = ArrayHelper.asArray(1,2,3);

谨慎使用泛型可变参数

在上边的例子中,我们看到,通过:

static <T> T[] asArray(T ... objs){
    return objs;
}

似乎可以安全地创建一个泛型数组,但实际上,这种方法非常危险。

如果在方法内部创建了泛型数组,最好不要将它返回给外部使用

posted @ 2021-06-15 15:03  ShineLe  阅读(43)  评论(0)    收藏  举报