2

合理地,编译器会为此给你原始类型转换警告:

//1
List<?> arrList = new ArrayList(); //raw type warning

但是,编译器可以使用此行(没有警告):

//2
List<?>[] arr_of_arrList = new ArrayList[3];// no warning, why ?

所以,没有编译器的任何抱怨,我可以进一步做:

 arr_of_arrList[0] = new ArrayList<String>();
 arr_of_arrList[1] = new ArrayList<Integer>();

您能否解释一下为什么给定的数组初始化(2)被认为是类型安全的,而不是第一个列表初始化(1),以及编译器在情况 2 中做了什么。

4

2 回答 2

2

编译器还会在定义时警告您:

List<String>[] foo = new ArrayList[3];

这是因为通过它的警告,编译器试图让您知道存储在其中List<String>[] foo的列表可能不是泛型类型String。你总是可以在运行时得到一个List<Integer>in :foo

 void main(){

    List<String>[] array = new List[1];
    fill(array);

    // The compiler could not check the array at compile time, so
    // the next line is permitted. But you just created yourself a time bomb.
    List<String> list = array[0];

    // The next line will finally cause a ClassCastException at runtime!
    // Good luck with debugging, especially if you have passed your list
    // arround for a while.
    // If you had defined List<?>[] foo, this assignment would have been
    // forbidden without explicit casting to String. But at least the "type"
    // of the array did not make you false promises about the generic type
    // of the list.
    String value = list.get(0);
 }

 // This method receives an array of lists. At runtime the generic type of
 // the array is gone. Therefore, a call to this method can be called with
 // anz List<SomeType>[] array as an argument. 
 void fill(List<?>[] array) {
   List<Integer> list = new ArrayList<Integer>();
   list.add(123)
   array[0] = list;
 }

在 Java 中,泛型类型的数组没有泛型表示。相反,所有类型的数组List[](在字节码中,类型被称为[java.util.List)共享一个单一的表示,无论是它List<String>还是List<Integer>其他任何东西。这是出于向后兼容性的原因以及数组在 Java 字节码中的表示方式。换句话说,编译器无法将数组实例标记为仅接受例如List<String>对象。相反,编译器只能将数组标记为接受ListJava 5 之前的子类型。

通过说明

List<?>[] foo = new ArrayList[3];

你基本上告诉编译器你知道编译器无法检查任何东西,除了List由 表示的数组中的所有 sfoo都是一些Object当然是微不足道的子类型。(?等同于? extends Object。)或者换句话说,当使用通配符时?,您要求编译器确保 aList包含在foo任何泛型类型。如前所述,由于这个需求是微不足道的,编译器实际上可以释放这个需求并且不会产生警告。

现在问题来了:

class MyClass<T extends Number> { }

你仍然不能说:

MyClass<? extends Number>[] foo = new MyClass[3];

没有编译器警告。为什么?我不知道。它应该是类型最安全的声明。当看到同义声明时,这更没有意义

MyClass<?>[] foo = new MyClass[3];

被接受。出于这个原因,我假设编译器只是在完全涉及数组时跳过泛型类型变量的类型检查,但是通过确保<?>与完全缺乏泛型的遗留代码相比,确保您认识到检查泛型数组类型是不可能的类型。

于 2013-06-14T17:58:24.157 回答
1

ArrayStoreException泛型或通配符完全无关。ArrayStoreException即使在“类型安全”代码中,数组也是 Java 中的一个事实:

Object[] foo = new Integer[3];
foo[0] = "bar";

这正是您的异常中发生的情况。返回的列表Arrays.asList不是 a java.util.ArrayList,因此是ArrayStoreException.

于 2013-05-20T09:18:18.607 回答