简单了解java中的集合底层的存储结构。能力有限,如果有什么不对的地方希望大家指出,不胜感激
单向链表
单向链表可以很容易实现一个栈,详情请点击链接
双向链表
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
Node<E> node(int index) {
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
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;
}
}
//添加元素到队尾
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++;
}
//删除元素,先遍历集合找到对应的node然后调用这个方法
E unlink(Node<E> x) {
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;
}
}
数组结构
java.util.Vector
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//底层是数组结构
protected Object[] elementData;
//元素数量
protected int elementCount;
//数组的扩展数量(如果有指定那么每次按指定数量扩展数组,如果没有指定,那么数组直接扩展为原数组2倍)
protected int capacityIncrement;
// 新增元素的时候,会判断当前数组是否可以存下这个对象,如果存不下就扩展
// 如果指定扩展数量就扩展固定数量否则,直接将原数组扩大一倍
//希望扩展的最小数量 minCapacity
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
// 删除元素
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
int numMoved = elementCount - index - 1;
if (numMoved > 0)
//将elementData[index+1]开始后面所有的元素 复制到elementData[index]开始
//删除元素不改变数组大小
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--elementCount] = null;
return oldValue;
}
}
java.util.ArrayList
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{ //默认初始数组大小 10
private static final int DEFAULT_CAPACITY = 10;
//底层是数组结构
transient Object[] elementData;
private int size;//元素个数
//当数组存不下要保存的所有元素的时候增长 50%
//最小数量 minCapacity
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 增长原长度的50%
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);
}
// 从头开始删除找到的第一个元素
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
//将elementData[index+1]开始后面所有的元素 复制到elementData[index]开始
//删除元素不改变数组大小
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
}
Set
java.util.HashSet 由java.util.HashMap实现
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable
{
private transient HashMap<E,Object> map;
// value值
private static final Object PRESENT = new Object();
}
java.util.TreeSet 由 java.util.TreeMap 实现
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
private transient NavigableMap<E,Object> m;
// value值
private static final Object PRESENT = new Object();
}
Map
java.util.HashMap
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
transient Node<K,V>[] table;// 底层是数组加链表结构,每个数组上的元素都是链表的开始
transient Set<Map.Entry<K,V>> entrySet;// 是内部类EntrySet,具体方法依赖于HashMap自己
transient int size;//元素个数
//如果有指定容量大小,那么该值是通过java.util.HashMap#tableSizeFor方法计算阀值,并以此阀值作为初始数组的大小 值只能是 16*2^n;
//如果是使用默认的那么该值是java.util.HashMap#resize来赋值=(初始用量*加载因子)
//当元素个数大于阀值的时候数组就扩展一倍,阀值一样扩大一倍resize方法进行修改
int threshold;//阀值 最大是 Integer.MAX_VALUE
final float loadFactor;// 加载因子,用来计算阀值
final Node<K,V>[] resize(){
if (oldCap > 0) {
//oldCap原数组大小,如大于0,就是已经初始化了过了
if (oldCap >= MAXIMUM_CAPACITY) { //如果已经大于了最大容量 1 << 30
threshold = Integer.MAX_VALUE;//直接设置阀值为最大整数
return oldTab;
//否则的话原大小扩容至2倍,原阀值也扩容至2倍
} else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
} else if (oldThr > 0) // 初始容量等于原阀值
//如果指定了初始容量和加载因子,会先计算阀值(16*2^n),初始化数组的时候走到这一步,新数组=阀值的容量
newCap = oldThr;
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
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);
}
//创建一个新的数组长度为newCap,并将原来的数据(如果原数组有值的话)填入到新的数组,位置是根据hash重新计算的。所以有可能会变。这就是为什么不保证顺序
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
//存值之前先判断数组,如果数组为空就调用resize()进行初始化
//(数组长度-1)&hash就是新元素的数组下标,如果该位置没有值就存在这个位置
//如果值就和这个元素开始的链表进行判断看是否相等(依赖equals方法),key相等的更新value
// key不相等的就创建新的Node,用该链表的最后一个节点的next指向新创建的节点
//最后判断元素数量和阀值比较
if (++size > threshold)
resize();
}
// 单向链表,HashMap中保存的元素,如果有hash值相同,就保存下一个元素的引用
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
}
// 迭代器的具体实现,依赖HashMap.HashIterator,最后是调用HashMap.table[]中直接拿Node
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}
abstract class HashIterator {
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot
HashIterator() {
expectedModCount = modCount;
Node<K,V>[] t = table;
current = next = null;
index = 0;
// 找到数组中第一个节点,让next指向这个值
if (t != null && size > 0) {
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
//返回当前值并让next指向下一个节点
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
//如果当前节点有下一个节点的引用,就让next指向下一个节点
if ((next = (current = e).next) == null && (t = table) != null) {
//如果当前节点没有下一个节点的引用,就从保存的index开始往后找数组中的第一个节点
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}
}
}
java.util.LinkedHashMap
继承与HashMap重写了newNode();
在HashMap的基础上每个节点增加了前后元素的引用,形成了一个双向链表,以此保证顺序;
节点使用静态内部类java.util.LinkedHashMap.Entry继承自的HashMap.Node,保存上一个下一个元素
存取有序依赖链表结构
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
{
transient LinkedHashMap.Entry<K,V> head;
transient LinkedHashMap.Entry<K,V> tail;
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;
}
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
}
java.util.TreeMap
树形结构,不是特别了解,画的不对的地方希望指出。
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
private final Comparator<? super K> comparator;//比较器
private transient Entry<K,V> root = null;//根节点
//保存元素
public V put(K key, V value) {
Entry<K,V> t = root;
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;
// 根节点不为空需要进行比较
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);//节点相等会更新value,并返回原value
//一直找到t==null
} while (t != null);
} else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
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,那么已最后一个不为null的节点为父节点创建新的节点
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;
}
//遍历依赖的方法先找到第一个元素getFirstEntry(),再依次找下一个元素方向 左中右
//找到左边第一个元素
final Entry<K,V> getFirstEntry() {
Entry<K,V> p = root;
if (p != null)
while (p.left != null)
p = p.left;
return p;
}
//根据传入的节点找到下一个节点
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
if (t == null)
return null;
else if (t.right != null) {
Entry<K,V> p = t.right;
while (p.left != null)
p = p.left;
return p;
} else {
Entry<K,V> p = t.parent;
Entry<K,V> ch = t;
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
//元素类型
static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
Entry<K,V> left = null;//左叶子节点
Entry<K,V> right = null;//右叶子节点
Entry<K,V> parent;//父节点
}
}