今天和大家一起探讨如何创建一个泛型数组?
可能会有人说,这还不简单,直接 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 对象,获取被泛型擦除的具体类型。
本次分享至此结束,希望本文对你有所帮助,若能点亮下方的点赞按钮,在下感激不尽,谢谢您的【精神支持】。
若有任何疑问,也欢迎与我交流,若存在不足之处,也欢迎各位指正!