关于java:如何安全地从泛型类型的集合转换为数组?

How to safely convert from a Collection of generic types to an array?

本问题已经有最佳答案,请猛点这里访问。

出于各种原因,我希望将列表转换为数组,但是集合包含本身是泛型的对象。

我尝试了以下四个选项来编译它,而不需要@supressWarnings("unchecked")注释,但它们都不起作用。是否有解决方案可以使此正确工作,或者强制使用注释?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Iterator<T>[] iterators;
final Collection<Iterator<T>> initIterators = new ArrayList<Iterator<T>>();

// Type safety: Unchecked cast from Iterator[] to Iterator<T>[]
iterators = initIterators.<Iterator<T>>toArray(
        (Iterator<T>[])new Iterator[initIterators.size()]);

// Type safety: Unchecked invocation toArray(Iterator[]) of the generic
// method toArray(T[]) of type Collection<Iterator<T>>
// Type safety: The expression of type Iterator[] needs unchecked conversion
// to conform to Iterator<T>[]
iterators = initIterators.<Iterator<T>>toArray(
        new Iterator[initIterators.size()]);

// Type safety: The expression of type Iterator[] needs unchecked conversion
// to conform to Iterator<T>[]
iterators = initIterators.toArray(new Iterator[initIterators.size()]);

// Doesn't compile
iterators = initIterators.toArray(new Iterator<T>[initIterators.size()]);


没有类型安全的方法来创建参数化类型的数组,如Iterator[]

或者,您可以创建一个原始数组:Iterator[]。或者,如果可以完全避免使用数组,请使用像List>这样的集合类型。

不可能的原因是Java数组是协变的,泛型类型的参数化边界是不变的。这就是说:

1
2
3
Integer[] integers = new Integer[1];
Number[] numbers = integers; // OK because Integer extends Number
numbers[0] = new Double(3.14); // runtime exception

由于Double扩展了Number,并且声明的numbers类型是Number[],因此编译器允许赋值。但在运行时,实际的数组对象实例是原始的Integer[1],数组知道它们包含的对象的类型。

对于泛型,参数化类型是不同的。首先,由于编译时类型擦除,它们本质上不知道自己的运行时类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<Integer> integerList = new ArrayList<Integer>();

List<Number> numberList = integerList; // compiler error, prevents:
numberList.add(new Double(3.14)); // would insert a Double into integerList

Collection<Integer> integerCollection = integerList; // allowed
// OK because List extends Collection and the <type parameter> did not change

Collection<Number> numberCollection = integerList; // compiler error
// an"Integer" is a"Number"
// but"a collection of Integers" is more specific than"a collection of Numbers"
// and cannot be generally treated the same way and guarantee correct behavior

List<?> rawList = integerList; // allowed, but...
rawList.add(new Integer(42));  // compiler error, Integer is not a ... a what?

对于泛型,在Java中,您依赖编译器(而不是运行时)来验证泛型类型是否正确和安全。

因此,虽然Iterator[]在运行时知道它是一个包含Iterator元素的数组,但Iterator[]中的在编译时被删除,运行时无法知道它应该是什么。所以你会得到一个未选中的警告。