这篇文章我们来分析一下HashMap的源码实现,进一步阅读之前强烈建议先浏览一下之前文章《《Java Generics and Collections》笔记-Lists/Maps 》中关于Maps的部分。
- java.lang.Object
-
- java.util.AbstractMap<K,V>
-
- java.util.HashMap<K,V>
149 static final Entry<?,?>[] EMPTY_TABLE = {};
150
151 /**
152 * The table, resized as necessary. Length MUST Always be a power of two.
153 */
154 transient Entry<K,V>[] table = (Entry<K,V>[])EMPTY_TABLE;
这里涉及到强制类型转换的问题,我们首先来看下面的例子:
15 class Base{}
16 class Derived extends Base{
18 }
7 Base b = new Derived();
8 Derived d = (Derived)b;
9
10 Base bs = new Base();
11 Derived d2 = (Derived)bs;
运行时异常: java.lang.ClassCastException: Base cannot be cast to Derived
子类转换为父类是可以直接转换的,因为子类的内存模型里面包含了父类的部分。父类强制转换为子类要分情况,如果父类的实际类型也是父类,那么是不可以的,因为根据内存模型它的实际内存就只有父类的那么大,不能扩展到下面。但是如果实际类型是子类,那么就很容易转为子类了。
对于这里的泛型道理也是一样的,但是要正确判断泛型的父类与子类。比如HashSet<Object>与HashSet<Integer>不满足父子关系,Set<Object>与HashSet<Object>则满足父子类关系。 对于数组类型的泛型,我们知道对于普通类型Father[]是Son[]的父类。对于泛型,List<Father>[]就不是List<Son>[]的父类。至于为什么泛型作此规定可以从文章《Java泛型总结》中2.1小节得到答案。
154行把Entry<?,?>[]强制转为Entry<K,V>[],后者是前者的子类,把父类强制转为子类,只有当父类实际类型是子类的时候才允许,这里由于泛型擦出的原因是满足的。
这里的table就是用来保存实际的数据的,它的元素类型为Entry,接下来我们看一下Entry的结构:
805 static class Entry<K,V> implements Map.Entry<K,V> {
806 final K key;
807 V value;
808 Entry<K,V> next;
809 int hash;
810
811 /**
812 * Creates new entry.
813 */
814 Entry(int h, K k, V v, Entry<K,V> n) {
815 value = v;
816 next = n;
817 key = k;
818 hash = h;
819 }
820
821 public final K getKey() {
822 return key;
823 }
824
825 public final V getValue() {
826 return value;
827 }
829 public final V setValue(V newValue) {
830 V oldValue = value;
831 value = newValue;
832 return oldValue;
833 }
836 if (!(o instanceof Map.Entry))
837 return false;
838 Map.Entry e = (Map.Entry)o;
839 Object k1 = getKey();
840 Object k2 = e.getKey();
841 if (k1 == k2 || (k1 != null && k1.equals(k2))) {
842 Object v1 = getValue();
843 Object v2 = e.getValue();
844 if (v1 == v2 || (v1 != null && v1.equals(v2)))
845 return true;
846 }
847 return false;
848 }
850 public final int hashCode() {
851 return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
852 }
853
854 public final String toString() {
855 return getKey() + "=" + getValue();
856 }
872 }
250 public HashMap(int initialCapacity, float loadFactor) {
251 if (initialCapacity < 0)
252 throw new IllegalArgumentException("Illegal initial capacity: " +
253 initialCapacity);
254 if (initialCapacity > MAXIMUM_CAPACITY)
255 initialCapacity = MAXIMUM_CAPACITY;
256 if (loadFactor <= 0 || Float.isNaN(loadFactor))
257 throw new IllegalArgumentException("Illegal load factor: " +
258&n