[Java] HashMap 源码简要分析

 特性

* 允许null作为key/value。
* 不保证按照插入的顺序输出。使用hash构造的映射一般来讲是无序的。
* 非线程安全。
* 内部原理与Hashtable类似。
 
源码简要分析
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链表。
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 @ 2014-03-07 21:54  cacard  阅读(416)  评论(0编辑  收藏  举报