HashMap源码剖析
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 //默认初始容量是16,容量必须保持为2的幂
static final int MAXIMUM_CAPACITY = 1 << 30; //最大容量2的30次方
static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认的加载因子
static final Entry<?,?>[] EMPTY_TABLE = {};//存储Entry的默认空数组
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; //哈希桶,存放链表。
transient int size;//键值对的个数
int threshold; //默认时16*0.75 =12 //HashMap的阈值,用于判断是否需要调整HashMap的容量
final float loadFactor; //加载因子 0.75 传进来的值
transient int modCount;//map结构修改次数,累加,用于fail-fast机制
static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;/** 默认阈值*/
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)
? Integer.parseInt(altThreshold)
: ALTERNATIVE_HASHING_THRESHOLD_DEFAULT;
// disable alternative hashing if -1
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;
}
}
transient int hashSeed = 0;
public HashMap(int initialCapacity, float loadFactor) {//带有初始容量和加载因子
if (initialCapacity < 0)//确保容量大小合法
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
//初始容量最大不能超过2的30次方
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;//将阈值设置为初始容量,这里不是真正的阈值,是为了扩展table的,后面这个阈值会重新计算
init();//一个空方法
}
public HashMap(int initialCapacity) {//带有初始容量,加载因子设为默认值
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap() {//初始容量和加载因子均为默认值
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
public HashMap(Map<? extends K, ? extends V> m) {//构造一个映射关系与指定 Map 相同的新 HashMap
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
inflateTable(threshold);
putAllForCreate(m);
}
//将初始容量转变成2的幂
private static int roundUpToPowerOf2(int number) { //12 最接近的一个2的幂
// assert number >= 0 : "number must be non-negative";
return number >= MAXIMUM_CAPACITY
? MAXIMUM_CAPACITY//如果容量超过了最大值,设置为最大值//否则设置为最接近给定值的2的幂
: (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
}
//初始化table
private void inflateTable(int toSize) {
// Find a power of 2 >= toSize
int capacity = roundUpToPowerOf2(toSize);//将传入的容量大小转化为:>传入容量大小的最小的2的次幂
//重新计算阈值 threshold = 容量 * 加载因子
threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);//阈值//默认是16*0.75 =12
table = new Entry[capacity];//用该容量初始化table
//初始化时机
//因此初始化table不是在HashMap的构造函数里,因为构造函数中仅仅简单的将传进去的容量作为阈值。
//真正初始化table是在第一次向HashMap中put数据的时候。
initHashSeedAsNeeded(capacity);
}
void init() {
}
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; //false
}
final int hash(Object k) {
int h = hashSeed; //0
if (0 != h && k instanceof String) { //在我们的系统里hashSeed = 0
return sun.misc.Hashing.stringHash32((String) k);
}
h ^= k.hashCode(); // key hashcode 散列码
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
//扰动处理 加大哈希码低位的随机性,使得分布更均匀,从而提高对应数组存储下标位置的随机性 & 均匀性,最终减少Hash冲突
//让哈希码分布的更加均匀 从而避免出现哈希冲突
}
static int indexFor(int h, int length) {//计算key对应在table中的index位置
// assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
return h & (length-1);//hash(key) & 16 -1 = hash(key) % 16
}
public int size() {//返回当前HashMap的key-value映射数,即Entry数量
return size;
}
public boolean isEmpty() {//判断HashMap是否为空,size==0表示空
return size == 0;
}
public V get(Object key) {
if (key == null)
return getForNullKey();//key==null时,从table[0]中取value
Entry<K,V> entry = getEntry(key);//key!=null->getEntry
return null == entry ? null : entry.getValue();
}
private V getForNullKey() {
if (size == 0) {
return null;
}
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;//从table[0]中取key==null的value值
}
return null;
}
public boolean containsKey(Object key) {//判断HashMap中是否包含指定键的映射
return getEntry(key) != null;
}
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
// 如果hash值相等,并且key相等则证明这个Entry里的东西是我们想要的
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
public V put(K key, V value) {
if (table == EMPTY_TABLE) {//如果哈希表没有初始化(table为空)
inflateTable(threshold);//threshold 阈值 //用构造时的阈值(其实就是初始容量)扩展table
}
//如果key==null,就将value加到table[0]的位置
//该位置永远只有一个value,新传进来的value会覆盖旧的value
if (key == null)
return putForNullKey(value);
//根据键值key计算hash值
int hash = hash(key); //扰动处理后的key的hashcode
int i = indexFor(hash, table.length);//value值应该存放在哪个下标下面 //具体:hash(key) & (16 -1) = hash(key) % 16
for (Entry<K,V> e = table[i]; e != null; e = e.next) {//循环遍历Entry数组,若该key对应的键值对已经存在,则用新的value取代旧的value
Object k; //key 小明 value 13 key 小明 value 12
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//当有重复的key插入的时候就会替换掉之前的value
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;//并返回旧的value
}
}
modCount++;
addEntry(hash, key, value, i);//如果在table[i]中没找到对应的key,那么就直接在该位置的链表中添加此Entry
return null;
}
//传进key==null的Entry
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) { //本身已经存放一个key为null
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//本身没有存放一个key为null
modCount++;
addEntry(0, null, value, 0);//将key为空的value存放在数组的0号下标上(key为NULL时hash为0)
return null;
}
private void putForCreate(K key, V value) {//看需不需要创建新的Entry
int hash = null == key ? 0 : hash(key);// 如果key为null,则定义hash为0,否则用hash函数处理得到hash值
int i = indexFor(hash, table.length);
//遍历所有的Entry
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;//如果有hash相同,且key相同的键值key,那么则不需要创建新的Entry,退出
}
}
createEntry(hash, key, value, i);//否则需要创建新的Entry
}
private void putAllForCreate(Map<? extends K, ? extends V> m) {//根据已有的Map创建对应的Entry
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
putForCreate(e.getKey(), e.getValue());
}
void resize(int newCapacity) {//用新的容量newCapacity来给table扩容--- 默认2倍扩容
Entry[] oldTable = table;//保存old table
int oldCapacity = oldTable.length;//保存old capacity
if (oldCapacity == MAXIMUM_CAPACITY) {//如果旧的容量已经是系统默认最大容量了,那么将阈值设置成整形的最大值,退出
threshold = Integer.MAX_VALUE;
return;
}
//根据新的容量新建一个table
Entry[] newTable = new Entry[newCapacity];//32
transfer(newTable, initHashSeedAsNeeded(newCapacity));//将table转换成newTable
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);//设置阈值
}
void transfer(Entry[] newTable, boolean rehash) {//将所有的Entry移到新的table中
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {//获得原来table中的所有Entry
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];//x//设置e.next为newTable[i]保存的Entry
newTable[i] = e;//将e设置为newTable[i]
e = next;//设置e为下一个Entry,继续上面while循环
}
}
}
//将指定的Map中所有映射复制到现有的HashMap中,这些映射关系将覆盖当前HashMap中针对指定键相同的映射关系
//其实和put的原理一样,key如果存在,就替换现有key对应的value
public void putAll(Map<? extends K, ? extends V> m) {
int numKeysToBeAdded = m.size();//统计需要复制多少个映射关系
if (numKeysToBeAdded == 0)
return;
if (table == EMPTY_TABLE) {//如果table还没初始化,先用刚刚统计的复制数去初始化table
inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));
}
//如果要复制的数目比阈值还要大
if (numKeysToBeAdded > threshold) {
int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);//需要先resize即扩容
if (targetCapacity > MAXIMUM_CAPACITY)
targetCapacity = MAXIMUM_CAPACITY;
int newCapacity = table.length;
while (newCapacity < targetCapacity)
newCapacity <<= 1;
if (newCapacity > table.length)
resize(newCapacity);
}
//开始复制
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());//看到这就可以发现最后调用的还是put()方法
}
public V remove(Object key) {//根据指定的key删除Entry,返回对应的value
Entry<K,V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
}
final Entry<K,V> removeEntryForKey(Object key) {//根据指定的key,删除Entry,并返回对应的value
if (size == 0) {
return null;
}
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;
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == e) //删除的是头一个节点
table[i] = next;//直接将第一个节点中的next的引用存入table[i]中
else
prev.next = next;//否则将table[i]中当前Entry的前一个Entry中的next置为当前Entry的next
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
final Entry<K,V> removeMapping(Object o) {//根据Entry来删除HashMap中的值
if (size == 0 || !(o instanceof Map.Entry))
return null;
Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
Object key = entry.getKey();//第一步也是先获得该Entry中保存的key
int hash = (key == null) ? 0 : hash(key);//接下来就和上面根据key删除Entry一样
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;
}
public void clear() {//清空HashMap中所有的Entry
modCount++;
Arrays.fill(table, null);//将table中存储的Entry全部置为null
size = 0;//size置为0
}
public boolean containsValue(Object value) {//判断HashMap中是否有key映射到指定的value
if (value == null)
return containsNullValue();
Entry[] tab = table;
for (int i = 0; i < tab.length ; i++)//否则遍历链表中的每个Entry
for (Entry e = tab[i] ; e != null ; e = e.next)
if (value.equals(e.value))//如果有Entry中的value与指定的value相等
return true;
return false;
}
private boolean containsNullValue() {//value为空时调用的方法
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;
}
public Object clone() {//克隆HashMap,这里是浅拷贝,并没有复制键和值的本身
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;
}
//Entry其实是个单链表即HashMap链式存储对应的链表
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
int hash;
Entry(int h, K k, V v, Entry<K,V> n) { //e
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;
}
//判断两个Entry是否相等,必须key和value都相等,才返回true
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());
}
public final String toString() {
return getKey() + "=" + getValue();
}
void recordAccess(HashMap<K,V> m) {
}
void recordRemoval(HashMap<K,V> m) {
}
}
//向HashMap中添加Entry
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {//threshold默认为16*0.75 =12
resize(2 * table.length); //2倍扩容
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex);
//调用createEntry方法在table数组适当的位置创建一个Entry,
//new Entry的时候,将next置为原本在该位置的Entry即可
//这样,原来的Entry就挂到现在的Entry上了,以后只要在该位置新new一个Entry
//就将原来的挂上去,这样一个挂一个,形成了一个链表。
//但是table中永远存储的是最新的Entry,并非一个真正的链表数据结构
//只是Entry是一个个连在一起的,跟链表很像而已。
}
//创建一个Entry
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];//先把table中该位置原来的Entry保存
//在table中该位置新建一个Entry,将原来的Entry挂到该Entry的next
//Entry<K,V> next;Entry(int h, K k, V v, Entry<K,V> n);next = n;
table[bucketIndex] = new Entry<>(hash, key, value, e);
//所以table中的每个位置永远只保存一个最新加进来的Entry,其他Entry是一个挂一个,这样挂上去的
size++;
}
//HashIterator实现了Iterator接口
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K,V> current; // current entry
HashIterator() {
expectedModCount = modCount;//保存modCount用于fail-fast机制
if (size > 0) { // advance to first entry //寻找第一个节点
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {//判断有没有下一个Entry
return next != null;
}
final Entry<K,V> nextEntry() {//获得下一个Entry
if (modCount != expectedModCount) //快速失败
throw new ConcurrentModificationException();//在迭代的过程中发现被修改了,就会抛出异常
Entry<K,V> e = next;
if (e == null)//没有就抛出异常
throw new NoSuchElementException();
if ((next = e.next) == null) { //这一步相当于指针向后移动
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
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;
}
}
private final class ValueIterator extends HashIterator<V> {//内部class ValueIterator迭代器,它修改了next方法
public V next() {
return nextEntry().value;
}
}
private final class KeyIterator extends HashIterator<K> {//内部class KeyIterator迭代器,它修改了next方法
public K next() {
return nextEntry().getKey();
}
}
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {//内部class EntryIterator迭代器,它修改了next方法
public Map.Entry<K,V> next() {
return nextEntry();
}
}
// Subclass overrides these to alter behavior of views' iterator() method
//定义上面三个对应的Iterator方法
Iterator<K> newKeyIterator() {
return new KeyIterator();
}
Iterator<V> newValueIterator() {
return new ValueIterator();
}
Iterator<Map.Entry<K,V>> newEntryIterator() {
return new EntryIterator();
}
// Views
private transient Set<Map.Entry<K,V>> entrySet = null;
public Set<K> keySet() {
Set<K> ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}
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()));
}
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();
}
}
public Set<Map.Entry<K,V>> entrySet() {
return entrySet0();
}
private Set<Map.Entry<K,V>> entrySet0() {
Set<Map.Entry<K,V>> es = entrySet;
return es != null ? es : (entrySet = new EntrySet());
}
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();
}
}
/************************** 序列化 *****************************/
private void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
// Write out the threshold, loadfactor, and any hidden stuff
s.defaultWriteObject();
// Write out number of buckets
if (table==EMPTY_TABLE) {//将table.length写入流
s.writeInt(roundUpToPowerOf2(threshold));
} else {
s.writeInt(table.length);
}
// Write out size (number of Mappings)
s.writeInt(size);
// Write out keys and values (alternating)
//这里之所以不直接将table写出,而是分开写里面保存Entry的key和value的原因是:
//table数组定义为了transient,也就是说在进行序列化时,并不包含该成员。
//为什么将其设置为transient呢?因为Object.hashCode方法对于一个类的两个实例返回的是不同的哈希值。
//即我们在机器A上算出对象A的哈希值与索引,然后把它插入到HashMap中,然后把该HashMap序列化后,
//在机器B上重新算对象的哈希值与索引,这与机器A上算出的是不一样的,
//所以我们在机器B上get对象A时,会得到错误的结果。
//所以我们分开序列化key和value
if (size > 0) {
for(Map.Entry<K,V> e : entrySet0()) {
s.writeObject(e.getKey());
s.writeObject(e.getValue());
}
}
}
private static final long serialVersionUID = 362498820763181265L;
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
// Read in the threshold (ignored), loadfactor, and any hidden stuff
s.defaultReadObject();
if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
throw new InvalidObjectException("Illegal load factor: " +
loadFactor);
}
// set other fields that need values
table = (Entry<K,V>[]) EMPTY_TABLE;
// Read in number of buckets
s.readInt(); // ignored.
// Read number of mappings
int mappings = s.readInt();
if (mappings < 0)
throw new InvalidObjectException("Illegal mappings count: " +
mappings);
// capacity chosen by number of mappings and desired load (if >= 0.25)
int capacity = (int) Math.min(
mappings * Math.min(1 / loadFactor, 4.0f),
// we have limits...
HashMap.MAXIMUM_CAPACITY);
// allocate the bucket array;
if (mappings > 0) {
inflateTable(capacity);
} else {
threshold = capacity;
}
init(); // Give subclass a chance to do its thing.
// Read the keys and values, and put the mappings in the HashMap
for (int i = 0; i < mappings; i++) {
K key = (K) s.readObject();
V value = (V) s.readObject();
putForCreate(key, value);
}
}
// These methods are used when serializing HashSets
int capacity() { return table.length; }
float loadFactor() { return loadFactor; }
}