public V put(K key, V value):
public V put(K key, V value) {// hash函数计算得到hash值int hash = hash(key);// 通过hash函数获得哈希槽的位置int i = indexFor(hash, table.length);// 遍历哈希槽上所有数据,判断key是否相等for (Entry<K, V> e = table[i]; e != null; e = e.next) {Object k;// hash值和key完全相等,则覆盖原先的值if (e.hash == hash && ((k = e.key) == key || (key.equals(k)))) {V oldValue = e.value;e.value = value;return oldValue;}}// 指定hash槽没有找到给定的keymodCount++;// 添加元素,最后一个是数组下标addEntry(hash, key, value, i);return null;}
/*** @param hash* @param key 键* @param value 值* @param bucketIndex 哈希槽*/void addEntry(int hash, K key, V value, int bucketIndex) {// 新增元素时需要判断元素是否到达阀值且数组下标位置已经有了元素if ((size > threshold) && (null != table[bucketIndex])) {// 扩容2倍,size表示实际存储元素个数,而length是数组的容量大小resize(2 * table.length);// 重新计算hashhash = (null != key) ? hash(key) : 0;// 找到哈希槽bucketIndex = indexFor(hash, table.length);}// 创建节点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++;}
扩容:
// 扩容void resize(int newCapacity) {// 创建指定容量大小Entry[] newTable = new Entry[newCapacity];// 转移transfer(newTable, initHashSeedAsNeeded(newCapacity));// 赋值table = newTable;// 重新计算负载因子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) {// 如果此slot上有元素while (null != e) {Entry<K, V> next = e.next;// 当前元素总是直接放在数据下标位置的slot,而不是放在链表的最后if (rehash) {e.hash = null == e.key ? 0 : hash(e.key);}if (rehash) {//通过e的key值计算e的hash值e.hash = null == e.key ? 0 : hash(e.key);}//得到e在新table中的插入位置int i = indexFor(e.hash, newCapacity);//采用链头插入法将e插入i位置,最后得到的链表相对于原table正好是头尾相反的e.next = newTable[i];newTable[i] = e;//下一次循环e = next;}}}