1. 程式人生 > 其它 >jdk原始碼+hashmap

jdk原始碼+hashmap

一:集合有哪些

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;
}
在無人能夠指引的路上,自己就是明燈