?首先,最重要的,HashMap
作為一個我們使用非常多的集合。最常被大家認知的是,它是一個key-value形式存儲數據的數據結構,可以實現快速的存,取操作。
關于HashMap的源碼,我們截取一部分分析:
public class HashMap<K,V>extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable
{/*** The default initial capacity - MUST be a power of two.*/static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16/*** The maximum capacity, used if a higher value is implicitly specified* by either of the constructors with arguments.* MUST be a power of two <= 1<<30.*/static final int MAXIMUM_CAPACITY = 1 << 30;/*** The load factor used when none specified in constructor.*/static final float DEFAULT_LOAD_FACTOR = 0.75f;/*** An empty table instance to share when the table is not inflated.*/static final Entry<?,?>[] EMPTY_TABLE = {};/*** The table, resized as necessary. Length MUST Always be a power of two.*/transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
我們看到了它實現的接口有Serializable,說明他能序列化,有Cloneable,說明能被克隆,有Map<K,V>,說明是一個Map(廢話)。還有幾條有用的信息:第一:有個默認初始容量,第二:有個最大容量,第三:有個調節因子,第四:有個數組。
再往后看,發現這玩意又是由一個數組組成的,而這個數組的初始容量是16,最大容量是2^30。當然這個調節因子這個地方暫且不提。
既然是用數組存儲,我們存的又是Key-Value形式,這數組是怎么運作的呢?這里用往Map中添加數據為例說明:
public V put(K key, V value) {if (table == EMPTY_TABLE) {inflateTable(threshold);}if (key == null)return putForNullKey(value);int hash = hash(key);int i = indexFor(hash, table.length);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;}}modCount++;addEntry(hash, key, value, i);return null;
}
由于篇幅問題,我們就不粘貼太多代碼了,先說一下,我們的hashMap實現是有一個數組實現,數組中存儲的都是Entry<Key,Value>節點,Entry是HashMap的內部類,存儲的是key,value,key的哈希值和下一個節點,具體可以自己查看源碼。
這里我們看到,首先,如果這個數字為空,則先初始化一個數組,如果要添加的key為空,直接進行空Key的添加(這里HashMap是允許有一個key為空的值的)。如果key不為空,則算出key的哈希值,根據哈希值,查找對應數組的位置,如果此key存在,就是說有相同的key,則覆蓋(其實是鏈到后面的串,每個數組元素往后一個鏈表),沒有則直接添加。這么一說其實就簡單了,我們查詢什么的就可以根據哈希值直接定位到相應的Entry,然后扔出來就是了。
然后我們說說HashSet:
public class HashSet<E>extends AbstractSet<E>implements Set<E>, Cloneable, java.io.Serializable
{static final long serialVersionUID = -5024744406713321676L;private transient HashMap<E,Object> map;// Dummy value to associate with an Object in the backing Mapprivate static final Object PRESENT = new Object();/*** Constructs a new, empty set; the backing <tt>HashMap</tt> instance has* default initial capacity (16) and load factor (0.75).*/public HashSet() {map = new HashMap<>();}
這里就可以看出,HashSet底層就是一個HashMap,而它跟HashMap不同的就是它是實現Set接口,所以他的數據必須唯一。
?最后是HashTable:
?由于篇幅問題,就不貼代碼了,跟HashMap差不多,底層也是一個數組。就說一下它跟HashMap主要的區別吧:第一:HashMap允許一個null的key和任意value都有null,而HashTable無論key和value都不能為空。
第二:HashTable可以看做是線程安全的HashMap。