Java主要容器
总结容器中重要使用的数据结构。
先罗列接口和抽象类(主要的)的组织结构:
接口:
-Collection
--List
--Set
---SortedSet
----NavigableSet
--Queue
---Deque
-Map
--SortedMap
---NavigableMap
抽象类:
-AbstractCollection
--AbstractList
---AbstractSequentialList
----LinkedList(1.掌握)
---ArrayList(2.掌握)
---Vector(3.掌握)
----Stack(4.掌握)
--AbstractSet
---HashSet(5.掌握)
---TreeSet(6.掌握)
--ArrayDeque(7.掌握)
-AbstractMap
--HashMap(8.掌握)
--TreeMap(9.掌握)
--IdentityHashMap(10.熟悉)
--WeakHashMap(11.熟悉)
-Hashtable(12.掌握)
-LinkedHashMap(13.掌握)
1.LinkedList
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
基本结构:
Node<E> first;//头指针
Node<E> last;//尾指针
结构特点:
1.双向链表
2.not synchronized(非同步)
思想:
采用双向链表的方式进行数据存储。每个结点含有三个域:一个数据域,两个指针域(prev,next)。
优点:
1.在内存无限制的环境下,数据存储量不限。
2.在数据的插入、删除操作上简单。只需要改变prev和next的指向对象。
3.数据的写入顺序和逻辑存储顺序一致
缺点:
1.每查找特点的元素,需要遍历整个链表。最坏的时间复杂度为o(n)
2.ArrayList
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
基本结构:
transient Object[] elementData;//数组
private static final int DEFAULT_CAPACITY = 10;//默认存储大小
private int size;//记录数据
结构特点:
1.动态数组
2.not synchronized(非同步)
思想:
采用动态数组对数据进行存储,设置数组默认大小,超过容量扩容,每次扩容大小为原始容量的0.5倍。数组最大
容量为Integer.MAX_VALUE。
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);
}
优点:
1.利用数组的优点,随机读取速度快。时间复杂度O(1)。
2.数据的写入顺序和逻辑存储顺序一致
缺点:
1.插入和删除改变了数组的结构,数组中其他元素需要移位。时间开销最坏为o(n)
2.数组容量有限,数组过大时,扩容开销也大。
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));//扩容的核心:数组的拷贝
return copy;
}
3.Vector
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
基本结构:
protected Object[] elementData;//数组
protected int elementCount;//计数
protected int capacityIncrement;//数组增量
结构特点:
1.动态数组
2.synchronized(同步)
优点:1.同ArrayList
2.线程安全
缺点:1.同ArrayList
2.在不需要线程安全的情况下,使用Vector效率低于ArrayList
不同于ArrayList之处:
1.Vector同步,ArrayList不同步
2.Vector自定义数组扩容大小,ArrayList系统默认。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//不指定capacityIncrement时,扩容一倍;指定capacityIncrement,按capacityIncrement扩容
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);
}
4.Stack
public class Stack<E>
extends Vector<E>
基本结构:
protected Object[] elementData;//数组
protected int elementCount;//计数
结构特点:
1.栈
2.synchronized(同步)
2.动态数组
优点:1.先进后出
2.线程安全
3.争议:Stack实现了Vector,可以调用父类的方法,不但可以对栈顶元素进行操作,还可以进行随机
元素的增删查改。
缺点:1.容量有限
5.HashSet
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, Serializable
基本结构:
private transient HashMap<E,Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
结构特点:
1.动态数组+单向链表+红黑树
2.not synchronized(非同步)
3.散列表
思想:
1.利用HashMap 的键的唯一性,构建“集”。
2.集通过数据的hashcode值进行映射地址。
3.采用单向链表对同一地址的数据进行存储
hash映射方法:
见HashMap
优点:1.读取、插入、删除速度时间短
缺点:1.存储地址根据hash映射,无法顺序存储
6.TreeSet
public class TreeSet<E>
extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, Serializable
基本结构:
private transient NavigableMap<E,Object> m;//TreeMap
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
结构特点:
1.红黑树
2.not synchronized(非同步)
思想:
1.利用红黑树的二分查找思想,对数据进行顺序存储
注意:存储的元素类必须实现Comparable接口 或者 在构造方法中给出Comparator并实现compare方法
优点:1.顺序存储
缺点:1.相比HashSet类,TreeSet类插入元素和删除元素速度较慢。因为需要重新对红黑数进行平衡。
7.ArrayDeque
public class ArrayDeque<E>
extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable
基本结构:
transient Object[] elements; // non-private to simplify nested class access
/**
* The index of the element at the head of the deque (which is the
* element that would be removed by remove() or pop()); or an
* arbitrary number equal to tail if the deque is empty.
*/
transient int head;
/**
* The index at which the next element would be added to the tail
* of the deque (via addLast(E), add(E), or push(E)).
*/
transient int tail;
结构特点:
1.动态数组
2.栈
3.队列
4.双向队列
5.循环队列
思想:
对数组指定一个头指针和尾指针。即可以头插头删,也可以尾插尾删。不可以对非头尾结点进行查找。
栈:数组进行尾插尾删
循环队列:头删尾入。当头遇到尾时,数组扩容。
private static final int MIN_INITIAL_CAPACITY = 8;//默认数组大小
private void doubleCapacity() {//数组扩容1倍
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p; // number of elements to the right of p
int newCapacity = n << 1;
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
Object[] a = new Object[newCapacity];
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);
elements = a;
head = 0;
tail = n;
}
public void addFirst(E e) {//头插
if (e == null)
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;//循环数组
if (head == tail)//头遇到尾
doubleCapacity();//扩容
}
public void addLast(E e) {//尾插
if (e == null)
throw new NullPointerException();
elements[tail] = e;
if ( (tail = (tail + 1) & (elements.length - 1)) == head)//循环数组
doubleCapacity();//扩容
}
优点:1.实现栈和队列两个数据结构
2.循环数组利用空间
缺点:1.not synchronized(非同步)
8.HashMap
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
基本结构:
transient Node<K,V>[] table;//数组
static class Node<K,V> implements Map.Entry<K,V>;//单向链表
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> ;//红黑树
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;//默认数组容量
static final int MAXIMUM_CAPACITY = 1 << 30;//最大数组容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;//装填因子
static final int TREEIFY_THRESHOLD = 8;//树化阈值
static final int UNTREEIFY_THRESHOLD = 6;//链化阈值
transient int size;//键值对数
int threshold;//临界容量
结构特点:
1.动态数组+单向链表+红黑树
2.键值对映射
3.散列表
hash映射方法:
static final int hash(Object key) {
int h;
//hashcode值 异或 h >>> 16
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
数组下标地址映射:
/*
*hash 为 数的hash映射值,n为数组容量。i为映射下标值
*/
tab[i = (n - 1) & hash]
同一hash映射值存储于同一个数组单元中,每个单元默认采用单向链表连接数据。
当链表长度小于 8 时,采用 单向链表 连接
单向链表查找元素速度为o(n)
当链表长度大于 8 时,转换为 红黑树 存储
红黑树查找元素采用二分查找,速度为log(n)
当 table数组元素 size 大于 threshold 时,进行扩容 和 再散列。
if (++size > threshold)
resize();
扩容
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)//容量扩充一倍
newThr = oldThr << 1; // double threshold
新临界阈值:
float ft = (float)newCap * loadFactor;//新容量 * 装填因子
再散列:
对每个元素进行重新的hash映射地址。
若新的下标元素集元素低于 UNTREEIFY_THRESHOLD 值 时,红黑树 转为 单向链表
注意:
jdk1.8之前,HashMap 只采用单向链表来解决哈希冲突。
jdk1.8及以后,HashMap采用 单向链表+红黑树的方式来综合使用,大大提高了查找的效率。
优点:1.动态数组+链表
缺点:1.not synchronized(非同步)
9.TreeMap
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, Serializable
基本结构:
private final Comparator<? super K> comparator;//比较器接口
private transient Entry<K,V> root;//根节点
/**
* The number of entries in the tree
*/
private transient int size = 0;//键值对数
/**
* The number of structural modifications to the tree.
*/
private transient int modCount = 0;//修改计数
static final class Entry<K,V> implements Map.Entry<K,V>;//红黑树结构
结构特点:
1.红黑树
思想:利用红黑树对数据的二分排列,实现数据的有序存储
注意:元素必须实现Comparable接口或者提供实现了compare方法的Comparator接口
优点:1.查找,插入,删除速度快
缺点:1.在非要求顺序的情况下,HashMap更快
2.not synchronized(非同步)
10.IdentityHashMap
public class IdentityHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Serializable, Cloneable
基本结构:
private static final int DEFAULT_CAPACITY = 32;
private static final int MINIMUM_CAPACITY = 4;
private static final int MAXIMUM_CAPACITY = 1 << 29;
transient Object[] table;
transient int modCount;
结构特点:
1.动态数组+单向链表
2.散列表
思想:
private static int hash(Object x, int length) {
int h = System.identityHashCode(x);//利用System.identityHashCode方法映射hash
// Multiply by -127, and left-shift to use least bit as part of hash
return ((h << 1) - (h << 8)) & (length - 1);
}
优点:1.每个不同的对象都对应着不同的地址,即使内容相同
缺点:not synchronized(非同步)
11.WeakHashMap
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>
基本结构:
Entry<K,V>[] table;
private int threshold;
private final float loadFactor;
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();//元素引用队列
结构特点:
1.动态数组+单向链表
2.散列表
3.引用队列
思想:对无其他对象访问的键值对(本数组下标除外),添加到queue中,并结合jvm垃圾回收进行处理。
优点:1.内存友好
缺点:not synchronized(非同步)
12.Hashtable
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, Serializable
属性、结构同HashMap一致
优点:synchronized(同步)
13.LinkedHashMap
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;
final boolean accessOrder;//元素发生改变,就将该元素移到数组最后
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);
}
}
结构特点:
1.将 HashMap.Node 的 四个域 变成 六个域,添加了 before 域 和 after 域。用于存储前一个结点和后一个结点,建立顺序关系。
优点:1.按数据存入顺序存储
2.aeecessOrder为true时,常操作的元素总在链表最后,最近不常用的数据总在最前面。