一、簡介
public class HashMap<K,V>extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable
基於哈希表的 Map 接口的實現。此實現提供所有可選的映射操作,並允許使用null 值和 null 鍵。(除了非同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證映射的順序,特別是它不保證該順序恆久不變。
此實現假定哈希函數將元素適當地分佈在各桶之間,可爲基本操作(get 和 put)提供穩定的性能。迭代 collection 視圖所需的時間與HashMap 實例的“容量”(桶的數量)及其大小(鍵-值映射關係數)成比例。所以,如果迭代性能很重要,則不要將初始容量設置得太高(或將加載因子設置得太低)。
HashMap 的實例有兩個參數影響其性能:初始容量 和加載因子。容量 是哈希表中桶的數量,初始容量只是哈希表在創建時的容量。加載因子 是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數超出了加載因子與當前容量的乘積時,則要對該哈希表進行rehash 操作(即重建內部數據結構),從而哈希表將具有大約兩倍的桶數。
通常,默認加載因子 (.75) 在時間和空間成本上尋求一種折衷。加載因子過高雖然減少了空間開銷,但同時也增加了查詢成本(在大多數 HashMap 類的操作中,包括get 和 put 操作,都反映了這一點)。在設置初始容量時應該考慮到映射中所需的條目數及其加載因子,以便最大限度地減少 rehash 操作次數。如果初始容量大於最大條目數除以加載因子,則不會發生 rehash 操作。
如果很多映射關係要存儲在 HashMap 實例中,則相對於按需執行自動的 rehash 操作以增大表的容量來說,使用足夠大的初始容量創建它將使得映射關係能更有效地存儲。
注意,此實現不是同步的。
二、構造方法摘要
HashMap() 構造一個具有默認初始容量 (16) 和默認加載因子 (0.75) 的空HashMap。 |
HashMap(int initialCapacity) 構造一個帶指定初始容量和默認加載因子 (0.75) 的空HashMap。 |
HashMap(int initialCapacity, float loadFactor) 構造一個帶指定初始容量和加載因子的空HashMap。 |
HashMap(Map<? extendsK,? extends
V> m) 構造一個映射關係與指定
Map 相同的新 HashMap。 |
三、方法摘要
void |
clear() 從此映射中移除所有映射關係。 |
Object |
clone() 返回此HashMap 實例的淺表副本:並不複製鍵和值本身。 |
boolean |
containsKey(Object key) 如果此映射包含對於指定鍵的映射關係,則返回true。 |
boolean |
containsValue(Object value) 如果此映射將一個或多個鍵映射到指定值,則返回true。 |
Set<Map.Entry<K,V>> |
entrySet() 返回此映射所包含的映射關係的Set 視圖。 |
V |
get(Object key) 返回指定鍵所映射的值;如果對於該鍵來說,此映射不包含任何映射關係,則返回null 。 |
boolean |
isEmpty() 如果此映射不包含鍵-值映射關係,則返回true。 |
Set<K> |
keySet() 返回此映射中所包含的鍵的Set 視圖。 |
V |
put(K key,V value) 在此映射中關聯指定值與指定鍵。 |
void |
putAll(Map<? extendsK,? extends
V> m) 將指定映射的所有映射關係複製到此映射中,這些映射關係將替換此映射目前針對指定映射中所有鍵的所有映射關係。 |
V |
remove(Object key) 從此映射中移除指定鍵的映射關係(如果存在)。 |
int |
size() 返回此映射中的鍵-值映射關係數。 |
Collection<V> |
values() 返回此映射所包含的值的Collection 視圖。 |
四、部分的代碼
package com.jlz;
import java.util.*;
import java.util.Map.Entry;
/**
*
* @author Jlzlight hashmap的遍歷
*/
public class TestHashMap {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HashMap<String, Integer> hm = new HashMap<String, Integer>();
hm.put("one", 1);
hm.put("one", 2);//覆蓋one key的值1
hm.put("two", 3);
// EntrySet效率高相比KeySet
Iterator<Entry<String, Integer>> it = hm.entrySet().iterator();
while (it.hasNext()) {
//方法一
Object str = it.next().getKey();
if(str.equals("two"))
System.out.println("通過Key來獲取值"+hm.get(str));
//方法二
Entry<String, Integer> e = it.next();
System.out.println("Entry獲取Key:"+e.getKey()+"和Value:"+e.getValue());
}
System.out.println("hm.toString"+hm.toString());
System.out.println("Size = "+hm.size());
}
}
五、圖文講解Put方法(盜用)
Put方法的整個處理流程是:計算key的hash值,根據hash值獲得key在table數組中的索引位置,然後迭代該key處的Entry鏈表(我們暫且理解爲鏈表),若該鏈表中存在一個這個的key對象,那麼就直接替換其value值即可,否則在將改key-value節點插入該index索引位置處。如下:
首先我們假設一個容量爲5的table,存在8、10、13、16、17、21。他們在table中位置如下:
然後我們插入一個數:put(16,22),key=16在table的索引位置爲1,同時在1索引位置有兩個數,程序對該“鏈表”進行迭代,發現存在一個key=16,這時要做的工作就是用newValue=22替換oldValue16,並將oldValue=16返回。
在put(31,31),key=31所在的索引位置爲3,並且在該鏈表中也沒有存在某個key=33的節點,所以就將該節點插入該鏈表的第一個位置。