特性
* 允许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(); }