HashMap實現原理簡析及實現的demo(一看就明白)
HashMap底層就是一個數組結構,數組中的每一項又是一個鏈表。
jdk源碼:
1 transient Node<K,V>[] table; 2 static class Node<K,V> implements Map.Entry<K,V> { 3 final int hash; 4 final K key; 5 V value; 6 Node<K,V> next; 7 8 Node(int hash, K key, V value, Node<K,V> next) {9 this.hash = hash; 10 this.key = key; 11 this.value = value; 12 this.next = next; 13 } 14 //..... 15 }
table就是一個Node類的數組,而Node類繼承了Map.Entry<k,v>。每個 Map.Entry 其實就是一個鍵值對對,它還持有一個指向下一個元素的引用"next",這就構成了鏈表。如下圖:
table數組的索引在邏輯上叫做“桶”(bucket),它存儲了鏈表的第一個元素。
好了,直接看HashMap的工作原理:
HashMap基於hashing原理,我們通過put()和get()方法儲存和獲取對象。當我們將鍵值對傳遞給put()方法時,它調用鍵對象的hashCode()方法來計算hashcode,讓後找到bucket位置來儲存值對象。當獲取對象時,通過鍵對象的equals()方法找到正確的鍵值對,然後返回值對象。HashMap使用鏈表來解決碰撞問題,當發生碰撞了,對象將會儲存在鏈表的下一個節點中。 HashMap在每個鏈表節點中儲存鍵值對對象。
當兩個不同的鍵對象的hashcode相同時會發生什麽? 它們會儲存在同一個bucket位置的鏈表中。鍵對象的equals()方法用來找到鍵值對。
實現demo:
1 public class HashMapDemo<K, V> { 2 3 private class Entry<K, V> { 4 int hash; 5 K key; 6 V value; 7 Entry<K, V> next; 8 9 Entry(int hash, K key, V value, Entry<K, V> next) { 10 this.hash = hash; 11 this.key = key; 12 this.value = value; 13 this.next = next; 14 } 15 } 16 17 private static final int DEFAULT_CAPACITY = 1 << 4; 18 19 private Entry<K, V>[] table; 20 21 private int capacity; 22 23 private int size; 24 25 public HashMapDemo() { 26 this(DEFAULT_CAPACITY); 27 } 28 29 public HashMapDemo(int capacity) { 30 if (capacity < 0) { 31 throw new IllegalArgumentException(); 32 } else { 33 table = new Entry[capacity]; 34 size = 0; 35 this.capacity = capacity; 36 } 37 } 38 39 public int size() { 40 return size; 41 } 42 43 public boolean isEmpty() { 44 return size == 0 ? true : false; 45 } 46 47 private int hash(K key) { 48 double tmp = key.hashCode() * (Math.pow(5, 0.5) - 1) / 2; 49 double digit = tmp - Math.floor(tmp); 50 return (int) Math.floor(digit * capacity); 51 } 52 53 public void put(K key, V value) { 54 if (key == null) { 55 throw new IllegalArgumentException(); 56 } 57 int hash = hash(key); 58 Entry<K, V> nEntry = new Entry<K, V>(hash, key, value, null); 59 Entry<K, V> entry = table[hash]; 60 while (entry != null) { 61 if (entry.key.equals(key)) { 62 entry.value = value; 63 return; 64 } 65 entry = entry.next; 66 } 67 nEntry.next = table[hash]; 68 table[hash] = nEntry; 69 size++; 70 } 71 72 public V get(K key) { 73 if (key == null) { 74 throw new IllegalArgumentException(); 75 } 76 int hash = hash(key); 77 Entry<K, V> entry = table[hash]; 78 while (entry != null) { 79 if (entry.key.equals(key)) { 80 return entry.value; 81 } 82 entry = entry.next; 83 } 84 return null; 85 } 86 87 public static void main(String[] args) { 88 HashMapDemo<String, String> map = new HashMapDemo<String, String>(); 89 map.put("1", "11"); 90 map.put("1", "22"); 91 map.put("3", "33"); 92 System.out.println(map.get("1")); 93 System.out.println(map.get("3")); 94 } 95 96 }
面試小問:“如果HashMap的大小超過了負載因子(load factor)定義的容量,怎麽辦?”除非你真正知道HashMap的工作原理,否則你將回答不出這道題。默認的負載因子大小為0.75,也就是說,當一個map填滿了75%的bucket時候,和其它集合類(如ArrayList等)一樣,將會創建原來HashMap大小的兩倍的bucket數組,來重新調整map的大小,並將原來的對象放入新的bucket數組中。這個過程叫作rehashing,因為它調用hash方法找到新的bucket位置。
-------------------待完善
HashMap實現原理簡析及實現的demo(一看就明白)