java - 使用 rawtype 数组初始化的通配符集合数组

标签 java generics initialization wildcard raw-types

很合理的是,编译器会为此向您发出原始类型转换警告:

//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 中做了什么。

最佳答案

编译器在定义时也会警告你:

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

这是因为编译器会通过警告试图让您知道列表存储在 List<String>[] foo 中。可能不是通用类型 String 。你总是可以得到 List<Integer>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>对象。相反,编译器只能将数组标记为接受 List 的子类型。与 Java 5 之前一样。

通过说明

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

你基本上告诉编译器你知道编译器无法检查除此之外的任何东西 List foo 表示的数组中的 s属于 Object 的某些子类型这当然是微不足道的。 ( ? 相当于 ? extends Object 。)或者换句话说,当使用通配符 ? 时,您要求编译器确保 List包含在 foo属于任何通用类型。如前所述,因为这个需求很简单,所以编译器实际上可以释放这个需求并且不会产生警告。

现在问题来了:

class MyClass<T extends Number> { }

你仍然不能说明:

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

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

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

被接受。因此,我认为当完全涉及数组时,编译器只是跳过泛型类型变量的类型检查,但通过确保用户输入 <?> 来确保您认识到检查数组的泛型类型是不可能的。与完全缺乏泛型类型的遗留代码相比。

关于java - 使用 rawtype 数组初始化的通配符集合数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16633053/

相关文章:

c++ - 使用转换函数直接初始化

c++ - 如何找到全局静态初始化

java - 这个类是完全不可变的吗?

java - 在不同线程、JVM 和服务器之间使用 Hibernate

Python NET 创建通用字典,对象作为值的类型

Java 泛型 : instantiating A with a single constructor argument B

c++ - 是类型名称=名称;在 C++ 中有用吗?

java - 如何在 Android 中使用 HTTPS 发布

java - 如何编写java方法(如果String x = to String y返回String z)

java - 调用另一个通用方法的通用方法 - util 方法返回 Class<Customer> 而不是 Customer