Java容器
Java中容器类可以分为两大类:Collection与Map。
- Collection:存储对象的集合;
- Map:存储键值对。
Collection
Set
TreeSet
基于红黑树,支持有序性操作。
HashSet
基于哈希表实现,支持快速查找,不支持有序性操作。
LinkedHashSet
基于双向链表实现,只能顺序访问,可以快速在其中间插入和删除元素。
List
ArrayList
基于动态数组实现,支持随机访问。
ArrayList源码
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable //基于数组实现,RandomAccess表示支持随机访问。 private static final int DEFAULT_CAPACITY = 10; //默认大小为10 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); } //int newCapacity = oldCapacity + (oldCapacity >> 1); 表示每次扩容为旧容量的1.5倍。 transient Object[] elementData; //使用transient修饰,默认数组不会被序列化。
Vector
和ArrayList相似,是线程安全的(除了私有方法,其他方法都使用了synchronized修饰)。
public synchronized void copyInto(Object[] anArray) { System.arraycopy(elementData, 0, anArray, 0, elementCount); } public synchronized void trimToSize() { modCount++; int oldCapacity = elementData.length; if (elementCount < oldCapacity) { elementData = Arrays.copyOf(elementData, elementCount); } } public synchronized int capacity() { return elementData.length; } public synchronized boolean isEmpty() { return elementCount == 0; } private void grow(int minCapacity) { // overflow-conscious code 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); } //扩容的时候看传入的参数,如果大于0就扩大为原来基础上加上你传入的参数,如果小于0就扩大为原来的两倍(实际开发中因该很少调用构造函数,所以大多数情况是扩大为原来的两倍)。
``
LinkedList
基于双向链表实现,只能顺序访问,但是可以快速在链表中间插入和删除元素。
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; } } //使用双向链表且每个节点存储了上下两个节点。 transient Node<E> first; transient Node<E> last; //每个链表存储了first和last指针
Queue
LinkedList
常用于实现双向队列
PriorityQueue
基于堆结构实现,可以实现优先队列。
Map
TreeMap
基于红黑树实现
HashMap
基于哈希表实现
在jdk1.7及以前的时候使用的是数组和链表,在jdk1.8及以后使用的是数组、链表和红黑树。
transient Entry[] table; //不会被序列化
拉链法
HashMap<String, String> map = new HashMap<>(); map.put("K1", "V1"); map.put("K2", "V2"); map.put("K3", "V3");
- 新建一个 HashMap,默认大小为 16;
- 插入 <K1,V1> 键值对,先计算 K1 的 hashCode 为 115,使用除留余数法得到所在的桶下标 115%16=3。
- 插入 <K2,V2> 键值对,先计算 K2 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6。
- 插入 <K3,V3> 键值对,先计算 K3 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6,插在 <K2,V2> 前面。
注意:链表的插入是头插法的方式进行的。
查找:
- 计算键值对所在的桶;
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
扩容的时候扩大为原来的2倍。
void addEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<>(hash, key, value, e); if (size++ >= threshold) resize(2 * table.length); }
HashTable
与HashMap类似,是线程安全的,但不推荐使用(推荐使用ConcurrentHashMap)
LinkedHashMap
使用双向链表来维护元素的顺序,顺序插入顺序或者最近最少使用(LRU)顺序。
继承HashMap
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
来源:https://www.cnblogs.com/we9999/p/12409330.html