JDK源码阅读之HashMap的实现
2014-03-27 20:35
471 查看
基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的时间与HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。所以,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。
HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括get 和put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。
如果很多映射关系要存储在 HashMap 实例中,则相对于按需执行自动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。
注:HashMap不是线程安全的。
此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的时间与HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。所以,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。
HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括get 和put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。
如果很多映射关系要存储在 HashMap 实例中,则相对于按需执行自动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。
注:HashMap不是线程安全的。
//继承了AbstractMap抽象类,实现了Map接口 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { //默认初始化化容量,即16 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 //最大容量,即2的30次方 static final int MAXIMUM_CAPACITY = 1 << 30; //默认装载因子 static final float DEFAULT_LOAD_FACTOR = 0.75f; //HashMap内部的存储结构是一个数组,此处数组为空,即没有初始化之前的状态 static final Entry<?,?>[] EMPTY_TABLE = {}; //空的存储实体 transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; //HashMap的元素数目 transient int size; //HashMap下次扩容是的阀值 int threshold; //HashMap的装载因子 final float loadFactor; //修改次数 transient int modCount; //默认的threshold值 static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE; //通过虚拟机配置来修改threshold值 private static class Holder { static final int ALTERNATIVE_HASHING_THRESHOLD; static { String altThreshold = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction( "jdk.map.althashing.threshold"));//读取配置值 int threshold; try { threshold = (null != altThreshold)//修改threshold值 ? Integer.parseInt(altThreshold) : ALTERNATIVE_HASHING_THRESHOLD_DEFAULT; if (threshold == -1) { threshold = Integer.MAX_VALUE; } if (threshold < 0) { throw new IllegalArgumentException("value must be positive integer."); } } catch(IllegalArgumentException failed) { throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed); } ALTERNATIVE_HASHING_THRESHOLD = threshold; } } //计算Hash值时的key transient int hashSeed = 0; //通过初始容量和状态因子构造HashMap public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0)//参数有效性检查 throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY)//参数有效性检查 initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor))//参数有效性检查 throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; threshold = initialCapacity; init();//这个实现为空 } //通过扩容因子构造HashMap,容量去默认值,即16 public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } //装载因子取0.75,容量取16,构造HashMap public HashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); } //通过其他Map来初始化HashMap,容量通过其他Map的size来计算,装载因子取0.75 public HashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); inflateTable(threshold);//初始化HashMap底层的数组结构 putAllForCreate(m);//添加m中的元素 } //选择合适的容量值,容量值取大于等于最接近number的2的冪数 private static int roundUpToPowerOf2(int number) { int rounded = number >= MAXIMUM_CAPACITY //参数有效性检查 ? MAXIMUM_CAPACITY : (rounded = Integer.highestOneBit(number)) != 0 ? (Integer.bitCount(number) > 1) ? rounded << 1 : rounded : 1; return rounded; } //初始化HashMap的底层数据结构 private void inflateTable(int toSize) { int capacity = roundUpToPowerOf2(toSize);//选取合适的容量值 threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);//选取合适的threshold(扩容阀值) table = new Entry[capacity];//初始化底层数据结构 initHashSeedAsNeeded(capacity);//选择合适的Hash因子 } //目前为空 void init() { } //选择合适的Hash因子,这里和虚拟机的配置有关 final boolean initHashSeedAsNeeded(int capacity) { boolean currentAltHashing = hashSeed != 0; boolean useAltHashing = sun.misc.VM.isBooted() && (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD); boolean switching = currentAltHashing ^ useAltHashing; if (switching) { hashSeed = useAltHashing ? sun.misc.Hashing.randomHashSeed(this) : 0; } return switching; } //计算key的Hash值,这里针对String类的Key优化了Hash函数,这里和安全有关,后面专门分析这个 final int hash(Object k) { int h = hashSeed; if (0 != h && k instanceof String) {//这里针对String优化了Hash函数,是否使用新的Hash函数和Hash因子有关 return sun.misc.Hashing.stringHash32((String) k); } h ^= k.hashCode(); h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } //根据Hash值和Hash表的大小选择合适的Hash桶 static int indexFor(int h, int length) { return h & (length-1); } //返回HashMap的元素个数 public int size() { return size; } //判断是否为空 public boolean isEmpty() { return size == 0; } //获取key值为key的元素值 public V get(Object key) { if (key == null)//如果Key值为空,则获取对应的值,这里也可以看到,HashMap允许null的key,其内部针对null的key有特殊的逻辑 return getForNullKey(); Entry<K,V> entry = getEntry(key);//获取实体 return null == entry ? null : entry.getValue();//判断是否为空,不为空,则获取对应的值 } //获取key为null的实体 private V getForNullKey() { if (size == 0) {//如果元素个数为0,则直接返回null return null; } //key为null的元素存储在table的第0个位置 for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null)//判断是否为null return e.value;//返回其值 } return null; } //判断是否有键为key的元素 public boolean containsKey(Object key) { return getEntry(key) != null;//这里需要遍历 } //获取键值为key的元素 final Entry<K,V> getEntry(Object key) { if (size == 0) {//元素个数为0 return null;//直接返回null } int hash = (key == null) ? 0 : hash(key);//获取key的Hash值 for (Entry<K,V> e = table[indexFor(hash, table.length)];//根据key和表的长度,定位到Hash桶 e != null; e = e.next) {//进行遍历 Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))//判断Hash值和对应的key,合适则返回值 return e; } return null; } //添加元素 public V put(K key, V value) { if (table == EMPTY_TABLE) {//如果底层表为空,则初始化 inflateTable(threshold); } if (key == null)//如果key为空,则执行空的逻辑 return putForNullKey(value); int hash = hash(key);//获取key的Hash值 int i = indexFor(hash, table.length);//定位Hash桶 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);//调用value的回调函数,其实这个函数也为空实现 return oldValue; } } modCount++;//更新修改次数 addEntry(hash, key, value, i);//添加到对应Hash桶的链接表中 return null; } //添加key为空的元素,key为null的元素添加到第0号Hash桶中 private V putForNullKey(V value) { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) {//判断元素 V oldValue = e.value;//如果已经存在,修改值 e.value = value; e.recordAccess(this); return oldValue; } } modCount++;//更新修改次数 addEntry(0, null, value, 0);//执行链表插入 return null; } //添加元素 private void putForCreate(K key, V value) { int hash = null == key ? 0 : hash(key);//计算key的Hash值 int i = indexFor(hash, table.length);//定位Hash桶 //遍历第i号Hash桶 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { e.value = value; return; } } //创建元素实体,这里会添加到第i号Hash桶中 createEntry(hash, key, value, i); } //添加m中的元素到HashMap中 private void putAllForCreate(Map<? extends K, ? extends V> m) { for (Map.Entry<? extends K, ? extends V> e : m.entrySet())//遍历添加 putForCreate(e.getKey(), e.getValue()); } //按新的容量扩容Hash表 void resize(int newCapacity) { Entry[] oldTable = table;//老的数据 int oldCapacity = oldTable.length;//获取老的容量值 if (oldCapacity == MAXIMUM_CAPACITY) {//老的容量值已经到了最大容量值 threshold = Integer.MAX_VALUE;//修改扩容阀值 return; } //新的结构 Entry[] newTable = new Entry[newCapacity]; transfer(newTable, initHashSeedAsNeeded(newCapacity));//将老的表中的数据拷贝到新的结构中 table = newTable;//修改HashMap的底层数组 threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);//修改阀值 } //将老的表中的数据拷贝到新的结构中 void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length;//容量 for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) {//如果是重新Hash,则需要重新计算hash值 e.hash = null == e.key ? 0 : hash(e.key); } int i = indexFor(e.hash, newCapacity);//定位Hash桶 e.next = newTable[i];//元素连接到桶中,这里相当于单链表的插入 newTable[i] = e; e = next; } } } //添加元素 public void putAll(Map<? extends K, ? extends V> m) { int numKeysToBeAdded = m.size(); if (numKeysToBeAdded == 0)//m为空,则直接返回 return; if (table == EMPTY_TABLE) {//底层数组为空 inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));//执行初始化 } //按m的size执行HashMap的扩容 if (numKeysToBeAdded > threshold) {//阀值代表的扩容的条件,如果比阀值要大,则一定要扩容 int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);//选择容量值 if (targetCapacity > MAXIMUM_CAPACITY)//有效性判断 targetCapacity = MAXIMUM_CAPACITY; int newCapacity = table.length;//目前的容量 while (newCapacity < targetCapacity)//如果小于m的容量,则增加目前的容量 newCapacity <<= 1; if (newCapacity > table.length) resize(newCapacity);//执行扩容 } //有足够的空间之后进行扩容 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue());//执行添加操作 } //删除元素,元素的键值为key public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key);//删除键为key的元素 return (e == null ? null : e.value);//同时返回该值 } //删除元素,元素的键值为key final Entry<K,V> removeEntryForKey(Object key) { if (size == 0) { return null; } int hash = (key == null) ? 0 : hash(key);//计算Hash值 int i = indexFor(hash, table.length);//定位Hash桶 Entry<K,V> prev = table[i]; Entry<K,V> e = prev;//保存前面一个指针值 while (e != null) { Entry<K,V> next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {//在Hash桶中定位元素 modCount++;//更新修改次数 size--;//元素个数-1 if (prev == e)//是否是第一个元素 table[i] = next; else prev.next = next;//执行的是单链表的删除 e.recordRemoval(this); return e; } prev = e;//单链表移动指针 e = next; } return e; } //删除一个Entry实体,这里通过o的key查找到元素,之后删除,和上面的实现类似 final Entry<K,V> removeMapping(Object o) { if (size == 0 || !(o instanceof Map.Entry))//参数有效性验证 return null; Map.Entry<K,V> entry = (Map.Entry<K,V>) o; Object key = entry.getKey(); int hash = (key == null) ? 0 : hash(key); int i = indexFor(hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> e = prev; while (e != null) { Entry<K,V> next = e.next; if (e.hash == hash && e.equals(entry)) { modCount++; size--; if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; } //清空Hash表 public void clear() { modCount++;//更新修改次数 Arrays.fill(table, null);//底层数组置为null size = 0;//元素个数为0 } //判断是否包含值为value的元素 public boolean containsValue(Object value) { if (value == null)//值为null return containsNullValue();//执行null的逻辑 Entry[] tab = table; //执行两层循环来查找 for (int i = 0; i < tab.length ; i++) for (Entry e = tab[i] ; e != null ; e = e.next) if (value.equals(e.value))//这里判断内容 return true; return false; } //执行null的逻辑 private boolean containsNullValue() { Entry[] tab = table; for (int i = 0; i < tab.length ; i++) for (Entry e = tab[i] ; e != null ; e = e.next) if (e.value == null)//这里直接判断引用 return true; return false; } //浅复制HashMap public Object clone() { HashMap<K,V> result = null; try { result = (HashMap<K,V>)super.clone(); } catch (CloneNotSupportedException e) { // assert false; } if (result.table != EMPTY_TABLE) { result.inflateTable(Math.min( (int) Math.min( size * Math.min(1 / loadFactor, 4.0f), // we have limits... HashMap.MAXIMUM_CAPACITY), table.length)); } result.entrySet = null; result.modCount = 0; result.size = 0; result.init(); result.putAllForCreate(this); return result; } //实现Map.Entry接口,这是HashMap内部key和value的一个抽象 static class Entry<K,V> implements Map.Entry<K,V> { final K key;//键 V value;//值 Entry<K,V> next;//指向下一个元素的指针 int hash;//key的hash值 //创建Entry Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; } public final K getKey() { return key; } public final V getValue() { return value; } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } //判断元素内容 public final boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Object k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) {//判断键 Object v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2)))//判断值 return true; } return false; } public final int hashCode() { return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());//键和值的hash值的异或 } public final String toString() { return getKey() + "=" + getValue(); } //空实现 void recordAccess(HashMap<K,V> m) { } //空实现 void recordRemoval(HashMap<K,V> m) { } } //添加Entry void addEntry(int hash, K key, V value, int bucketIndex) { if ((size >= threshold) && (null != table[bucketIndex])) {//判断是否需要扩容 resize(2 * table.length);//按2倍扩容 hash = (null != key) ? hash(key) : 0;//计算hash值 bucketIndex = indexFor(hash, table.length);//定位Hash桶 } createEntry(hash, key, value, bucketIndex);//创建元素 } //创建元素 void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<>(hash, key, value, e);//这里执行链接操作 size++;//元素个数+1 } //继承了Iterator接口,提供迭代器实现 private abstract class HashIterator<E> implements Iterator<E> { Entry<K,V> next; //下一个实体 int expectedModCount; //迭代器修改次数 int index; //Hash桶的索引号 Entry<K,V> current; //当前实体 HashIterator() { expectedModCount = modCount;//更新修改次数 if (size > 0) { //目前有元素 Entry[] t = table; while (index < t.length && (next = t[index++]) == null)//寻找第一个不为空的Hash桶 ; } } //判断是否有下一个元素 public final boolean hasNext() { return next != null; } //返回下一个元素 final Entry<K,V> nextEntry() { if (modCount != expectedModCount)//迭代期间有修改,则抛出异常 throw new ConcurrentModificationException(); Entry<K,V> e = next;//从next开始遍历 if (e == null) throw new NoSuchElementException(); if ((next = e.next) == null) {//如果为空,则找到下一个不为空的Hash桶 Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } current = e;//返回next的值 return e; } //删除元素 public void remove() { if (current == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); Object k = current.key; current = null; HashMap.this.removeEntryForKey(k);//调用父类删除元素 expectedModCount = modCount;//修改并发修改次数 } } //HashMap值集迭代器,依赖Entry迭代器 private final class ValueIterator extends HashIterator<V> { public V next() { return nextEntry().value; } } //HashMap键集迭代器,依赖Entry迭代器 private final class KeyIterator extends HashIterator<K> { public K next() { return nextEntry().getKey(); } } //HashMap Entry迭代器 private final class EntryIterator extends HashIterator<Map.Entry<K,V>> { public Map.Entry<K,V> next() { return nextEntry(); } } //返回键集迭代器 Iterator<K> newKeyIterator() { return new KeyIterator(); } //返回值集迭代器 Iterator<V> newValueIterator() { return new ValueIterator(); } //返回Entry迭代器 Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); } //视图结合,HashMap内部Entry的集合 private transient Set<Map.Entry<K,V>> entrySet = null; //返回键集 public Set<K> keySet() { Set<K> ks = keySet; return (ks != null ? ks : (keySet = new KeySet())); } //键集合的实现,实现了AbstractSet抽象类,调用了父类的方法 private final class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return newKeyIterator(); } public int size() { return size; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { return HashMap.this.removeEntryForKey(o) != null; } public void clear() { HashMap.this.clear(); } } //返回值集合 public Collection<V> values() { Collection<V> vs = values; return (vs != null ? vs : (values = new Values())); } //值集合的实现,实现了AbstractCollection抽象类,调用了父类的方法来实现 private final class Values extends AbstractCollection<V> { public Iterator<V> iterator() { return newValueIterator(); } public int size() { return size; } public boolean contains(Object o) { return containsValue(o); } public void clear() { HashMap.this.clear(); } } //entry集合 public Set<Map.Entry<K,V>> entrySet() { return entrySet0(); } //防火entry集合 private Set<Map.Entry<K,V>> entrySet0() { Set<Map.Entry<K,V>> es = entrySet; return es != null ? es : (entrySet = new EntrySet()); } //entry集合的实现,继承了AbstractSet抽象类 private final class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() {//迭代器的实现 return newEntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<K,V> e = (Map.Entry<K,V>) o; Entry<K,V> candidate = getEntry(e.getKey()); return candidate != null && candidate.equals(e); } public boolean remove(Object o) { return removeMapping(o) != null; } public int size() { return size; } public void clear() { HashMap.this.clear(); } } //省略了序列化和反序列化的实现,后面专门分析。 }
相关文章推荐
- JDK源码阅读:实现自己的HashMap
- jdk源码阅读笔记-HashMap
- Java中HashMap底层实现原理(JDK1.8)源码分析
- JDK源码阅读——HashMap(1.7)
- JDK 1.7源码阅读笔记(七)集合类之HashMap
- JDK源码阅读之 HashMap
- jdk1.8.0_45源码解读——HashMap的实现
- JDK7集合框架源码阅读(三) HashMap
- Java Jdk1.8 HashMap源码阅读笔记二
- Java面试绕不开的问题: Java中HashMap底层实现原理(JDK1.8)源码分析
- 【JDK源码阅读8-util】Map接口----HashMap
- Java中HashMap底层实现原理(JDK1.8)源码分析
- JDK源码阅读之HashMap -- hash值计算方式、下标查找及tableSizeFor方法
- JDK源码阅读之HashMap类
- (转载)Java中HashMap底层实现原理(JDK1.8)源码分析
- Java中HashMap底层实现原理(JDK1.8)源码分析
- jdk 1.8 hashmap resize 源码阅读
- Java中HashMap底层实现原理(JDK1.8)源码分析
- Java Jdk1.8 HashMap源码阅读笔记一
- Java中HashMap底层实现原理(JDK1.8)源码分析