[Java] HashMap 源码简要分析

 特性

* 允许null作为key/value。
* 不保证按照插入的顺序输出。使用hash构造的映射一般来讲是无序的。
* 非线程安全。
* 内部原理与Hashtable类似。
 
源码简要分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public class HashMap<K,V>
{
     static final int DEFAULT_INITIAL_CAPACITY = 16 ; // 默认初始容量是16。(必须是2的次方)
     static final int MAXIMUM_CAPACITY = 1 << 30 ; // 即2的30次方
     static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认装载因子
 
     Entry[] table;  // Entry表
     int size; // Entry[]实际存储的Entry个数
     int threshold; // reash的阈值,=capacity * load factor
     final float loadFactor;
 
     // 构造函数
     public HashMap(int initialCapacity, float loadFactor) {
     // 找到一个比initialCapacity大的最小的2的次方数
     int capacity = 1;
     while (capacity < initialCapacity)
            capacity <<= 1;
     }
 
     this.loadFactor = loadFactor;
     threshold = (int)(capacity * loadFactor);
     table = new Entry[capacity];
 
     // addEntry()
    void addEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        if (size++ >= threshold)
            resize(2 * table.length);
    }
 
     // put():添加元素
     public V put(K key, V value) {
          int hash = hash(key.hashCode());     // key的hash值
          int i = indexFor(hash,table.length);     // 槽位
 
          // 寻找是否已经有key存在,如果已经存在,使用新值覆盖旧值,返回旧值
          for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                return oldValue;
            }
          }
 
          // 添加Entry
          addEntry(hash,key,value,i);
          return null;
     }
 
     // resize():重新哈希
    void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
    }
 
    /**
     * Transfers all entries from current table to newTable.
     */
    void transfer(Entry[] newTable) {
        Entry[] src = table;
        int newCapacity = newTable.length;
        for (int j = 0; j < src.length; j++) {
            Entry<K,V> e = src[j];
            if (e != null) {
                src[j] = null;    
                do {
                    Entry<K,V> next = e.next;
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                } while (e != null);
            }
        }
    }
 
}

  

遍历方式

* 低效遍历:按照Key进行遍历,则每次都需要按Key查找槽位(不同的Key有重复查找),且可能需要遍历槽位上所在Entry链表(不同的Key有重复遍历)。
* 高效遍历:HashMap的entrySet()返回自定义的EntryIterator,是先按照槽位遍历一次,再遍历一次槽位上Entry链表。
1
2
3
4
5
6
Map<String, String[]> paraMap = new HashMap<String, String[]>();
for( Map.Entry<String, String[]> entry : paraMap.entrySet() )
{
    String appFieldDefId = entry.getKey();
    String[] values = entry.getValue();
}

  

 

posted @   cacard  阅读(418)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示