标签:
今天来看下HashMap源码,先从put方法入手:
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); 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; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
第一部分主要完成对空容器的一个初始化:
private void inflateTable(int toSize) { // Find a power of 2 >= toSize int capacity = roundUpToPowerOf2(toSize); threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1); table = new Entry[capacity]; initHashSeedAsNeeded(capacity); }
如果key为null时会将键值对插在table[0]这个位置,可见null可以作为HashMap的键值,
int hash = hash(key); int i = indexFor(hash, table.length);
这两行主要是为了在table数组中定位,其中可以看出String的hash值只跟字符内容有关。
table数组的每个元素都是一个Entry<K,V>链表,
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; e.recordAccess(this); return oldValue; } }
这一段就是要验证插入前HashMap是否存在与插入元素相同的键值,如果有就更新值,如果没有
addEntry(hash, key, value, i);
void addEntry(int hash, K key, V value, int bucketIndex) { if ((size >= threshold) && (null != table[bucketIndex])) { resize(2 * table.length); hash = (null != key) ? hash(key) : 0; bucketIndex = indexFor(hash, table.length); } createEntry(hash, key, value, bucketIndex); }
如果size超过threshold就扩容否则将新建元素插入都链表头部。
详细参考http://www.cnblogs.com/matrix-skygirl/archive/2013/01/17/2864919.html
标签:
原文地址:http://www.cnblogs.com/yigeboke/p/4572018.html