原始碼分析之手寫1.7HahMap(三)
阿新 • • 發佈:2018-12-06
public interface ExtMap<K, V> {
// 向集合中插入資料
public V put(K k, V v);
// 根據k 從Map集合中查詢元素
public V get(K k);
// 獲取集合元素個數
public int size();
interface Entry<K, V> {
K getKey();
V getValue();
V setValue(V value);
}
import com.mayikt.jdk7hash.ExtMap.Entry; /** * 手寫jdk1.7的hashMap * * @author zjmiec * */ public class ExtJdk7HaspMap<K, V> implements ExtMap<K, V> { // 1.定義table 存放HashMap 陣列元素 預設不初始化容器 攔截在 Node<K, V>[] table = null; // 2.實際用到table 儲存容量大小 int size; /** * 3.預設負載因子 0.75 擴容用到,負載因子越小。hash衝突機率越低, 根據每個連結串列個數 */ float DEFAULT_LOAD_FACTOR = 0.75f; // 4.table 預設初始大小 16 int DEFAULT_INITIAL_CAPACITY = 16; public V put(K k, V v) { // 1.判斷table陣列大小是否為空(如果為空,做初始化操作) if (table == null) { table = new Node[DEFAULT_INITIAL_CAPACITY]; } /** * 2.判斷陣列 是否需要擴容 為什麼需要擴容? 使用連結串列查詢,連結串列越長,查詢效率越慢,而且, 陣列儲存採用hash下標, * 過短會導致hash衝突的機率增加 如果size大於12,進行擴容陣列,大小為之前的兩倍 */ if (size > DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY) { // 開始對陣列擴容 } // 3.計算hash制定下標 int index = getIndex(k, DEFAULT_INITIAL_CAPACITY); Node<K, V> node = table[index]; if (node == null) { // 沒有hash衝突 node = new Node<K, V>(k, v, null); size++; // return node.setValue(v); } else { Node<K, V> newNode = node; // 發生hash衝突key 直接新增(衝突node)到前面了,不是往後加 while (newNode != null) { if (newNode.getKey().equals(k) || newNode.getKey() == k) { // hash相同,而且equals相同 說明是同一個物件,進行修改值 // node.value=v; return newNode.setValue(v); } else { // 繼續新增 排在前面hashCode 取模餘數相同存 if (newNode.next == null) { // 遍歷node到最後沒有存在相同的key,就會新增node node = new Node<K, V>(k, v, node); size++; } } newNode = newNode.next; } } table[index] = node; return null; } private void resize() { // 1.生成新的table,長度為之前的兩倍 Node<K, V>[] newTable = new Node[DEFAULT_INITIAL_CAPACITY << 1]; // 2.重新計算index的索引,存放到新的table容器 for (int i = 0; i < table.length; i++) { Node<K, V> oldNode = table[i]; while (oldNode != null) { table[i] = null;// 垃圾回收 // 獲取之前的key K oldkey = oldNode.key; // 重新計算index int index = getIndex(oldkey, newTable.length); // 存放在之前的table 原來的node next ExtJdk7HaspMap<K, V>.Node<K, V> next = oldNode.next; // 如果index在newTablez發生衝突,以連結串列方式儲存 // 原來連結串列存放的是A,B,C,新連結串列會儲存為C,B,A // 原來node存放新node的下一個節點 oldNode.next = newTable[index]; // 將之前的node賦值給newTable[index] newTable[index] = oldNode; // oldNode = next; } } // 3.將新的table的賦值給舊的table table = newTable; DEFAULT_INITIAL_CAPACITY = newTable.length; newTable = null; } void print() { System.out.println("-------" + table.length); for (int i = 0; i < table.length; i++) { Node<K, V> node = table[i]; System.out.print("下標位置:" + i); while (node != null) { System.out.print("[ key:" + node.getKey() + ",value:" + node.getValue() + "]"); node = node.next; /* * if(node.next!=null){ node=node.next; }else{ node=null; } */ } System.out.println(); } } public V get(K k) { int index = getIndex(k, DEFAULT_INITIAL_CAPACITY); Node<K, V> node = getNode(table[getIndex(k, DEFAULT_INITIAL_CAPACITY)], k); return node == null ? null : node.value; } public Node<K, V> getNode(Node<K, V> node, K k) { while (node.next != null) { if (node.getKey().equals(k)) { return node; } node = node.next; } return null; } public int size() { // TODO Auto-generated method stub return 0; } public int getIndex(K k, int length) { int hashCode = k.hashCode(); int hash = hashCode % table.length; return hash; } class Node<K, V> implements Entry<K, V> { // 存放Map 集合key private K key; // 存放map 集合value private V value; private Node<K, V> next; public K getKey() { return this.key; } public Node(K key, V value, Node<K, V> next) { super(); this.key = key; this.value = value; this.next = next; } public V getValue() { // TODO Auto-generated method stub return this.value; } public V setValue(V value) { // 設定新值 返回老值 V oldValue = this.value; this.value = value; return oldValue; } } }