java 泛型数组初始化_Java 泛型 泛型数组

直接创建泛型数组不能通过编译,而转型对象数组通过编译但是不能在JVM运行

69c5a8ac3fa60e0848d784a6dd461da6.png

69c5a8ac3fa60e0848d784a6dd461da6.png public class ArrayOfGeneric{

static Generic[] gia;

@SupperssWarnings("unchecked")

public static void main(String[] args){

gia = (Generic[])new Generic[100]; // 通过类型转换匿名对象

//! gia[0] = new Object(); //编译不通过,不能(直接)创建泛型数组实例

}

}

69c5a8ac3fa60e0848d784a6dd461da6.png

69c5a8ac3fa60e0848d784a6dd461da6.png

问题在于数组将跟踪他们的实际类型,而这个类型是在数组被创建时确定的,因此,即使gia已经被转型为Generic[],但这个信息只存在于编译期(并且如果没有@SuppressWarning("unchecked")注解,将得到这个转型的警告)。在运行时,它仍旧是Object数组

因此,成功创建泛型数组的唯一方式就是创建一个被擦出类型的新数组,然后对其转型(而且是在运行时转型)

直接对整个数组强制转型,在编译时依旧会被擦除掉类型!所以应该在运行时转型,而这时最好的办法就是使用一个泛型数组包装器,维护一个原始类型的数组,通过数组入口方法进行元素编译期的类型安全检测(对应返回值)和强制类型转换(对于运行时不重要),从而保证类型安全。

对整个数组强制转型的例子(错误方法)

69c5a8ac3fa60e0848d784a6dd461da6.png

69c5a8ac3fa60e0848d784a6dd461da6.png public class GenericArray {

private T[] array;

@SupperessWarning("unchecked")

public GenericArray(int sz) {

array = (T[]) new Object[sz];

}

public void put(int index, T item) {

array[index] = item;

}

public T get(int index) { return array[index]; }

public T[] rep() { return array; } //应该在运行时出口做文章

public static void main (String[] args){

GenericArray gai = new GenericArray(10);

// Integer[] ia = gai.rep(); //ClassCastException

Object[] oa = gai.rep(); //只能返回对象数组类型为Object[]

69c5a8ac3fa60e0848d784a6dd461da6.png

69c5a8ac3fa60e0848d784a6dd461da6.png

实际的运行时对象数组是Object[],而实际的运行时数组对象可能是T类型。

因此,应该在运行时,数组对象的出口做转型输出,入口方法在编译期已实现类型安全,所以出口方法可以放心强制类型转换,保证成功。如下

69c5a8ac3fa60e0848d784a6dd461da6.png

69c5a8ac3fa60e0848d784a6dd461da6.png public class GenericArray2 {

private Object[] array; //维护Object[]类型数组

@SupperessWarning("unchecked")

public GenericArray2(int sz) {

array = new Object[sz];

}

public void put(int index, T item) {

array[index] = item;

}

public T get(int index) { return (T)array[index]; }//数组对象出口强转

public T[] rep() { return (T[])array; } //运行时无论怎样都是Object[]类型

public static void main (String[] args){

GenericArray gai = new GenericArray(10);

// Integer[] ia = gai.rep(); //依旧ClassCastException

Object[] oa = gai.rep(); //只能返回对象数组类型为Object[]

gai.put(0,11);

System.out.println(gai.get(0)); // 11 ,出口成功转型

}

}

69c5a8ac3fa60e0848d784a6dd461da6.png

69c5a8ac3fa60e0848d784a6dd461da6.png

通过反射在运行时构出实际类型为type[]的对象数组,避免了类型擦除,从而转换成功,无ClassCastException

69c5a8ac3fa60e0848d784a6dd461da6.png

69c5a8ac3fa60e0848d784a6dd461da6.png

import java.lang.reflect.*;

public class GenericArrayWithTypeToken {

private T[] array;

@SuppressWarning("unchecked")

public GenericArrayWithTypeToken(Class type, int sz) {

array = (T[]) Array.newInstance(type, sz);//通过反射在运行时构出实际类型为type[]的对象数组,避免了类型擦除,从而转换成功,无ClassCastException

}

public void put(int index, T item){

array[index] = item;

}

public T get(int index) { return array[index]; }

public T[] rep() { return array; } //能成功返回了~

public static void main(String[] args) {

GenericArrayWithTypeToken gawtt = new GenericArrayWithTypeToken<>(Integer.class, 10);

Integer[] ia = gawtt.rep(); //能成功返回了!

}

}

结论

不能(直接)创建泛型数组

泛型数组实际的运行时对象数组只能是原始类型( T[]为Object[],Pair[]为Pair[] ),而实际的运行时数组对象可能是T类型( 虽然运行时会擦除成原始类型 )

一般解决方案:(泛型数组包装器):使用ArrayList收集泛型数组对象的对象元素,如ArrayList、ArrayList>

将获得数组的行为,以及由泛型提供的编译期的类型安全

69c5a8ac3fa60e0848d784a6dd461da6.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值