java源码分析之HashMap(四)

2014-11-24 11:24:54 · 作者: · 浏览: 38
9 targetCapacity = MAXIMUM_CAPACITY;
10 int newCapacity = table.length;
11 while (newCapacity < targetCapacity)
12 newCapacity <<= 1;
13 if (newCapacity > table.length)
14 resize(newCapacity);
15 }
16
17 for (Iterator< extends Map.Entry< extends K, extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
18 Map.Entry< extends K, extends V> e = i.next();
19 put(e.getKey(), e.getValue());
20 }
21 }
先回答上面的问题:为什么判断条件是numKeysToBeAdded,不是(numKeysToBeAdded+table.length)>threshold
这是一种保守的做法,明显地,我们应该在(numKeysToBeAdded+table.length)>threshold的时候去拓展容量,但是考虑到将被添加的元素可能会有Key与原本存在的Key相同的情况,所以采用保守的做法,避免拓展到过大的容量。
接着是遍历m中的内容,然后调用put方法将元素添加到table数组中。
遍历的时候涉及到了entrySet方法,这个方法定义在Map接口中,HashMap中也有实现,后面会解释HashMap的这个方法,其它Map的实现暂不解释。
下面介绍在put方法中被调用到的putForNullKey方法。
1 private V putForNullKey(V value) {
2 for (Entry e = table[0]; e != null; e = e.next) {
3 if (e.key == null) {
4 V oldValue = e.value;
5 e.value = value;
6 e.recordAccess(this);
7 return oldValue;
8 }
9 }
10 modCount++;
11 addEntry(0, null, value, 0);
12 return null;
13 }
这是一个私有方法,在put方法中被调用。它首先遍历table数组,如果找到key为null的元素,则替换元素值并返回oldValue;否则通过addEntry方法添加元素,之后返回null。
还记得上面构造方法中调用到的putAllForCreate吗?一口气将put操作的方法看完吧。
1 private void putAllForCreate(Map< extends K, extends V> m) {
2 for (Iterator< extends Map.Entry< extends K, extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
3 Map.Entry< extends K, extends V> e = i.next();
4 putForCreate(e.getKey(), e.getValue());
5 }
6 }
先将遍历的过程放在一边,因为它同样涉及到了entrySet()方法。剩下的代码很简单,只是调用putForCreate方法逐个元素加入。
1 private void putForCreate(K key, V value) {
2 int hash = (key == null) 0 : hash(key.hashCode());
3 int i = indexFor(hash, table.length);
4 for (Entry e = table[i]; e != null; e = e.next) {
5 Object k;
6 if (e.hash == hash &&
7 ((k = e.key) == key || (key != null && key.equals(k)))) {
8 e.value = value;
9 return;
10 }
11 }
12 createEntry(hash, key, value, i);
13 }
该方法先计算需要添加的元素的hash值和在table数组中的索引i。接着遍历table[i]的链表,若有元素的key值与传入key值相等,则替换value,结束方法。若不存在key值相同的元素,则调用createEntry创建并添加元素。
1 void createEntry(int hash, K key, V value, int bucketIndex) {
2 Entry e = table[bucketIndex];
3 table[bucketIndex] = new Entry(hash, key, value, e);
4 size++;
5 }
这个方法的内容就不解释了,上面都解释过。
至此所有put相关操作都解释完毕了。put之外,另一个常用的操作就是get,下面就来看get方法。
1 public V get(Object key) {
2 if (key == null)
3 return getForNullKey();
4 int hash = hash(key.hashCode());
5 for (Entry e = table[indexFor(hash, table.length)];
6 e != null;
7 e = e.next) {
8 Object k;
9 if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
10 return e.value;
11 }
12 return null;
13 }
该方法分为key为null和不为null两块。先看不为null的情况。先获取key的hash值,之后通过hash值及table.length获取key对应的table数组的索引,遍历索引的链表,所找到key相同的元素,则返回元素的value,否者返回null。不为null的情况调用了getForNullKey()方法。
1 private V getForNullKey() {
2 for (Entry e = table[0]; e != null; e = e.next) {
3 if (e.key == null)
4 return e.va