在java泛型中是不能实例化参数化类型的数组的,例如:
Pair<String>[] table = new Pair<String>[10]; //Error
这是为什么呢?其实主要是为了避免数组里出现类型不一致的元素。
我们先看一下,数组是否可以存储其它类型元素
Pair[] table = new Pair[10];
table[0] = new Object(); //编译错误
很明显直接存储,编译器会报错。那么将数组向上转换一下,再存储呢?
Pair[] table = new Pair[10];
Object[] o = table; //自动转换
o[0] = new Object();
此时编译器是不会报错的,但是运行时会抛出ArrayStoreException异常
说明了数组存储检查是很严格的,它只能存储创建时元素类型。
但是,泛型擦除会破坏这种机制,举例:
Pair<String>[] table = new Pair<String>[10] //假设可以
Object[] o = table; //泛型擦除变为Pair[],向上自动转换为Object[]
o[0] = new Pair<Double>();
你会发现,此时Pair<String>数组里存储了Pair<Double>元素
当然以下情况还是不行的:
o[1] = new Object(); // 编译不报错,运行抛出异常
总之java不允许创建参数化的泛型数组,是为了保护数组安全性。
另外,虽然参数化的泛型数组不能创建,但是可以创建通配符的泛型数组。
Pair<?>[] table = new Pair<?>[10];
这是可以的,因为new Pair<?>表示数组可以存储任意参数的Pair,如Pair<String>和Pair<Double>等等。
另外,还可以这么创建
Pair<String>[] table = new Pair[10]; //兼容转换,并不是父子关系
table[0] = new Pair<Double>; //编译错误
此时,数组的实际类型是虽然是Pair,但是声明为Pair<String>,所以报错。
原因在于,泛型类型和原始类型可以转换,但却不是继承关系。按理来说,Pair<Double>可以转为Pair,应该可以存储,但此时声明的Pair<String>却不是Pair的父类,所以Pair<Double>不能存储。
但是,以下方式可以正常运行
Object[] o =table;
o[0] = new Pair<Double>;