泛型数组需要怎么建立? --《JAVA编程思想》 54

今天和大家一起探讨如何创建一个泛型数组?

可能会有人说,这还不简单,直接 T[] array = new T[size],不就可以了嘛?

很可惜,编译器会提示泛型无法直接被实例化。
在这里插入图片描述
那我们换个思路,先创建一个 Object 数组,再将它转换成对应的泛型,是不是就可以了呢?

public class GenericArrayTest<T> {
    
    

    private T[] array;

    public GenericArrayTest(int size) {
    
    
        this.array = (T[]) new Object[size];
    }

    public T[] getArray() {
    
    
        return array;
    }

    public void put(int index, T element) {
    
    
        array[index] = element;
        System.out.println("下标:"+index+",存入元素:"+element);        
    }

    public T get(int index) {
    
    
        System.out.println("获取下标:" + index + " 元素:" + array[index]);
        return array[index];
    }

    public static void main(String[] args) {
    
    
        GenericArrayTest<String> genericArrayTest = new GenericArrayTest<String>(10);
        String[] array = genericArrayTest.getArray();
    }

}

上述这段代码虽然通过了编译,但实际却是无法运行的。运行代码会抛出类型转换异常,因为泛型擦除的影响,所有未定义边界的泛型参数默认被擦除成 Object,又因数组的数据结构要求在创建时确定其存储的数据的类型,且后续无法变更其存储的数据类型,故 Object[]无法将转换为 String[](泛型擦除的介绍可参考泛型擦除是什么?)。

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
	at mtn.baymax.charpter15.GenericArrayTest.main(GenericArrayTest.java:40)

为了验证 T[] 在运行期间是 Object[],我们通过反射绕过编译器的限制,再调用 put() 方法,可以成功将任意类型放入 GenericArrayTest 中的数组。

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException,
            IllegalAccessException {
    
    
        GenericArrayTest<String> genericArrayTest = new GenericArrayTest<String>(10);
        Class clazz = genericArrayTest.getClass();
        Method put = clazz.getMethod("put", int.class, Object.class);
        put.invoke(genericArrayTest, 1,123);
        put.invoke(genericArrayTest, 1,4.5F);
        put.invoke(genericArrayTest, 1,5.24D);
    }
下标:1,存入元素:123
下标:1,存入元素:4.5
下标:1,存入元素:5.24

那么,泛型数组到底该如何创建呢?

虽然泛型会在运行期间被转换为 Object ,但是我们可以将 Class 对象传入构造方法,再通过 Class 恢复具体的类型,从而创建对应的数组,代码如下所示。

public class GenericArrayTest<T> {
    
    

    private T[] array;

    public GenericArrayTest(Class<T> tClass, int size) {
    
    
        this.array = (T[]) Array.newInstance(tClass, size);
    }

    public T[] getArray() {
    
    
        return array;
    }

    public void put(int index, T element) {
    
    
        array[index] = element;
        System.out.println("下标:" + index + ",存入元素:" + element);
    }

    public T get(int index) {
    
    
        System.out.println("获取下标:" + index + " 元素:" + array[index]);
        return array[index];
    }

    public static void main(String[] args) {
    
    
        GenericArrayTest<String> genericArrayTest = new GenericArrayTest<String>(String.class, 10);
        genericArrayTest.put(0, "a");
        genericArrayTest.put(1, "b");
        genericArrayTest.put(2, "c");
        String[] array = genericArrayTest.getArray();
        for (int i = 0; i < array.length; i++) {
    
    
            genericArrayTest.get(i);
        }
    }

}
下标:0,存入元素:a
下标:1,存入元素:b
下标:2,存入元素:c
获取下标:0 元素:a
获取下标:1 元素:b
获取下标:2 元素:c
获取下标:3 元素:null
获取下标:4 元素:null
获取下标:5 元素:null
获取下标:6 元素:null
获取下标:7 元素:null
获取下标:8 元素:null
获取下标:9 元素:null

小结

创建泛型数组需要知晓以下几点:

1.未定义边界的泛型在运行期间都会被擦除为 Object。

2.数组的类型在创建完成后,无法进行变更 。

3.可通过在泛型中传入 Class 对象,获取被泛型擦除的具体类型。

本次分享至此结束,希望本文对你有所帮助,若能点亮下方的点赞按钮,在下感激不尽,谢谢您的【精神支持】。

若有任何疑问,也欢迎与我交流,若存在不足之处,也欢迎各位指正!

猜你喜欢

转载自blog.csdn.net/BaymaxCS/article/details/120381690
54