集合類繼承圖
其中常見的有:
HashMap、TreeMap、ConcurrentHashMap、ArrayList、LinkedList
ArrayList
特點:底層數據結構是數組。線程不安全。初始大小爲10,最大容量爲最大爲Integer.MAX_VALUE,即((2^31)-1)2147483647。
add(e)實現:
首先去檢查一下數組的容量是否足夠
擴容到原來的1.5倍
第一次擴容後,如果容量還是小於minCapacity,就將容量擴充爲minCapacity。
足夠:直接添加
不足夠:擴容
add(e,i)實現:
檢查角標
空間檢查,如果有需要進行擴容
插入元素
擴容方法:
擴容大小爲1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1);
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
總結:
ArrayList是基於動態數組實現的,在增刪時候,需要數組的拷貝複製,所以增刪時效率較低但是在讀取修改時效率高。
ArrayList的默認初始化容量是10,每次擴容時候增加原先容量的一半,也就是變爲原來的1.5倍
刪除元素時不會減少容量,若希望減少容量則調用trimToSize()
它不是線程安全的。它能存放null值。
LinkedList
特點:底層數據結構是雙向鏈表。線程不安全。
add方法:
往鏈表的最後添加數據
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
remove方法:
如果添加的o爲空則刪除最後一個節點,不爲空則遍歷全部節點找到相同的然後解鏈。
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
解鏈方法:
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
總結:
底層數據結構是雙向鏈表。線程不安全。增刪速度較快但查改較慢。
Vector(瞭解)
底層數據結構是數組。線程安全,每次擴容增加原先的2倍
HashMap
特點:
1、底層結構爲散列表(哈希表)+紅黑樹實現(數組+鏈表-->散列表)。初始容量爲16最大容量爲2的31次方。桶滿並且散列表容量大於64時會從鏈表變成紅黑二叉樹 , 默認當一個元素被添加到至少有8個元素的桶中時桶中鏈表變紅黑樹 ,當一個元素被刪除後桶中只剩6個元素時紅黑樹變鏈表
2、裝填因子默認爲0.75,也就是如果表中超過了75%的位置已經填入了元素,那麼這個表就會用雙倍的桶數自動進行再散列,並擴容兩倍。
3、初始容量和裝載因子對HashMap影響挺大的
hash值計算方法:
將hash值和他的高16位進行異或運算。(異或運算:相同爲0,不同爲1)
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
put方法:
1、當散列表爲空時,調用resize初始化散列表
2、查看桶是否爲空,爲空則直接放入
3、若不爲空查找鏈表有沒有key相同的元素,如果有則將value值覆蓋。
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
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;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
LinkedList
特點:
1、底層是散列表和雙向鏈表。繼承於HashMap所以如初始容量、裝載因子等參數函數和HashMap相同。
2、允許爲null,不同步
3、插入的順序是有序的(底層鏈表致使有序)
4、裝載因子和初始容量對LinkedHashMap影響是很大的~
5、LinkedHashMap遍歷的是內部維護的雙向鏈表,所以說初始容量對LinkedHashMap遍歷是不受影響的
TreeMap
特點:
1、TreeMap底層是紅黑樹,它方法的時間複雜度都不會太高:log(n),map集合有序。
2、非同步
3、TreeMap實現了NavigableMap接口,而NavigableMap接口繼承着SortedMap接口,致使我們的TreeMap是有序的!
4、使用Comparator或者Comparable來比較key是否相等與排序的問題~
ConcurrentHashMap
1、底層結構是散列表(數組+鏈表)+紅黑樹,這一點和HashMap是一樣的。
2、Hashtable是將所有的方法進行同步,效率低下。而ConcurrentHashMap作爲一個高併發的容器,它是通過部分鎖定+CAS算法來進行實現線程安全的。CAS算法也可以認爲是樂觀鎖的一種~
3、在高併發環境下,統計數據(計算size…等等)其實是無意義的,因爲在下一時刻size值就變化了。
4、get方法是非阻塞,無鎖的。重寫Node類,通過volatile修飾next來實現每次獲取都是最新設置的值
5、ConcurrentHashMap的key和Value都不能爲null