Java集合类汇总详解
1、List(有序、可重复)
- ArrayList:object数据存储元素,有序,但线程不同步->插入删除麻烦,查询为O(1),支持随机访问,多于存储结尾预留空间,浪费空间
- LinkedList:实现了Queue接口,双向循环列表,有序,但线程不安全->插入删除简单,查询为O(n),不支持随机访问,多余存储索引浪费空间
- Vector:Object数组存储元素,方法线程同步,但粒度大效率低
- CopyOnWriteArrayList:是一个线程安全的List接口的实现,它使用了ReentrantLock锁来保证在并发情况下提供高性能的并发读取。
List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。
2、Set(无序、不能重复,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。)
- HashSet:仅存储对象,底层采用 HashMap 来保存元素,使用add方法,使用成员对象计算hashcode,对于两个对象来说hashcode可能相同,扩容时翻倍(扩容根据客座率:饱和程度,自己指定)
- LinkedHashSet:LinkedHashSet 继承与 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 Hashmap 实现一样,LinkedHashSet中的元素可以按照它们插入规则集的顺序提取。
- TreeSet:红黑树(自平衡的排序二叉树。),所以按照树的遍历则有序。
- AbstractSet:是一个实现Set接口的抽象类
3、Queue(数据结构中的队列)
- Queue:数据结构中的队列,本身并不是线程安全的,方法offer表示向队列添加一个元素,poll()与remove()方法都是移除队列头部的元素,两者的区别在于如果队列为空,那么poll()返回的是null,而remove()会抛出一个异常。方法element()与peek()主要是获取头部元素,不删除。
- BlockingQueue:可以提供阻塞功能的队列(头不出,出不去)
LinkedBlockingQueue的容量是没有上限的(说的不准确,在不指定时容量为Integer.MAX_VALUE,不要然的话在put时怎么会受阻呢),但是也可以选择指定其最大容量,它是基于链表的队列,此队列按 FIFO(先进先出)排序元素。ArrayBlockingQueue在构造时需要指定容量, 并可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来 达到这种公平性的:即等待时间最长的线程会先操作)。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队 列,此队列按 FIFO(先进先出)原则对元素进行排序。PriorityBlockingQueue是一个带优先级的 队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限(看了一下源码,PriorityBlockingQueue是对 PriorityQueue的再次包装,是基于堆数据结构的,而PriorityQueue是没有容量限制的,与ArrayList一样,所以在优先阻塞 队列上put时是不会受阻的。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError),但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元 素要具有比较能力。DelayQueue(基于PriorityQueue来实现的)是一个存放Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。
4、Map(键值对、键唯一、值不唯一)
Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。
- HashMap:存储键值对,使用put,get方法,数组加链表组成,数组是主体,链表是为了拉链法解决hash冲突,jdk1.8之后链表超过阈值(8)时使用红黑树实现(一种弱平衡树的数据结构,增加了查询效率),非线程安全(所以效率高),其中null可以作为主键,但只能出现一次。默认扩充时为原来的两倍
- LinkedHashMap:LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑(但本身条目是无序的,只保证了添加的顺序而已)。
- TreeMap:红黑树(自平衡的排序二叉树)
- ConcurrentHashMap:底层使用分段的数组+链表(红黑树)实现,线程安全,粒度小。
- Hashtable:线程安全(使用synchronized修饰),粒度大(使用的同一把锁,效率低),不能出现null值。默认扩充时为原来的2n+1倍,无红黑树链表机制。
|
|
是否有序 |
是否允许元素重复 |
Collection |
|
|
|
List |
是 |
是 |
|
Set |
AbstractSet |
否 |
否 |
|
HashSet |
||
|
TreeSet |
是(用二叉排序树) |
|
Map |
AbstractMap |
否 |
使用key-value来映射和存储数据,key必须唯一,value可以重复 |
|
HashMap |
||
|
TreeMap |
是(用二叉排序树) |
其中1.8之后的ConcurrentHashMap锁结构
注:带下划线的为线程安全的
原文总结至:
Java集合类:https://zhuanlan.zhihu.com/p/42806127,https://zhuanlan.zhihu.com/p/34554399,