Java容器
![java容器](https://i-blog.csdnimg.cn/blog_migrate/f43a01400eb699036542dd1f34340627.png)
ps:上图中,Map到Collection中间并没有实现关系。
整体说明:
从上图可知List、Set和Queue都继承了Collection接口。其中List的具体实现有ArrayList和LinkedList。Set的实现有HashSet和TreeSet,Queue的实现有PriorityQueue等。
Map是1个接口,对应的实现有HashMap、HashTable和TreeMap等。
Map(HashMap、Hashtable、TreeMap和ConcurrentHashMap)
HashMap
继承AbstractMap实现Map。
底层结构:数组+链表。key和value均可为null。线程不安全。
默认初始capacity为16,负载极限为0.75(时间和空间的一个折中)。说明,当capacity一定时,负载极限(0~1)越大,该hashmap能够装更多的对象。通常设置负载极限一般是为了以时间换空间(负载极限高)或者以空间换时间(负载极限低)。
当负载因子(size/capacity)大于负载极限时,HashMap将进行扩容,capacity变为原来的二倍,扩容后将原有的对象重新放入桶中(此过程称为rehash)。扩容后对象所在的桶的位置的索引只可能是旧的索引或者旧的索引+capacity。
如果两个key做hash后对capacity取模是一样的(即hash冲突),那么这两个对象将以链表的形式放在桶的同1个位置,有先后顺序,取值时做equal比较。当链表长度超过8之后会转换成红黑树(说明:当小于6时链表的查询速度是比红黑树快的,当大于8时链表的查询速度不如红黑树,这里说的查询速度包含从链表转换成红黑树的耗时,因此大于8会转换成红黑树,当小于6时会转换成链表)。
Hashtable
继承Dictionary实现Map
底层结构:数组+链表。key和value均不可为null。线程安全。
扩容:原理和hashmap一样,区别扩容后的capacity为原capacity*2+1
线程安全:在修改数据时锁住整个HashTable,效率低。
TreeMap
继承AbstractMap实现NavigableMap(继承了SortedMap)
底层结构:红黑树。是1个有序的key-value集合。
实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。 它的iterator 方法返回的迭代器是fail-fastl
TreeMap的增删改查和统计相关的操作的时间复杂度都为 O(logn)但是它是有序的
因此主要运用:需要基于排序的统计功能。
ConcurrentHashMap
继承AbstractMap实现ConcurrentMap
底层结构:分段数组+链表,线程安全。
线程安全:实现方式,只锁住1个bucket。对于跨段的操作,如size,则会锁住整个表。
List(ArrayList、LinkedList和Vector)
ArrayList
继承AbstractList实现List,RandomAccess
底层结构:数组。线程不安全。
默认size为10,扩容:1.5*oldsize(int newCapacity = oldCapacity + (oldCapacity >> 1)
)
RandomAccess:支持随机访问
关于arraylist的一些时间复杂度
增加元素至末尾(add(E e))时间复杂度为O(1)
增加元素至指定位置(add(int index, E element))时间复杂度为O(n)
查询指定元素(get(int index))时间复杂度为O(1)
删除指定元素(remove(int index)和remove(Object o))时间复杂度为O(n)
LinkedList
继承AbstractSequentialList实现List, Deque(双端队列)
底层结构:链表。线程不安全。
增加元素至末尾(add(E e))时间复杂度为O(1)
增加元素至指定位置(add(int index, E element))时间复杂度为O(n)
查询指定元素(get(int index))时间复杂度为O(n)
删除指定元素(remove(int index))时间复杂度为O(1)
Vector
继承AbstractList实现List, RandomAccess
RandomAccess:支持随机访问
底层结构:数组。线程安全。采用synchronized保证线程安全。
初始容量为10,扩容与ArrayList有差别。
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);
}
Set(HashSet和TreeSet)
不能存储相同的元素。两者差别可参考HashMap和TreeMap
HashSet
继承AbstractSet实现Set
底层结构:HashMap。通过hashMap的key来保证唯一性
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
TreeSet
继承AbstractSet实现NavigableSet
底层结构:TreeMap。通过TreeMap的key来保证唯一性
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
Queue(Deque)
Queue:队列,FIFO,先进先出。
Deque:双端队列。
常用方法:
add:插入元素,(由于队列大小限制)失败抛出异常
offer:插入元素,失败返回false
poll:删除并返回第1个元素,失败返回null
remove() :删除并返回第1个元素,失败抛出异常
peek:获取队列不一个元素(不删除),失败返回null
element:获取队列不一个元素(不删除),失败抛出异常
非阻塞队列
LinkedList:LinkedList是双相链表结构。
PriorityQueue:有序队列,存储到队列中的元素会按照自然顺序排列。可以指定一个实现了 java.util.Comparator 接口的排序类来指定元素排列的顺序。
ConcurrentLinkedQueue:基于链接节点的并且线程安全的队列(采用cas实现)。因为它在队列的尾部添加元素并从头部删除它们,添加、删除很方便,求size之类的操作需要进行遍历。
阻塞队列
队列空时取阻塞,队列满时存阻塞。
ArrayBlockingQueue:一个内部由数组支持的有界队列。初始化时必须指定队列的容量,还可以设置内部的ReentrantLock是否使用公平锁。但是公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队列,此队列按 FIFO(先进先出)原则对元素进行排序。BlockQueue
LinkedBlockingQueue:一个内部由链接节点支持的可选有界队列。初始化时不需要指定队列的容量,默认是Integer.MAX_VALUE,也可以看成容量无限大。此队列按 FIFO(先进先出)排序元素 。
PriorityBlockingQueue:一个内部由优先级堆支持的无界优先级队列。是对PriorityQueue的再次包装,队列中的元素按优先级顺序被移除。
DelayQueue :一个内部由优先级堆支持的、基于时间的调度队列。队列中存放Delayed元素,只有在延迟期满后才能从队列中提取元素。当一个元素的getDelay()方法返回值小于等于0时才能从队列中poll中元素,否则poll()方法会返回null。
SynchronousQueue:一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制。