java
集合類主要分為兩大體系,繼承自Collection
的List
和Set
,還有自己作為根的Map
.大體的結(jié)構(gòu)如下.
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
├HashSet
├TreeSet
Map
├Hashtable
├HashMap
└TreeMap
└WeakHashMap
Map
HashMap
通過hash表實現(xiàn)的key-value存儲,按照key的hashCode存儲,可以有null key,
TreeMap
是有序的,通過key的Comparable比較器實現(xiàn)key-value的有序存儲
LinkedHashMap
也是有序的,也是通過key的hashCode存儲,但是遍歷是增加了有序?qū)傩裕磁c加入的順序保持一致
HashMap
HashMap
是基于hash
算法實現(xiàn)的,通過hash因子的作用,將元素"比較平均"的分散,以提高元素查找的命中率.具體的實現(xiàn)原理如下圖:
HashMap
是非線程安全的,允許null key
,當(dāng)threshold=capacity*loadfactor
時會擴容為capacity<<1
,這里capacity
為桶的數(shù)量.
以下是put<k,v>()
方法:
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;
}
可以看到優(yōu)先判斷null key
,然后計算key
的hash
值,通過hash
值與capacity
結(jié)合判斷位于Hash桶
的位置,然后判斷是否有當(dāng)前key
的Entry
,如果存在,替換value
為新值,并返回舊的value
,否則添加一個新的Entry
,并且返回null
,如果一個桶已有至少一個Entry
,則會作為鏈表的第一個元素插入.
HashTable
HashTable
的原理與HashMap
原理類似,只是比較特殊的所有操作加上了對當(dāng)前對象操作的synchronized
,以達到同步鎖的功能,從而實現(xiàn)線程同步.
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
modCount++;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry<K,V> e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
return null;
}
private int hash(Object k) {
// hashSeed will be zero if alternative hashing is disabled.
return hashSeed ^ k.hashCode();
}
從上可知,HashTable
不允許加入null key
,null value
.
還有一個就是,HashTable
初始容量是11.
Collection
Hashset
Hashset
本應(yīng)不在map
系列,但由于Hashset
的實現(xiàn)是基于HashMap
實現(xiàn)的,所以這里列出,
// Dummy value to associate with an Object in the backing Map
private 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<>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
從上可以看出,每次add
一個元素,其實是將該元素當(dāng)做一個key
存入Hashmap
中,value
為一個"dummy value"(一個Object
對象).所以其實是通過Hashmap
保證了元素的唯一.
LinkedList與Queue
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
可知LinkedList
實現(xiàn)了Deque
,而Deque
是豐富了父接口Queue
,
Queue
是Collection接口的子類,Collection
實現(xiàn)了Iterable
,所以是可遍歷的。
而Map
沒有實現(xiàn)Iterable
,但是通過一系列方法如entrySet()
等轉(zhuǎn)換成集合類Set
來實現(xiàn)遍歷功能.
Arraylist
Arraylist
的實現(xiàn)是基于數(shù)組的,初始數(shù)組大小為10,容量不足時擴展為原來的1.5
倍.
Collections
Collections
主要是作為集合方法的一些擴展,有大量的static方法,來幫助我們方便的處理集合,在其中主要摘兩點做一些研究:
不變的empty集合
Collections
含有很多的靜態(tài)空集合方法,其實我們使用這些特性的地方無非有兩處:
- 在自己的方法中
return null
處return Collections.emptyList()
,這樣可以避免上層調(diào)用使用時發(fā)生NullPointException
.
2.返回一個不可變(引用不可變)的集合實例.
@SuppressWarnings("unchecked")
public static final <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
@SuppressWarnings("unchecked")
public static final List EMPTY_LIST = new EmptyList<>();
上面是返回emptyList
的源碼.
不變的empty迭代器
大多數(shù)空方法返回的是不變空集合,但是有以下三個方法返回的是空迭代器:<T> Enumeration<T> emptyEnumeration() (classic iteration method), <T> Iterator<T> emptyIterator(), and <T> ListIterator<T> emptyListIterator()
作用也無非上面返回空集合的那些作用.
@SuppressWarnings("unchecked")
public static <T> Iterator<T> emptyIterator() {
return (Iterator<T>) EmptyIterator.EMPTY_ITERATOR;
}
private static class EmptyIterator<E> implements Iterator<E> {
static final EmptyIterator<Object> EMPTY_ITERATOR
= new EmptyIterator<>();
public boolean hasNext() { return false; }
public E next() { throw new NoSuchElementException(); }
public void remove() { throw new IllegalStateException(); }
}
綜上,我們可以得出結(jié)論,這些空方法可以幫助我們讓編碼更安全,防止空引用的發(fā)生。