jdk原始碼+hashmap
阿新 • • 發佈:2021-08-17
一:集合有哪些
1、java.lang
1) Object 1 2) String 1 3) AbstractStringBuilder 1 4) StringBuffer 1 5) StringBuilder 1 6) Boolean 2 7) Byte 2 8) Double 2 9) Float 2 10) Integer 2 11) Long 2 12) Short 2 13) Thread 2 14) ThreadLocal 2 15) Enum 3 16) Throwable 3 17) Error 3 18) Exception 3 19) Class 4 20) ClassLoader 4 21) Compiler 4 22) System 4 23) Package 4 24) Void 4
2、java.util
1) AbstractList 1 2) AbstractMap 1 3) AbstractSet 1 4) ArrayList 1 5) LinkedList 1 6) HashMap 1 7) Hashtable 1 8) HashSet 1 9) LinkedHashMap 1 10) LinkedHashSet 1 11) TreeMap 1 12) TreeSet 1 13) Vector 2 14) Queue 2 15) Stack 2 16) SortedMap 2 17) SortedSet 2 18) Collections 3 19) Arrays 3 20) Comparator 3 21) Iterator 3 22) Base64 4 23) Date 4 24) EventListener 4 25) Random 4 26) SubList 4 27) Timer 4 28) UUID 4 29) WeakHashMap 4
二、hashmap
連結串列:增刪快,查詢慢,時間複雜度是O(n)
陣列:查詢快,增刪慢,時間複雜度是O(1)
Hashmap=連結串列+陣列+紅黑樹(在連結串列超過8,陣列長度超過64,變樹,連結串列小於6變回)
實際上每個元素都是裝滿連結串列的陣列的儲存格式
連結串列的每個node結構是:hash+map+next(指標),hash是通過hash碰撞出來的hashcode,map是鍵值對(k,v)
三、程式碼
// 預設容量16 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 最大容量 static final int MAXIMUM_CAPACITY = 1 << 30;// 預設負載因子0.75 static final float DEFAULT_LOAD_FACTOR = 0.75f; // 連結串列節點轉換紅黑樹節點的閾值, 9個節點轉 static final int TREEIFY_THRESHOLD = 8; // 紅黑樹節點轉換連結串列節點的閾值, 6個節點轉 static final int UNTREEIFY_THRESHOLD = 6; // 轉紅黑樹時, table的最小長度 static final int MIN_TREEIFY_CAPACITY = 64; // 連結串列節點, 繼承自Entry static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; // ... ... } // 紅黑樹節點 static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> { TreeNode<K,V> parent; // red-black tree links TreeNode<K,V> left; TreeNode<K,V> right; TreeNode<K,V> prev; // needed to unlink next upon deletion boolean red; // ... }
// 程式碼1 static final int hash(Object key) { // 計算key的hash值 int h; // 1.先拿到key的hashCode值; 2.將hashCode的高16位參與運算 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } // 程式碼2 int n = tab.length; // 將(tab.length - 1) 與 hash值進行&運算 int index = (n - 1) & hash;
四:經典部分
public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; } final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> first, e; int n; K k; // 1.對table進行校驗:table不為空 && table長度大於0 && // table索引位置(使用table.length - 1和hash值進行位與運算)的節點不為空 if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { // 2.檢查first節點的hash值和key是否和入參的一樣,如果一樣則first即為目標節點,直接返回first節點 if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; // 3.如果first不是目標節點,並且first的next節點不為空則繼續遍歷 if ((e = first.next) != null) { if (first instanceof TreeNode) // 4.如果是紅黑樹節點,則呼叫紅黑樹的查詢目標節點方法getTreeNode return ((TreeNode<K,V>)first).getTreeNode(hash, key); do { // 5.執行連結串列節點的查詢,向下遍歷連結串列, 直至找到節點的key和入參的key相等時,返回該節點 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } // 6.找不到符合的返回空 return null; }
/** * 從呼叫此方法的節點開始查詢, 通過hash值和key找到對應的節點 * 此方法是紅黑樹節點的查詢, 紅黑樹是特殊的自平衡二叉查詢樹 * 平衡二叉查詢樹的特點:左節點<根節點<右節點 */ final TreeNode<K,V> find(int h, Object k, Class<?> kc) { // 1.將p節點賦值為呼叫此方法的節點,即為紅黑樹根節點 TreeNode<K,V> p = this; // 2.從p節點開始向下遍歷 do { int ph, dir; K pk; TreeNode<K,V> pl = p.left, pr = p.right, q; // 3.如果傳入的hash值小於p節點的hash值,則往p節點的左邊遍歷 if ((ph = p.hash) > h) p = pl; else if (ph < h) // 4.如果傳入的hash值大於p節點的hash值,則往p節點的右邊遍歷 p = pr; // 5.如果傳入的hash值和key值等於p節點的hash值和key值,則p節點為目標節點,返回p節點 else if ((pk = p.key) == k || (k != null && k.equals(pk))) return p; else if (pl == null) // 6.p節點的左節點為空則將向右遍歷 p = pr; else if (pr == null) // 7.p節點的右節點為空則向左遍歷 p = pl; // 8.將p節點與k進行比較 else if ((kc != null || (kc = comparableClassFor(k)) != null) && // 8.1 kc不為空代表k實現了Comparable (dir = compareComparables(kc, k, pk)) != 0)// 8.2 k<pk則dir<0, k>pk則dir>0 // 8.3 k<pk則向左遍歷(p賦值為p的左節點), 否則向右遍歷 p = (dir < 0) ? pl : pr; // 9.程式碼走到此處, 代表key所屬類沒有實現Comparable, 直接指定向p的右邊遍歷 else if ((q = pr.find(h, k, kc)) != null) return q; // 10.程式碼走到此處代表“pr.find(h, k, kc)”為空, 因此直接向左遍歷 else p = pl; } while (p != null); return null; }
在無人能夠指引的路上,自己就是明燈