HashMap源码解析
Posted teiba
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HashMap源码解析相关的知识,希望对你有一定的参考价值。
变量:
/** * 初始化容量为16 */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 /** * 最大容量:2^30 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * 负载因子默认0.75,负载因子越小,hash冲突几率越低 */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * 初始化一个空的数组 */ static final Entry<?,?>[] EMPTY_TABLE = {}; /** * 存值的数组,初始化为空数组 */ transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; /** * HashMap存入元素的个数 */ transient int size; /** * 临界值,HashMap能存储的大小,公式为(threshold=capacity*loadFactor) */ // If table == EMPTY_TABLE then this is the initial capacity at which the // table will be created when inflated. int threshold; /** * 负载因子 */ final float loadFactor; /** *HashMap修改的次数,用于迭代 */ transient int modCount; /** * 最大值*/ static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
构造方法:
public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY)//MAXIMUM_CAPACITY 最大容量 initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor))//loadFactor 负载因子 throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; threshold = initialCapacity; init(); }
走完构造方法,HashMap创建了一个空的数组,transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; 当使用put(K, V)存入键值对的时候,才会使用inflateTable(initialCapacity)初始化数组的大小为initialCapacity。下面是put(K, V)源码:
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold);//初始化table的大小 } if (key == null) 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) {//如果当前数组上的链表头不为null,遍历链表 Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//不为null时,检测key值得hash是否相同,如果相同替换掉原来的值,并返回原来的值 V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++;//修改次数+1 addEntry(hash, key, value, i);//添加元素 return null; }
private static int roundUpToPowerOf2(int number) { // assert number >= 0 : "number must be non-negative"; return number >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;//确保是2的倍数 } /** * Inflates the table. */ 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); }
放入元素,如果是table是空数组,初始化table,临界值;
key是null,将该entry放入到数组table的第0个下标处(第一个位置);
根据key值计算出hash值,根据hash值计算出在数组table中的下标,根据下标找到链表,如果链表头不为null,遍历链表,检查key值是否存在于链表,如果存在,将新值替换掉旧值,并返回旧值;
addEntry方法,将新的entry添加到链表头中。
void addEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex];//记录原来的链表头 table[bucketIndex] = new Entry<K,V>(hash, key, value, e);//表头引用该变成要插入的entry元素 if (size++ >= threshold) resize(2 * table.length);//加入元素后,空间不足,扩容table长度的2倍 }
以上是关于HashMap源码解析的主要内容,如果未能解决你的问题,请参考以下文章