HashMap中的泛型似乎不能始终如一地使用

时间:2013-10-13 22:20:35

标签: java generics hashmap

首先是泛型的新手。现在提问 - 在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?

是存在深层概念还是仅仅是负担得起的不一致?

1 个答案:

答案 0 :(得分:7)

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

如果您尝试这样的代码,您将收到编译器错误:

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

问题是泛型类型是non-reifiable - 它们的类型信息在运行时不可用。同时,数组使用运行时可用的类型信息来执行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

所以,如果编译了第一个赋值,那么编译器看起来很好的第4个赋值将在运行时抛出ClassCastException


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

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

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


另见: