1、ArrayList
1.1 类属性
/**
* Default initial capacity. 默认初始容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
// 默认容量的空的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存储ArrayList元素的数组缓冲区。ArrayList的容量是此数组缓冲区的长度。添加第一个元素时,
* elementData==DEFAULTCAPACITY_empty_elementData的任何空ArrayList都将扩展为DEFAULT_CAPACITY。
*/
transient Object[] elementData;
/**
* 集合大小,初始默认值为0
* @serial
*/
private int size;
1.2 构造方法
/**
* 无参构造方法
* Constructs an empty list with an initial capacity of ten.
* 构造一个初始容量为10的空的集合,但是在集合初始化时,是一个空数组
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity 集合初始容量
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
// >0, 则按照实际容量创建新的数组
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// =0, 则将初始属性空数组赋给elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {
// <0, 抛出非法容量异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
1.3 add()方法执行
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
// 将元素添加到数组中
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
// 如果element是默认初始容量的数组,即第一次添加数据
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 在DEFAULT_CAPACITY(10)和传入的minCapacity(1)获取最大值传给minCapacity
minCapacity = Math.max(DEFAULT_CAPACITY(10), minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //记录集合被修改的次数
// 需要最小容量 - 当前数组容量 > 0时, 说明当前数组不够大,进行数组扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// 获取原数组长度,注意:第一次添加元素时,该值为0
int oldCapacity = elementData.length;
// 扩容后数组长度,为当前数组长度的1.5倍,第一次添加元素时,此处为0
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
//如果扩容之后数组长度仍然小于所需最小容量,则将所需最小容量赋值给新数组长度
//注意:第一次添加元素时,进行数组扩容,此时minCapacity是DEFAULT_CAPACITY(10)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
// 如果大于数组最大长度,则返回Integer.MAX_VALUE,否则返回MAX_ARRAY_SIZE
newCapacity = hugeCapacity(minCapacity);
// 将原数组复制到新的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
// 数组最大值,超过会报内存溢出
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
1.4 总结:
- ArrayList中维护一个Object类型的数组用来存储数据
- 无参构造创建集合时,初始elementData数组容量为0,当第一次添加时,数组才会扩容到默认初始容量10。之后扩容倍数为原来数组长度的1.5倍。
- 如果使用有参构造创建,则elementData容量为指定大小,如需扩容,扩容为原来的1.5倍
2、LinkedList
2.1 内部类
private static class Node<E> {
// 存储的数据
E item;
// 下一个节点
Node<E> next;
// 前一个节点
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
2.2 类属性
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
2.3 构造方法
/**
* Constructs an empty list.
*/
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
2.4 add()方法
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* Links e as last element.
* 将新节点连接到链表后面
*/
void linkLast(E e) {
// 创建一个临时节点l, 指向last。第一次添加时last为null, 即l为null
final Node<E> l = last;
// 创建一个新的节点,prev指向l, next指向null
final Node<E> newNode = new Node<>(l, e, null);
// last节点指向新的节点
last = newNode;
if (l == null)
// 如果l节点为null, first节点指向newNode节点。第一次为null
first = newNode;
else
// 否则的话,l的下一个节点指向新的节点
l.next = newNode;
size++;
modCount++;
}
2.5 总结:
- LinkedList底层维护了一个双向列表
- LinkedList中维护了两个属性first和last,分别指向头节点和尾节点
- 每个节点对象中,维护了prev、next、item三个属性,分别指向前一个节点、下一个节点和自身存储数据
3、HashSet
底层是由HashMap实现的,所以它的源码其实主要就是看HashMap源码
3.1 类属性
private transient HashMap<E,Object> map;
// 作为map的value一个虚拟值
private static final Object PRESENT = new Object();
3.2 构造方法
public HashSet() {
map = new HashMap<>();
}
3.3 add方法
public boolean add(E e) {
// e为添加的值, PRESENT为属性中初始化的object,在这里其实就是去map中给value占个值
return map.put(e, PRESENT)==null;
}
4、LinkedHashSet
LinkedHashSet继承自HashSet
4.1 构造方法
public LinkedHashSet() {
// 初始容量16, 加载因子0.75,第三个参数用来区别于其他构造行数
super(16, .75f, true);
}
// hashSet中构造方法dummy:笨蛋, 用来区别于其他构造函数
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
4.1总结
- LinkedHashSet是HashSet子类,是由LinkedHashMap实现的。
- 底层维护了一个哈希表+双向链表,双向链表用来保证数据插入和取出的次序
5、TreeSet
public TreeSet() {
this(new TreeMap<>());
}
5.1 总结
TreeSe底层是由TreeMap实现的。底层是由红黑树实现
6、HashMap
6.1 内部类
/*
* 链表节点
*/
static class Node<K,V> implements Map.Entry<K,V> {
// 节点hash
final int hash;
// map key值
final K key;
// map value值
V value;
// 下一个节点
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
/**
* 树节点类
*/
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left;
TreeNode<K,V> right;
TreeNode<K,V> prev; // needed to unlink next upon deletion
boolean red;
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}
/**
* Returns root of tree containing this node.
*/
final TreeNode<K,V> root() {
for (TreeNode<K,V> r = this, p;;) {
if ((p = r.parent) == null)
return r;
r = p;
}
}
6.2 类属性
/**
* 默认初始容量 16,必须为2的幂
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* 最大容量,如果指定容量大于这个数,则使用这个值
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* 默认加载因子0.75
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 当链表节点为8时,转为红黑树
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* 当节点小于6时,将树转为链表
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* 最小转为树的容量 64
*/
static final int MIN_TREEIFY_CAPACITY = 64;
/**
* 维护的链表数组
*/
transient Node<K,V>[] table;
/**
* 保存缓存的keySet()
*/
transient Set<Map.Entry<K,V>> entrySet;
// 集合大小
transient int size;
// 扩容临界值,达到临界值进行扩容操作
int threshold;
// 哈希表的加载因子
final float loadFactor;
6.3 构造方法
public HashMap() {
// 无参构造默认加载因子0.75
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
6.4 put()方法
64public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
// 进行hash计算,获得一个int的hash值
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
/**
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent 如果为true,则不改变原来的值
* @param evict 如果为false, the table 则处于创建模式.
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
// 创建一个临时链表数组,后面会将类属性table进行赋值,这么做是为了避免重复去堆中进行属性获取。
Node<K,V>[] tab;
// 创建临时节点p
Node<K,V> p;
int n;
int i;
// 如果数组为null,或者数组长度为0,进行第一次扩容
if ((tab = table) == null || (n = tab.length) == 0)
// 数组长度赋给 n
n = (tab = resize()).length;
// i = (n - 1) & hash通过hash值计算元素应在放在数组的位置,然后对该位置进行判断是否为null
if ((p = tab[i = (n - 1) & hash]) == null)
// 如果该位置为null,则创建一个node节点放在数组该位置上
tab[i] = newNode(hash, key, value, null);
else {
// 如果数组该位置不为null
Node<K,V> e;
K k;
//先比较hash值是否相等,如果hash值相等,则比较key是否相等
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
//如果hash值和key值都相等,将数组该位置链表首节点赋给e
e = p;
else if (p instanceof TreeNode)
// p是红黑树
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
// p是链表
for (int binCount = 0; ; ++binCount) {
// 将链表下一节点赋给e,如果链表下一个节点为null,即是链表尾节点
if ((e = p.next) == null) {
// 则将新节点放在该位置节点后面
p.next = newNode(hash, key, value, null);
// 判断链表长度是否>=8
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
// 对该链表进行转换为红黑树
treeifyBin(tab, hash);
break;
}
// 如果数组此位置的节点的下一节点不为null,则将下一节点拿出来与该元素值进行比较,如果相等,直接退出循环,
// 否则将下一节点赋值给p继续循环进行判断
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
// 放入了相同的key时
if (e != null) { // existing mapping for key
// 将原来node节点的value值
V oldValue = e.value;
// onlyIfAbsent传入为false,取反为真
if (!onlyIfAbsent || oldValue == null)
// 将要添加的value值赋给原来的value值
e.value = value;
afterNodeAccess(e);
// 返回被覆盖的value值
return oldValue;
}
}
++modCount;
// 如果集合个数大于扩容临界值,则进行扩容
if (++size > threshold)
resize();
// HashMap中该方法是一个空方法
afterNodeInsertion(evict);
return null;
}
/**
* 数组进行扩容
*/
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
// 第一次添加元素时,oldTable为null, oldCap为0
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else {
// 第一次添加元素时,newCap = 16
newCap = DEFAULT_INITIAL_CAPACITY;
// newThr = 0.75 * 16 = 12 临界值,当数组已经用到临界值时,进行扩容
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
// 数组扩容的临界值
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
// 实例化链表数组,第一次添加元素时newCap=16
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
// 如果原数组不为Null
if (oldTab != null) {
// 遍历原来的链表数组
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
// 如果链表!=null, 将该位置链表首节点赋值给e
if ((e = oldTab[j]) != null) {
// 将原来位置设为Null
oldTab[j] = null;
// 如果首节点下一节点为null
if (e.next == null)
// 将e放到新链表数组计算过的位置上
newTab[e.hash & (newCap - 1)] = e;
// 如果e是红黑树
else if (e instanceof TreeNode)
// 将树重新拆分
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
// 是链表中其他节点,冲进进行分布
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
/**
* 将链表转换为红黑树
*/
final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index;
Node<K,V> e;
// 判断链表数组是否为null或者数组长度是否<64, n为数组长度
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
// 扩容
resize();
// 判断数组最后一个位置不等于null, 进行红黑树转换,
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K,V> hd = null, tl = null;
do {
TreeNode<K,V> p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
if ((tab[index] = hd) != null)
hd.treeify(tab);
}
}
// For treeifyBin
TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
return new TreeNode<>(p.hash, p.key, p.value, next);
}
6.5 总结
- 底层维护一个链表数组table,有两个内部类Node和TreeNode
- 默认初始容量为16,加载因子为0.75,构造器实例化的时候数组并没有实例化,当第一次添加集合元素时,进行扩容,数组大小才确定为16,之后每次使用到临界值的时候,即原数组长度*加载因子,扩容为原数组的两倍。
- 当集合大小>64并且链表长度>=8时,链表会自动转为红黑树
7、LinkedHashMap
LinkedHashMap继承自HashMap
7.1 内部类
/**
* HashMap.Node subclass for normal LinkedHashMap entries.
*/
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
7.2 类属性
/**
* 双向链表头节点
*/
transient LinkedHashMap.Entry<K,V> head;
/**
* 双向链表的尾节点
*/
transient LinkedHashMap.Entry<K,V> tail;
/**
* 此链接哈希图的迭代排序方法:true表示访问顺序,false表示插入顺序。
*
* @serial
*/
final boolean accessOrder;
7.3 构造方法
public LinkedHashMap() {
super();
accessOrder = false;
}
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
7.4 put()方法
// 调用的是HashMap中的方法,LinkedHashMap中put的区别在于afterNodeInsertion(evict)这个方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
// putVal()方法中newNode会调用LinkedHashMap中的newNode()方法
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
linkNodeLast(p);
return p;
}
// link at the end of list
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
// 将双向链表尾节点给last
LinkedHashMap.Entry<K,V> last = tail;
// 把新创建的p节点给尾节点
tail = p;
// 第一次添加的时候,last为null
if (last == null)
// 第一次添加元素的时候,头节点指向添加的节点
head = p;
else {
//添加节点的前一个节点指向last
p.before = last;
last.after = p;
}
}
// afterNodeInsertion(evict)在hashmap类中是空实现,LinkedHashMap中覆写了这个方法
void afterNodeInsertion(boolean evict) { // evict传入的是true
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
7.5 总结
- LinkedHashMap继承自HashMap类,重写了newCode()等方法。
- 底层维护了数组table + Entry双向链表.
8、TreeMap
8.1 内部类
static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
// 左节点
Entry<K,V> left;
// 右节点
Entry<K,V> right;
// 父节点
Entry<K,V> parent;
boolean color = BLACK;
/**
* Make a new cell with given key, value, and parent, and with
* {@code null} child links, and BLACK color.
*/
Entry(K key, V value, Entry<K,V> parent) {
this.key = key;
this.value = value;
this.parent = parent;
}
/**
* Returns the key.
*
* @return the key
*/
public K getKey() {
return key;
}
/**
* Returns the value associated with the key.
*
* @return the value associated with the key
*/
public V getValue() {
return value;
}
/**
* Replaces the value currently associated with the key with the given
* value.
*
* @return the value associated with the key before this method was
* called
*/
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
}
public int hashCode() {
int keyHash = (key==null ? 0 : key.hashCode());
int valueHash = (value==null ? 0 : value.hashCode());
return keyHash ^ valueHash;
}
public String toString() {
return key + "=" + value;
}
}
8.2 类属性
/**
* 比较器
*/
private final Comparator<? super K> comparator;
private transient Entry<K,V> root;
/**
* 树的节点数
*/
private transient int size = 0;
/**
* The number of structural modifications to the tree.
*/
private transient int modCount = 0;
// Red-black mechanics
private static final boolean RED = false;
private static final boolean BLACK = true;
8.3 构造方法
public TreeMap() {
comparator = null;
}
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
8.4 put()方法
public V put(K key, V value) {
//根节点给t
Entry<K,V> t = root;
// 根节点为null, 第一次添加元素
if (t == null) {
compare(key, key); // type (and possibly null) check
// 创建根节点
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
// 不是第一次添加
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
// 如果比较器不为null
if (cpr != null) {
do {
// 将根节点给parent
parent = t;
// 比较添加节点和父节点key值
cmp = cpr.compare(key, t.key);
// 如果小,将左子节点给父节点循环遍历
if (cmp < 0)
t = t.left;
// 如果大,将右子节点给父节点进行循环遍历
else if (cmp > 0)
t = t.right;
else
// 如果相等,值进行覆盖
return t.setValue(value);
} while (t != null);
}
// 没传入比较器
else {
// 如果添加的Key为null, 报空指针异常
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
// 调用实现Comparable父接口向上转型
Comparable<? super K> k = (Comparable<? super K>) key;
do {
// 第一次是将根节点给父节点
parent = t;
// 进行比较
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
// 以传入的key,value 创建新的Entry节点
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
// 如果小,放左子节点
parent.left = e;
else
// 如果大,放右子节点
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
// 节点插入之后,按照红黑树规则进行调整
private void fixAfterInsertion(Entry<K,V> x) {
x.color = RED;
while (x != null && x != root && x.parent.color == RED) {
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
Entry<K,V> y = rightOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
if (x == rightOf(parentOf(x))) {
x = parentOf(x);
rotateLeft(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
}
} else {
Entry<K,V> y = leftOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
if (x == leftOf(parentOf(x))) {
x = parentOf(x);
rotateRight(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateLeft(parentOf(parentOf(x)));
}
}
}
root.color = BLACK;
}