4

首先是泛型的新手。现在问题 - 在 HashMap.java 我看到以下内容 -

 transient Entry[] table; 
 which is initiated in constructor as
 table = new Entry[capacity];

为什么这没有用类型参数声明?

或者

 private V getForNullKey() {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {

为什么 for 循环中的 Entry 用类型参数声明?

是否有一个深刻的概念或只是一个负担得起的不一致?

4

1 回答 1

7

那是因为创建一个具体参数化类型的数组不是类型安全的,这就是为什么根本不允许这样做。

如果你尝试这样的代码,你会得到一个编译器错误:

List<String>[] arr = new ArrayList<String>[10]; // Compiler error: Generic Array creation

问题是泛型类型是不可具体化的——它们的类型信息在运行时不可用。同时,数组使用运行时可用的类型信息ArrayStoreCheck来检查插入到数组中的元素是否与数组的类型兼容。因此,如果您混合使用数组和泛型,那么您最终可能会在运行时出现令人惊讶的行为。

例如,考虑以下代码:

List<String>[] arr = new ArrayList<String>[10];  // Suppose this was valid
Object[] objArr = arr;         // This is valid assignment. A `List[]` is an `Object[]`
objArr[0] = new ArrayList<Integer>();  // There you go. A disaster waiting at runtime.

String str = arr[0].get(0);    // Assigned an `Integer` to a `String`. ClassCastException

因此,如果编译了第一个赋值,那么编译器看起来不错的第四个赋值将ClassCastException在运行时抛出 a。


但是,您可以创建原始类型数组 -ArrayList或无界通配符参数化类型 - ArrayList<?>,因为它们都是完全可具体化的类型。因此,以下数组创建是有效的:

List[] arr = new ArrayList[10];
List<?>[] arr2 = new ArrayList<?>[10];

由于没有与原始类型或无界通配符类型关联的类型信息,因此在运行时不会丢失任何内容。因此这些类型是可具体化的,它们是数组的合格组件类型。这就是为什么Entry[]使用 代替Entry<K, V>[]


也可以看看:

于 2013-10-13T22:22:40.497 回答