建議多看源碼,若是以爲晦澀能夠戳這裏看源碼解析。html
安利網址:http://www.admin10000.com/document/3322.html,我的以爲分析的挺好java
JDK1.8之前,HashMap的put()方法、get()源碼以下:node
put():mysql
public V put(K key, V value) { // HashMap容許存放null鍵和null值。 // 當key爲null時,調用putForNullKey方法,將value放置在數組第一個位置。 if (key == null) return putForNullKey(value); // 根據key的hashCode從新計算hash值。 int hash = hash(key.hashCode()); // 搜索指定hash值所對應table中的索引。 int i = indexFor(hash, table.length); // 若是 i 索引處的 Entry 不爲 null,經過循環不斷遍歷 e 元素的下一個元素。 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } // 若是i索引處的Entry爲null,代表此處尚未Entry。 // modCount記錄HashMap中修改結構的次數 modCount++; // 將key、value添加到i索引處。 addEntry(hash, key, value, i); return null; }
get():算法
public V get(Object key) { // 若是 key 是 null,調用 getForNullKey 取出對應的 value if (key == null) return getForNullKey(); // 根據該 key 的 hashCode 值計算它的 hash 碼 int hash = hash(key.hashCode()); // 直接取出 table 數組中指定索引處的值, for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; // 搜索該 Entry 鏈的下一個 Entr e = e.next) // ① { Object k; // 若是該 Entry 的 key 與被搜索 key 相同 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
JDK1.8+,HashMap的put()、get()方法源碼以下:sql
put():數據庫
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; // table未初始化或者長度爲0,進行擴容 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // (n - 1) & hash 肯定元素存放在哪一個桶中,桶爲空,新生成結點放入桶中(此時,這個結點是放在數組中) if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); // 桶中已經存在元素 else { Node<K,V> e; K k; // 比較桶中第一個元素(數組中的結點)的hash值相等,key相等 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) // 將第一個元素賦值給e,用e來記錄 e = p; // hash值不相等,即key不相等;爲紅黑樹結點 else if (p instanceof TreeNode) // 放入樹中 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); // 爲鏈表結點 else { // 在鏈表最末插入結點 for (int binCount = 0; ; ++binCount) { // 到達鏈表的尾部 if ((e = p.next) == null) { // 在尾部插入新結點 p.next = newNode(hash, key, value, null); // 結點數量達到閾值,轉化爲紅黑樹 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); // 跳出循環 break; } // 判斷鏈表中結點的key值與插入的元素的key值是否相等 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) // 相等,跳出循環 break; // 用於遍歷桶中的鏈表,與前面的e = p.next組合,能夠遍歷鏈表 p = e; } } // 表示在桶中找到key值、hash值與插入元素相等的結點 if (e != null) { // 記錄e的value V oldValue = e.value; // onlyIfAbsent爲false或者舊值爲null if (!onlyIfAbsent || oldValue == null) //用新值替換舊值 e.value = value; // 訪問後回調 afterNodeAccess(e); // 返回舊值 return oldValue; } } // 結構性修改 ++modCount; // 實際大小大於閾值則擴容 if (++size > threshold) resize(); // 插入後回調 afterNodeInsertion(evict); return null; }
get():數組
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; // table已經初始化,長度大於0,根據hash尋找table中的項也不爲空 if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { // 桶中第一項(數組元素)相等 if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; // 桶中不止一個結點 if ((e = first.next) != null) { // 爲紅黑樹結點 if (first instanceof TreeNode) // 在紅黑樹中查找 return ((TreeNode<K,V>)first).getTreeNode(hash, key); // 不然,在鏈表中查找 do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; }
參考網址:多線程
JDK1.8之前:http://www.cnblogs.com/xwdreamer/archive/2012/06/03/2532832.html併發
JDK1.8+:http://www.cnblogs.com/leesf456/p/5242233.html
Dictionary<String, String> dic = new Hashtable<String, String>(); dic.put("zd", "zd"); dic.put("age", "21"); dic.put("zt", "zt"); dic.put("age", "22"); dic.put("sex", "girl"); Enumeration<String> elemvalues = dic.elements(); Enumeration<String> elemkeys = dic.keys(); while(elemvalues.hasMoreElements() && elemkeys.hasMoreElements()){ System.out.print(elemkeys.nextElement()+":"); System.out.println(elemvalues.nextElement()); }
更多詳情看源碼或戳這裏。
LinkedHashMap默認爲插入順序排序,HashMap爲無序:
public static void main(String[] args) { // TODO Auto-generated method stub Map<String, String> linkmap = new LinkedHashMap<String, String>(); linkmap.put("zd", "zd"); linkmap.put("age", "21"); linkmap.put("sex", "girl"); linkmap.put("zt", "zt"); linkmap.put("age", "22"); for(Entry<String, String> entry:linkmap.entrySet()){ System.out.println(entry.getKey()+":"+entry.getValue()); } System.out.println("==========================="); Map<String, String> hashmap = new HashMap<String, String>(); hashmap.put("zd", "zd"); hashmap.put("age", "21"); hashmap.put("zt", "zt"); hashmap.put("age", "22"); hashmap.put("sex", "girl"); for(Entry<String, String> entry:hashmap.entrySet()){ System.out.println(entry.getKey()+":"+entry.getValue()); } }
結果展現:
更多詳情看源碼或者戳這裏。
更多詳情看源碼或者戳這裏。
優秀博文:http://www.cnblogs.com/yydcdut/p/3959815.html
紅黑樹5點規定:
更多詳情請戳這裏,本人以爲講的很詳細,對紅黑樹也做了詳細的闡述。
EnumMap是專門爲枚舉類型量身定作的Map實現。雖然使用其它的Map實現(如HashMap)也能完成枚舉類型實例到值得映射,可是使用EnumMap會更加高效:它只能接收同一枚舉類型的實例做爲鍵值,而且因爲枚舉類型實例的數量相對固定而且有限,因此EnumMap使用數組來存放與枚舉類型對應的值。這使得EnumMap的效率很是高。
提示:EnumMap在內部使用枚舉類型的ordinal()獲得當前實例的聲明次序,並使用這個次序維護枚舉類型實例對應值在數組的位置。
下面是使用EnumMap的一個代碼示例。枚舉類型DataBaseType裏存放了如今支持的全部數據庫類型。針對不一樣的數據庫,一些數據庫相關的方法須要返回不同的值,示例中getURL就是一個。
//現支持的數據庫類型枚舉類型定義
public enum DataBaseType{ MYSQL,ORACLE,DB2,SQLSERVER }
//DataBaseInfo類中定義的獲取數據庫URL的方法以及EnumMap的聲明。
public class DataBaseInfo{ private EnumMap<DataBaseType, String> urls = new EnumMap<DataBaseType, String>(DataBaseType.class); public DataBaseInfo(){ urls.put(DataBaseType.DB2,"jdbc:db2://localhost:5000/sample"); urls.put(DataBaseType.MYSQL,"jdbc:mysql://localhost/mydb"); urls.put(DataBaseType.ORACLE,"jdbc:oracle:thin:@localhost:1521:sample"); urls.put(DataBaseType.SQLSERVER,"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb"); } }
/** * 根據不一樣的數據庫類型,返回對應的URL * @param type DataBaseType枚舉類新實例 */ public String getURL(DataBaseType type){ return this.urls.get(type); }
在實際使用中,EnumMap對象urls每每是由外部負責整個應用初始化的代碼來填充的。
該博文僅做爲複習記錄,大多數原理及源碼解釋已給出連接,優秀博客須要一塊兒共賞。最後,如有錯誤,望糾正。