JDK1.8集合框架原始碼分析三-------------HashMap
1.HashMap的一些重要成員屬性
1.1) 預設的初始容量 DEFAULT_INITIAL_CAPACITY = 1 << 4,官方建議必須時2的次方數
1.2) 負載因子DEFAULT_LOAD_FACTOR = 0.75f; 用來HashMap擴容判斷
1.3) Node<K,V>[] table; ---容器中的元素
2.HashMap的構造方法
1.1) 無參建構函式
1.2) 帶容量的有參建構函式
1.3) 帶容量和負載因子的有參建構函式
3.HashMap的hash方法
3.1) step1: 獲取到 key的hashcode值
3.2) step2: 將step1計算得到的值無符號右移16位
3.3) step3: 將 step1 和 step2 的結果異或運算得到結果
4.HashMap容器中的重要元素類Node的組成
4.1) hash值
4.2) key 和 value值
4.3) hash值相同時,變成連結串列結果的下一個Node
static class Node<K,V>{ final int hash; final K key; V value; Node<K,V> next; public Node(int hash, K key, V value, Node<K, V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } public K getKey() { return key; } public V getValue() { return value; } @Override public String toString() { return key + " = " + value; } //設定成新值,返回舊值 public final V setValue(V newValue) { V oldValue = value; this.value = newValue; return oldValue; } @Override public int hashCode() { return Objects.hash(key) ^ Objects.hash(value); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Node<?, ?> node = (Node<?, ?>) o; return Objects.equals(key, node.key) && Objects.equals(value, node.value); } }
5.HashMap的put方法
5.1) 計算出HashMap中陣列所在的下標值---步驟3的hash值 和 HashMap容量的值減去1做與運算
從上面的表格可以看出容量的大小,必須為2的次方數,不然最終陣列會有下標遺漏
5.2) HashMap容器put方法的返回值是舊值
5.3) HashMap擴容時,在進行元素的重新分配時,針對單向連結串列需要明確以下節點
5.3.1) 在同一個連結串列中,則說明這個連結串列中所有元素的hash值是相同的
5.3.2) HashMap擴容標準是2的次方數,從4->8->16....
5.3.3) 從5.1)可以得知hash值二進位制在舊的容量所在二進位制所處的位置是0 還是1 ,即可計算出當前整個連結串列
在新的HashMap容器中所處的位置
public V put(K key, V value) {
return putVal(hash(key), key, value);
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
private V putVal(int hash, K key, V value) {
//定義一個臨時變數用來儲存HashMap容器的容量大小
int capacity;
//定義一個新元素在HashMap中數組裡面的下表位置
int currentIndex;
//把HashMap容器的元素賦值給一個臨時變數
Node<K, V>[] tempTable = table;
//如果HashMap容器為空或者容量為0,則需要擴容
if (tempTable == null || tempTable.length == 0) {
tempTable = resize();
}
capacity = tempTable.length;
//計算新增的值將要儲存的位置
currentIndex = (capacity - 1) & hash;
//從HashMap中取出當前位置的元素
Node<K, V> tempNode = tempTable[currentIndex];
//如果HashMap容器的當前位置還沒有儲存元素
//則直接把信元素賦值到這個位置即可
if (tempNode == null) {
tempTable[currentIndex] = new Node<>(hash, key, value, null);
} else {
Node<K, V> modifyNode = null;
//如果當前位置已經儲存了元素,則需要根據不同的情況來處理這個元素
Node<K, V> currentNode = tempNode;
//1.如果新增的元素的hash(key)相同,並且(key 的物件 和 當前物件 相等 || key!=null && key值和當前的key相等),
// 則需要更新當前節點的值
//2.如果當前節點的型別是紅黑樹,則進入紅黑樹的邏輯進行處理--這裡不做說明
//3.進入單線連結串列的迴圈處理,如果在連結串列中找到和新增的元素的hash(key),key值和當前節點的都相同,並且key!= null的節點
//只需把這個節點的值更新即可,否則直接新增到連結串列的末尾
K currentKey = currentNode.key;
int currentHash = currentNode.hash;
if (currentHash == hash && (currentKey == key || key != null && key.equals(currentKey))) {
modifyNode = currentNode;
} else if (currentNode instanceof TreeNode) {
//TODO jdk1.8後才有的
} else {
for (int bitCount = 0; ; bitCount++) {
Node<K, V> nextNode = currentNode.next;
//如果當前節點的下一個節點為null,則到了單向連結串列的尾節點
//直接把新元素新增到單向連結串列的結尾即可
if (nextNode == null) {
nextNode.next = new Node<>(hash, key, value, null);
if (bitCount >= TREEIFY_THRESHOLD - 1) {
//TODO 如果單向連結串列的元素個數大於所設定的向紅黑樹轉變的條件,則需要處理
}
break;
}
//如果當前節點的下一個節點不為null,則判斷新節點和當前節點是否滿足相同節點的條件
if (nextNode.hash == hash && (nextNode.key == key || key != null && key.equals(nextNode.key))) {
modifyNode = nextNode;
break;
}
//如果沒有遍歷到單向連結串列的末尾,並且新節點不是當前節點
//則繼續遍歷
currentNode = nextNode;
}
}
//如果在單向連結串列中存在節點和新節點相同的條件,則只需要把舊節點的資料修改成新的值即可
if (modifyNode != null) {
V oldValue = modifyNode.value;
//TODO 如果有引數設定,節點已經存在,切節點的值不為null就不在新增,則不需要更新節點的值
modifyNode.value = value;
return oldValue;
}
}
size++;
//如果容器中元素的個數大於
// HashMap容器根據負載因子設定的閾值
// 則需要擴容,並重新分配HashMap中元素的位置
if (size > threshold) {
resize();
}
return null;
}
/**
* 初始化HashMap容器,或者重新分配HashMap容器中元素的位置
* 因為當HashMap容器中元素超過一定的數量,需要擴容,
* 而擴容之後元素hash值發生變化,所以需要重新分配HashMap容器中元素的位置
*/
final Node<K, V>[] resize() {
//定義一個臨時變數儲存舊的HashMap容器中的元素集合
Node<K, V>[] oldTable = table;
//舊HashMap容器的容量大小為
int oldCapacity = oldTable == null ? 0 : oldTable.length;
//舊的擴容標準
int oldThreshold = threshold;
//定義臨時變數儲存新容器容量和新擴容標準
int newCapactity = 0;
int newThreshold = 0;
//如果舊的HashMap容器大於0
if (oldCapacity > 0) {
//如果舊的HashMap容器已經達到HashMap允許的最大容量
//則只需把擴容標準放大到最大即可
if (oldCapacity >= MAXIMUM_CAPACITY) {
threshold = MAXIMUM_CAPACITY;
return oldTable;
}
//如果舊的HashMap容器還沒有達到HashMap允許的最大容量
//則把舊的容量擴大兩倍作為新的容器的容量
newCapactity = oldCapacity << 1;
//如果擴大後的容器容量小於HashMap允許的最大容量
//並且大於等於預設的最小初始容量
//則把舊的擴容標準加倍
if (newCapactity < MAXIMUM_CAPACITY && newCapactity >= DEFAULT_INITIAL_CAPACITY) {
newThreshold = oldThreshold << 1;
}
}
//如果舊的擴容標準大於0
else if (oldThreshold > 0) {
newCapactity = oldThreshold;
} else {
// 如果上面兩個條件都不滿足,則取HashMap容器預設的標準
newCapactity = DEFAULT_INITIAL_CAPACITY;
newThreshold = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
threshold = newThreshold;
//使用新的容量建立HashMap容器
Node<K, V>[] newTable = (Node<K, V>[]) new Node[newCapactity];
//將新HashMap容器賦值給HashMap容器
table = newTable;
//如果舊的HashMap容器不為空,則需要重新分配HashMap容器中的元素
if (oldTable != null) {
for (int i = 0; i < oldCapacity; i++) {
Node<K, V> currentNode = oldTable[i];
//舊HashMap容器當前位置不為空,則需要根據新的容量重新計算該元素應該存放的位置
if (currentNode != null) {
oldTable[i] = null;//為了讓GC回收
//判斷當前節點是否有下下一個節點,如果沒有,則直接進行元素位置的重新計算
if (currentNode.next == null) {
int currentHash = currentNode.hash;
int newIndex = currentHash & (newCapactity - 1);
newTable[newIndex] = currentNode;
} else if (currentNode instanceof TreeNode) {
//TODO 如果當前節點的型別是紅黑樹
} else {
//同一個單向連結串列中元素的hash值是相等的
//因此在新的HashMap容器中,這個連結串列中所有的元素,
// 也還是在相同的位置,並且是連結串列的格式儲存
Node<K, V> highHeadNode = null;
Node<K, V> highTailNode = null;
Node<K, V> lowHeadNode = null;
Node<K, V> lowTailNode = null;
do {
int currentHash = currentNode.hash;
int hashLocation = currentHash & oldCapacity;
if (hashLocation == 0){
//如果尾部節點還沒有設定,則說明此時還沒有頭結點
if(lowTailNode == null){
lowHeadNode = currentNode;
}else{
lowTailNode.next = currentNode;
}
lowTailNode = currentNode;
}else{
if(highTailNode == null){
highHeadNode = currentNode;
}else{
highTailNode.next = currentNode;
}
highTailNode = currentNode;
}
//繼續迴圈當前節點的下一個節點
currentNode = currentNode.next;
} while (currentNode.next != null);
//如果hash&oldCapacity = 0 則說明這個連結串列的元素在新HashMap容器中,陣列下表位置不變
if(lowTailNode != null){
lowTailNode.next = null;
newTable[i] = lowHeadNode;
}
if(highTailNode != null){
highTailNode.next = null;
newTable[i + oldCapacity] = highHeadNode;
}
}
}
}
}
return newTable;
}
6.HashMap的get方法
public V get(Object key) {
Node<K, V> node = null;
node = getNode(hash(key), key);
return node == null ? null : node.value;
}
private Node<K, V> getNode(int hash, Object key) {
Node<K, V>[] tempTable = table;
int capacity = tempTable.length;
//如果當前HashMap容器為空或者其容量為0,則直接返回null
if (tempTable == null || capacity == 0) {
return null;
}
//要查詢的key值,如果存在,則在容器中的位置為
int location = hash & (capacity - 1);
Node<K, V> firstNode = tempTable[location];
if (firstNode == null) {
return null;
}
if (firstNode.hash == hash
&& (firstNode.key == key
|| (key != null && key.equals(firstNode.key)))) {
return firstNode;
}
Node<K,V> nextNode = firstNode.next;
//是不是連結串列
if(nextNode != null){
if(nextNode instanceof TreeNode){
//TODO 紅黑樹結構的處理
}else{
do{
if (nextNode.hash == hash
&& (nextNode.key == key
|| (key != null && key.equals(nextNode.key)))) {
return nextNode;
}
nextNode = nextNode.next;
}while (nextNode != null);
}
}
return null;
}
7.HashMap的remove方法
public V remove(Object key) {
Node<K, V> removeNode = null;
removeNode = removeNode(hash(key), key);
return removeNode == null ? null : removeNode.value;
}
private Node<K, V> removeNode(int hash, Object key) {
Node<K, V> removeNode = null;
Node<K, V> prevNode = null;
Node<K, V>[] tempTable = table;
int capacity = tempTable.length;
//如果當前HashMap容器為空或者其容量為0,則直接返回null
if (tempTable == null || capacity == 0) {
return null;
}
//要查詢的key值,如果存在,則在容器中的位置為
int location = hash & (capacity - 1);
Node<K, V> firstNode = tempTable[location];
if (firstNode == null) {
return null;
}
if (firstNode.hash == hash
&& (firstNode.key == key
|| (key != null && key.equals(firstNode.key)))) {
removeNode = firstNode;
prevNode = firstNode;
}
Node<K, V> nextNode = firstNode.next;
//是不是連結串列
if (removeNode == null & nextNode != null) {
if (nextNode instanceof TreeNode) {
//TODO 紅黑樹結構的處理
} else {
do {
if (nextNode.hash == hash
&& (nextNode.key == key
|| (key != null && key.equals(nextNode.key)))) {
removeNode = nextNode;
break;
}
prevNode = nextNode;
nextNode = nextNode.next;
} while (nextNode != null);
}
}
//如果要刪除的元素存在
if (removeNode != null) {
//如果刪除的是
if (removeNode instanceof TreeNode) {
//TODO 紅黑樹
}
//如果刪除不是單向連結串列,這個位置只有一個元素,並且匹配上了
else if (removeNode == prevNode) {
tempTable[location] = removeNode.next;
}else{
prevNode.next = removeNode.next;
}
--size;
return removeNode;
}
return null;
}
8.自己手寫HashMap原始碼程式碼以及Junit測試類
package com.roger.collection.impl;
import javax.swing.tree.TreeNode;
import java.util.Objects;
public class RogerHashMap<K, V> {
//單向連結串列轉向紅黑樹的條件判斷
static final int TREEIFY_THRESHOLD = 8;
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//HashMap中陣列的最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75F;
static class Node<K, V> {
final int hash;
final K key;
V value;
Node<K, V> next;
public Node(int hash, K key, V value, Node<K, V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
@Override
public String toString() {
return key + " = " + value;
}
//設定成新值,返回舊值
public final V setValue(V newValue) {
V oldValue = value;
this.value = newValue;
return oldValue;
}
@Override
public int hashCode() {
return Objects.hash(key) ^ Objects.hash(value);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Node<?, ?> node = (Node<?, ?>) o;
return Objects.equals(key, node.key) &&
Objects.equals(value, node.value);
}
}
//HashMap容器下一次擴容的標準
//即當HashMap容器中元素的個數大於這個值
//就會觸發HashMap容器擴容
//JDK1.8保證這個值是2的次方數
int threshold;
//負載因子
final float loadFactor;
//HashMap容器中元素的個數
int size;
public RogerHashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
}
public RogerHashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public RogerHashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0) {
throw new IllegalArgumentException("Illegal initial capacity : " + initialCapacity);
}
if (initialCapacity > MAXIMUM_CAPACITY) {
initialCapacity = MAXIMUM_CAPACITY;
}
if (loadFactor < 0) {
throw new IllegalArgumentException("Illegal load factor : " + loadFactor);
}
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
Node<K, V>[] table;
public V get(Object key) {
Node<K, V> node = null;
node = getNode(hash(key), key);
return node == null ? null : node.value;
}
private Node<K, V> getNode(int hash, Object key) {
Node<K, V>[] tempTable = table;
int capacity = tempTable.length;
//如果當前HashMap容器為空或者其容量為0,則直接返回null
if (tempTable == null || capacity == 0) {
return null;
}
//要查詢的key值,如果存在,則在容器中的位置為
int location = hash & (capacity - 1);
Node<K, V> firstNode = tempTable[location];
if (firstNode == null) {
return null;
}
if (firstNode.hash == hash
&& (firstNode.key == key
|| (key != null && key.equals(firstNode.key)))) {
return firstNode;
}
Node<K, V> nextNode = firstNode.next;
//是不是連結串列
if (nextNode != null) {
if (nextNode instanceof TreeNode) {
//TODO 紅黑樹結構的處理
} else {
do {
if (nextNode.hash == hash
&& (nextNode.key == key
|| (key != null && key.equals(nextNode.key)))) {
return nextNode;
}
nextNode = nextNode.next;
} while (nextNode != null);
}
}
return null;
}
public V remove(Object key) {
Node<K, V> removeNode = null;
removeNode = removeNode(hash(key), key);
return removeNode == null ? null : removeNode.value;
}
private Node<K, V> removeNode(int hash, Object key) {
Node<K, V> removeNode = null;
Node<K, V> prevNode = null;
Node<K, V>[] tempTable = table;
int capacity = tempTable.length;
//如果當前HashMap容器為空或者其容量為0,則直接返回null
if (tempTable == null || capacity == 0) {
return null;
}
//要查詢的key值,如果存在,則在容器中的位置為
int location = hash & (capacity - 1);
Node<K, V> firstNode = tempTable[location];
if (firstNode == null) {
return null;
}
if (firstNode.hash == hash
&& (firstNode.key == key
|| (key != null && key.equals(firstNode.key)))) {
removeNode = firstNode;
prevNode = firstNode;
}
Node<K, V> nextNode = firstNode.next;
//是不是連結串列
if (removeNode == null & nextNode != null) {
if (nextNode instanceof TreeNode) {
//TODO 紅黑樹結構的處理
} else {
do {
if (nextNode.hash == hash
&& (nextNode.key == key
|| (key != null && key.equals(nextNode.key)))) {
removeNode = nextNode;
break;
}
prevNode = nextNode;
nextNode = nextNode.next;
} while (nextNode != null);
}
}
//如果要刪除的元素存在
if (removeNode != null) {
//如果刪除的是
if (removeNode instanceof TreeNode) {
//TODO 紅黑樹
}
//如果刪除不是單向連結串列,這個位置只有一個元素,並且匹配上了
else if (removeNode == prevNode) {
tempTable[location] = removeNode.next;
}else{
prevNode.next = removeNode.next;
}
--size;
return removeNode;
}
return null;
}
public V put(K key, V value) {
return putVal(hash(key), key, value);
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
private V putVal(int hash, K key, V value) {
//定義一個臨時變數用來儲存HashMap容器的容量大小
int capacity;
//定義一個新元素在HashMap中數組裡面的下表位置
int currentIndex;
//把HashMap容器的元素賦值給一個臨時變數
Node<K, V>[] tempTable = table;
//如果HashMap容器為空或者容量為0,則需要擴容
if (tempTable == null || tempTable.length == 0) {
tempTable = resize();
}
capacity = tempTable.length;
//計算新增的值將要儲存的位置
currentIndex = (capacity - 1) & hash;
//從HashMap中取出當前位置的元素
Node<K, V> tempNode = tempTable[currentIndex];
//如果HashMap容器的當前位置還沒有儲存元素
//則直接把信元素賦值到這個位置即可
if (tempNode == null) {
tempTable[currentIndex] = new Node<>(hash, key, value, null);
} else {
Node<K, V> modifyNode = null;
//如果當前位置已經儲存了元素,則需要根據不同的情況來處理這個元素
Node<K, V> currentNode = tempNode;
//1.如果新增的元素的hash(key)相同,並且(key 的物件 和 當前物件 相等 || key!=null && key值和當前的key相等),
// 則需要更新當前節點的值
//2.如果當前節點的型別是紅黑樹,則進入紅黑樹的邏輯進行處理--這裡不做說明
//3.進入單線連結串列的迴圈處理,如果在連結串列中找到和新增的元素的hash(key),key值和當前節點的都相同,並且key!= null的節點
//只需把這個節點的值更新即可,否則直接新增到連結串列的末尾
K currentKey = currentNode.key;
int currentHash = currentNode.hash;
if (currentHash == hash && (currentKey == key || key != null && key.equals(currentKey))) {
modifyNode = currentNode;
} else if (currentNode instanceof TreeNode) {
//TODO jdk1.8後才有的
} else {
for (int bitCount = 0; ; bitCount++) {
Node<K, V> nextNode = currentNode.next;
//如果當前節點的下一個節點為null,則到了單向連結串列的尾節點
//直接把新元素新增到單向連結串列的結尾即可
if (nextNode == null) {
nextNode.next = new Node<>(hash, key, value, null);
if (bitCount >= TREEIFY_THRESHOLD - 1) {
//TODO 如果單向連結串列的元素個數大於所設定的向紅黑樹轉變的條件,則需要處理
}
break;
}
//如果當前節點的下一個節點不為null,則判斷新節點和當前節點是否滿足相同節點的條件
if (nextNode.hash == hash && (nextNode.key == key || key != null && key.equals(nextNode.key))) {
modifyNode = nextNode;
break;
}
//如果沒有遍歷到單向連結串列的末尾,並且新節點不是當前節點
//則繼續遍歷
currentNode = nextNode;
}
}
//如果在單向連結串列中存在節點和新節點相同的條件,則只需要把舊節點的資料修改成新的值即可
if (modifyNode != null) {
V oldValue = modifyNode.value;
//TODO 如果有引數設定,節點已經存在,切節點的值不為null就不在新增,則不需要更新節點的值
modifyNode.value = value;
return oldValue;
}
}
size++;
//如果容器中元素的個數大於
// HashMap容器根據負載因子設定的閾值
// 則需要擴容,並重新分配HashMap中元素的位置
if (size > threshold) {
resize();
}
return null;
}
/**
* 初始化HashMap容器,或者重新分配HashMap容器中元素的位置
* 因為當HashMap容器中元素超過一定的數量,需要擴容,
* 而擴容之後元素hash值發生變化,所以需要重新分配HashMap容器中元素的位置
*/
final Node<K, V>[] resize() {
//定義一個臨時變數儲存舊的HashMap容器中的元素集合
Node<K, V>[] oldTable = table;
//舊HashMap容器的容量大小為
int oldCapacity = oldTable == null ? 0 : oldTable.length;
//舊的擴容標準
int oldThreshold = threshold;
//定義臨時變數儲存新容器容量和新擴容標準
int newCapactity = 0;
int newThreshold = 0;
//如果舊的HashMap容器大於0
if (oldCapacity > 0) {
//如果舊的HashMap容器已經達到HashMap允許的最大容量
//則只需把擴容標準放大到最大即可
if (oldCapacity >= MAXIMUM_CAPACITY) {
threshold = MAXIMUM_CAPACITY;
return oldTable;
}
//如果舊的HashMap容器還沒有達到HashMap允許的最大容量
//則把舊的容量擴大兩倍作為新的容器的容量
newCapactity = oldCapacity << 1;
//如果擴大後的容器容量小於HashMap允許的最大容量
//並且大於等於預設的最小初始容量
//則把舊的擴容標準加倍
if (newCapactity < MAXIMUM_CAPACITY && newCapactity >= DEFAULT_INITIAL_CAPACITY) {
newThreshold = oldThreshold << 1;
}
}
//如果舊的擴容標準大於0
else if (oldThreshold > 0) {
newCapactity = oldThreshold;
} else {
// 如果上面兩個條件都不滿足,則取HashMap容器預設的標準
newCapactity = DEFAULT_INITIAL_CAPACITY;
newThreshold = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
threshold = newThreshold;
//使用新的容量建立HashMap容器
Node<K, V>[] newTable = (Node<K, V>[]) new Node[newCapactity];
//將新HashMap容器賦值給HashMap容器
table = newTable;
//如果舊的HashMap容器不為空,則需要重新分配HashMap容器中的元素
if (oldTable != null) {
for (int i = 0; i < oldCapacity; i++) {
Node<K, V> currentNode = oldTable[i];
//舊HashMap容器當前位置不為空,則需要根據新的容量重新計算該元素應該存放的位置
if (currentNode != null) {
oldTable[i] = null;//為了讓GC回收
//判斷當前節點是否有下下一個節點,如果沒有,則直接進行元素位置的重新計算
if (currentNode.next == null) {
int currentHash = currentNode.hash;
int newIndex = currentHash & (newCapactity - 1);
newTable[newIndex] = currentNode;
} else if (currentNode instanceof TreeNode) {
//TODO 如果當前節點的型別是紅黑樹
} else {
//同一個單向連結串列中元素的hash值是相等的
//因此在新的HashMap容器中,這個連結串列中所有的元素,
// 也還是在相同的位置,並且是連結串列的格式儲存
Node<K, V> highHeadNode = null;
Node<K, V> highTailNode = null;
Node<K, V> lowHeadNode = null;
Node<K, V> lowTailNode = null;
do {
int currentHash = currentNode.hash;
int hashLocation = currentHash & oldCapacity;
if (hashLocation == 0) {
//如果尾部節點還沒有設定,則說明此時還沒有頭結點
if (lowTailNode == null) {
lowHeadNode = currentNode;
} else {
lowTailNode.next = currentNode;
}
lowTailNode = currentNode;
} else {
if (highTailNode == null) {
highHeadNode = currentNode;
} else {
highTailNode.next = currentNode;
}
highTailNode = currentNode;
}
//繼續迴圈當前節點的下一個節點
currentNode = currentNode.next;
} while (currentNode.next != null);
//如果hash&oldCapacity = 0 則說明這個連結串列的元素在新HashMap容器中,陣列下表位置不變
if (lowTailNode != null) {
lowTailNode.next = null;
newTable[i] = lowHeadNode;
}
if (highTailNode != null) {
highTailNode.next = null;
newTable[i + oldCapacity] = highHeadNode;
}
}
}
}
}
return newTable;
}
}
package com.roger.collection.impl;
import org.junit.Test;
import static org.junit.Assert.*;
public class RogerHashMapTest {
@Test
public void testPut() {
RogerHashMap<String, Object> rogerHashMap = new RogerHashMap<>(2);
rogerHashMap.put("name", "Roger");
rogerHashMap.put("age", 12);
rogerHashMap.put("address", "上海");
rogerHashMap.remove("name");
System.out.println("name:" + rogerHashMap.get("name"));
System.out.println("age:" + rogerHashMap.get("age"));
System.out.println("address:" + rogerHashMap.get("address"));
}
}