Java面向对象系列[v1.0.0][泛型与数组]

泛型与数组

如果泛型代码在编译时没有爆出“未经检查的转换”警告,那么在运行时不会引发ClassCastException异常,基于这个原因,数组元素的类型不能包含泛型变量或泛型形参,除非是无上限的类型通配符;但可以声明元素类型包含泛型变量或泛型形参的数组,也就是说可以声明List形式的数组,但不能创建ArrayList[10]这样的数组对象

// 如下声明和创建是不允许的
List<String>[] ls = new ArrayList<String>[10];
// 将ls向上转型为Object[]类型的变量
Object[] oa = ls;
List<Integer> li = new ArrayList<>();
li.add(3);
// 将List<Integer>对象作为oa的第二个元素
// 如下代码不会有警告
oa[1] = li;
// 下面代码也不会有警告,但会爆ClassCastException异常
String s = ls[1].get(0);

优化代码

// 下面代码编译时有“[unchecked] 未经检查的转换”警告
List<String>[] ls = new ArrayList[10];
// 将ls向上转型为Object[]类型的变量
Object[] oa = ls;
List<Integer> li = new ArrayList<>();
li.add(3);
oa[1] = li;
// 下面代码引起ClassCastException异常
String s = lsa[1].get(0);              
List<String>[] ls = new ArrayList<String>[10];
List<String>[] ls = new ArrayList[10];

比较一下,第二种写法是被允许的只是编译时有“[unchecked] 未经检查的转换”警告,也就是说编译器并不保证这段代码是类型安全的,编译器已经报了这种警告,那么在执行的时候是可能出现异常的
Java允许创建无上限的通配符泛型数组,例如new ArrayList<?>[10],因此也可以将第一段代码改为使用无上限的通配符泛型数组,在这种情况下程序不得不进行强制类型转换,在进行强制类型转换之前仍旧需要通过instanceof运算符的校验

List<?>[] lsa = new ArrayList<?>[10];
Object[] oa = lsa;
List<Integer> li = new ArrayList<>();
li.add(3);
oa[1] = li;
Object target = lsa[1].get(0);
if (target instanceof String)
{
   // 下面代码安全了
   var s = (String) target;
}

与此类似的是,创建元素类型是泛型类型的数组对象也将出现编译错误

<T> T[] makeArray(Collection<T> coll)
{
	// 因为类型变量在运行时并不存在
	// 编译器无法确定实际类型是什么,下面代码导致编译错误
	return new T[coll.size()];
}
发布了207 篇原创文章 · 获赞 124 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/dawei_yang000000/article/details/105349384