HashMap原始碼分析(jdk1.8)
private static final long serialVersionUID = 362498820763181265L;
//The default initial capacity - MUST be a power of two.
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //jdk1.6直接寫16,這效率更快??
// The maximum capacity,MUST be a power of two <= 1<<30.
static final
static final float DEFAULT_LOAD_FACTOR = 0.75f; //填充比,裝載因子
/**(jdk1.8新加)
* The bin count threshold for using a tree rather than list for a
* bin.當add一個元素到某個位桶,其連結串列長度達到8時將連結串列轉換為紅黑樹.
* 2< value<=8 時to mesh with assumptions in
*連結串列轉為樹,binCount>=TREEIFY_THRESHOLD-1,-1 for 1st。
*/ //當某個桶中的鍵值對數量大於8個【9個起】,且桶數量大於等於64,則將底層實現從連結串列轉為紅黑樹
// 如果桶中的鍵值對達到該閥值,則檢測桶數量static final int TREEIFY_THRESHOLD= 8; //jdk1.8新加
/** * The bin count threshold for untreeifying a (split) bin during a//太小則轉為連結串列
tab[index] = loHead.untreeify(map);
} */
static final int UNTREEIFY_THRESHOLD = 6;//jdk1.8新加
/** * The smallest table capacity for which bins may be treeified. * (Otherwise the table is resized if too many nodes in a bin.) * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts * between resizing and treeification thresholds. *連結串列轉樹時,if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) resize(); // 即不轉為樹了 */ //當桶數量到達64個的時候,才可能將連結串列轉為紅黑樹static final int MIN_TREEIFY_CAPACITY = 64;//jdk1.8新加
/* ---------------- Fields -------------- */
// jdk1.6 為 transient Entry[] table;
transient Node<K,V>[] table; //儲存元素(位桶)的陣列,length power of two
transient Set<Map.Entry<K,V>> entrySet;
transient int size; // key-value對,實際容量
transient int modCount; //結構改變次數,fast-fail機制
int threshold; // 新的擴容resize臨界值,當實際大小(容量*填充比)大於臨界值時,會進行2倍擴容
final float loadFactor;
Node 內部類
是HashMap內部類(jdk1.6就是Entry),繼承自 Map.Entry這個內部介面,它就是儲存一對對映關係的最小單元,也就是說key,value實際儲存在Node中。與1.6相比,修改了 hashCode()、equals()方法【直接呼叫Object的hashCode、equals方法,而不是copy程式碼過來】,去掉了toString()、recordAccess(HashMap<K,V> m)【the value in an entry is overwritten時呼叫】、recordRemoval(HashMap<K,V> m)【remove entry時呼叫】方法。【鍵值對】
static class Node<K,V>implements Map.Entry<K,V> {
final int hash; //結點的雜湊值,不可變
final K key;
V value;
Node<K,V> next; //指向下一個節點
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
// 由直接實現 變為 呼叫Object的HashCode,實際是一樣的
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
} //按位異或^不同為真,數a兩次異或同一個數b(a=a^b^b)仍然為原值a。
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
returnoldValue;
} // 優化邏輯
public final boolean equals(Object o) {//改為呼叫Object的equals
if (o == this) //記憶體地址(1.8新增)
return true;
if (o instanceof Map.Entry) {//1.6中!(instanceof)返回false
Map.Entry<?,?> e = (Map.Entry<?,?>)o; //新加<?,?>泛型
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
/* jdk 1.6 Entry 的equals方法
public final boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
} */
// 新增的紅黑樹,繼承LinkedHashMap.Entry<K,V>
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; //true表示紅節點,false表示黑節點
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}
/**
* Returns root of tree containing this node.獲取紅黑樹的根
*/
final TreeNode<K,V> root() {
for (TreeNode<K,V> r=this, p;;){//p定義,int a=1,b;不能直接輸出b(未初始化)
if ((p = r.parent) == null) //若改為類似並查集的路徑壓縮(結構改變)
return r;
r = p;
}
}
/**
* Ensures that the given root is the first node of its bin.
*/ //確保root是桶中的第一個元素,將root移到桶中的第一個【平衡思想】
static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {}
/**
* Finds the node starting at root p with the given hash and key.
* The kc argument caches comparableClassFor(key) upon first use
* comparing keys.
*///查詢hash為h,key為k的節點
final TreeNode<K,V> find(int h, Object k, Class<?> kc) { // 詳見get相關
TreeNode<K,V> p = this; …… }
/**
* Calls find for root node.
*/ //獲取樹節點,通過根節點查詢
final TreeNode<K,V> getTreeNode(int h, Object k) { // 詳見get相關
return ((parent != null) ? root() : this).find(h, k, null);
}
/**
* Tie-breaking utility for ordering insertions when equal
* hashCodes and non-comparable. We don't require a total
* order, just a consistent insertion rule to maintain
* equivalence across rebalancings. Tie-breaking further than
* necessary simplifies testing a bit.
*/ //比較2個物件的大小
static int tieBreakOrder(Object a, Object b) {}
/**
* Forms tree of the nodes linked from this node.
* @return root of tree
*/ //將連結串列轉為二叉樹
finalvoid treeify(Node<K,V>[] tab) {} //根節點設定為黑色
/**
* Returns a list of non-TreeNodes replacing those linked from
* this node.
*/ //將二叉樹轉為連結串列
final Node<K,V> untreeify(HashMap<K,V> map) {}
/**
* Tree version of putVal.
*/ //新增一個鍵值對
final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
inth, K k, V v) {}
/**
* Removes the given node, that must be present before this call.
* This is messier than typical red-black deletion code because we
* cannot swap the contents of an interior node with a leaf
* successor that is pinned by "next" pointers that are accessible
* independently during traversal. So instead we swap the tree
* linkages. If the current tree appears to have too few nodes,
* the bin is converted back to a plain bin. (The test triggers
* somewhere between 2 and 6 nodes, depending on tree structure).
*/
final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
boolean movable) {}
/**
* Splits nodes in a tree bin into lower and upper tree bins,
* or untreeifies if now too small. Called only from resize;
* see above discussion about split bits and indices.
*
* @param map the map
* @param tab the table for recording bin heads
* @param index the index of the table being split
* @param bit the bit of hash to split on
*/ //將結點太多的桶分割
finalvoid split(HashMap<K,V> map, Node<K,V>[] tab, intindex, intbit) {}
/* --------------------------------------------------*/
// Red-black tree methods, all adapted from CLR
//左旋轉
static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
TreeNode<K,V> p) {}
//右旋轉
static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
TreeNode<K,V> p) {}
//保證插入後平衡,共5種插入情況
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
TreeNode<K,V> x) {}
//刪除後調整平衡 ,共6種刪除情況
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
TreeNode<K,V> x) {}
/**
* Recursive invariant check
*/ //檢測是否符合紅黑樹
static <K,V> boolean checkInvariants(TreeNode<K,V> t) {}
}
static final int hash(Object key) { // 計算key的hash值hash(key) int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } |
n = tab.length |
table的下標【bucket的index】:(n - 1) & hash |
由上可知:
相關推薦
HashMap原始碼分析(JDK1.8)- 你該知道的都在這裡了
HashMap是Java和Android程式設計師的基本功, JDK1.8對HashMap進行了優化, 你真正理解它了嗎? 考慮如下問題: 1、雜湊基本原理?(答:散列表、hash碰撞、連結串列、紅黑樹)2、hashmap查詢的時間複雜度, 影響因素和原理?
java集合(4):HashMap原始碼分析(jdk1.8)
前言 Map介面雖然也是集合體系中的重要一個分支,但是Map介面並不繼承自Collection,而是自成一派。 public interface Map<K,V> Map集合儲存鍵對映到值的物件。一個集合中不能包含重複的鍵,每個鍵最多
HashMap原始碼分析(jdk1.8)
private static final long serialVersionUID = 362498820763181265L; //The default initial capacity - MUST be a power of two. static final
HashMap主要方法原始碼分析(JDK1.8)
本篇從HashMap的put、get、remove方法入手,分析原始碼流程 (不涉及紅黑樹的具體演算法) jkd1.8中HashMap的結構為陣列、連結串列、紅黑樹的形式 (未轉化紅黑樹時) (轉化為紅黑樹時的情況) 一、關於
java中排序原始碼分析(JDK1.8)
List排序 在開發過程中常用的是jdk自帶的排序 Collections.sort(List<T> list, Comparator<? super T> c); 開啟原始碼如下: @SuppressWarnings({"unchecked",
【Java集合類】LinkedList原始碼分析(jdk1.8)
ArrayList和LinkedList是List介面的兩種實現,具有相同的查詢、插入、刪除操作,只是底層的實現方式不一樣。LinkedList是以雙向連結串列形式實現的集合類。 其增刪操作由於不需要移
HashSet 原始碼分析(jdk1.8)
類繼承關係: (*=>:介面實現) java.lang.Object –java.util.AbstractCollection =>Collection –java.util.AbstractSet =>Set –java
ArrayList原始碼分析(JDK1.8)
不積跬步,無以至千里;不積小流,無以成江海。從基礎做起,一點點積累,加油! ArrayList的定義 public class ArrayList<E> extends AbstractList<E>implements
TreeMap原始碼分析(jdk1.8)
TreeMap的基本概念: TreeMap集合是基於紅黑樹(Red-Black tree)的 NavigableMap實現。該集合最重要的特點就是可排序,該對映根據其鍵的自然順序進行排序,或者根據建立對映時提供的 Comparator 進行排序,具體取決於使
java集合(6):TreeMap原始碼分析(jdk1.8)
前言 TreeMap的基本概念: TreeMap集合是基於紅黑樹(Red-Black tree)的 NavigableMap實現。該集合最重要的特點就是可排序,該對映根據其鍵的自然順序進行排序,或者根據建立對映時提供的 Comparator 進行排序,具體
java集合(7):TreeSet原始碼分析(jdk1.8)
前言 TreeSet是基於 TreeMap 的 NavigableSet 實現。使用元素的自然順序對元素進行排序,或者根據建立 set 時提供的 Comparator 進行排序,具體取決於使用的構造方法。這句話什麼意思呢?就是說,跟HashSet底層是一個Ha
LinkedList原始碼分析(jdk1.8)
LinkedList概述 LinkedList 是 Java 集合框架中一個重要的實現,我們先簡述一下LinkedList的一些特點: LinkedList底層採用的雙向連結串列結構; LinkedList支援空值和重複值(List的特點); LinkedList實現Deque介面,具有雙端佇列的特性,
jdk1.8 HashMap原始碼分析(resize函式)
final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.len
HashMap源碼分析(JDK1.8)
mage -s ret 增刪 函數 tno png log 唯一性 一、HashMap簡介 HashMap是一種基於數組+鏈表+紅黑樹的數據結構,其中紅黑樹部分在JDK1.8後引入,當鏈表長度大於8的時候轉換為紅黑樹。 HashMap繼承於AbstractMap(M
HashMap分析(JDK1.8)
這裡是基於JDK1.8。 可以看出HashMap繼承了AbstractMap,實現了Map。 先看看HashMap中的幾個關鍵的屬性: 預設初始容量是16: 也很好理解,1的二進位制還是1: 向左位移四位: 最大容量很大: 負載因子,主要
LinkedHashMap 原始碼詳細分析(JDK1.8)
1. 概述 LinkedHashMap 繼承自 HashMap,在 HashMap 基礎上,通過維護一條雙向連結串列,解決了 HashMap 不能隨時保持遍歷順序和插入順序一致的問題。除此之外,LinkedHashMap 對訪問順序也提供了相關支援。在一些場景下,該特性很有用,比如快取。在實現上
Object原始碼解析(JDK1.8)
package java.lang; public class Object { /** * 一個本地方法,具體是用C(C++)在DLL中實現的,然後通過JNI呼叫 */ private static native void registerN
String原始碼解析(JDK1.8)
1、string類的定義 public final class String implements java.io.Serializable, Comparable<String>, CharSequence {} java.io.Serializa
ConcurrentHashMap原始碼解析(JDK1.8)
package java.util.concurrent; import java.io.ObjectStreamField; import java.io.Serializable; import java.lang.reflect.ParameterizedType;
AbstractQueuedSynchronizer(1)原始碼解析(jdk1.8)
AbstractQueuedSynchronizer原始碼解析(簡稱AQS) 1.執行流程簡介 第一個執行緒呼叫 reentrantLock.lock(),翻到最前面可以發現,tryAcquire(1) 直接就返回 true了,結束。只是設定了 state=1(連 hea