很合理的是,编译器会为此向您发出原始类型转换警告:
//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/