单线程类集合
List
继承自Conllection
元素以线性方式存储,集合中可以存放重复对象。
- ArrayList:底层基于动态数组,多用于随机访问。
- LinkedList:底层基于链表,多适用于插入删除操作。
Map
元素以键值对的形式存储
基本同样接口Map,但是行为、效率、排序策略、保存对象的生命周期和判定“键”等价的策略等各不相同。标准Java类库定义了HashMap, TreeMap, LinkedHashMap, WeakHashMap, IdentityHashMap。
- HashMap:底层基于散列表实现
- LinkedHashMap:类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点。而在迭代访问时发而更快,因为它使用链表维护内部次序。
- TreeMap:基于红黑树数据结构(二叉查找树)的实现。查看“键”或“键值对”时,它们会被排序(次序由Comparabel或Comparator决定)。主要特点在于,得到的结果是经过排序的。TreeMap是唯一的带有subMap()方法的Map,它可以返回一个子树。
- WeakHashMap:弱键(weak key)Map,Map中使用的对象也被允许释放: 这是为解决特殊问题设计的。如果没有map之外的引用指向某个“键”,则此“键”可以被垃圾收集器回收。适用于构建缓存场景。
- IdentityHashMap:使用==代替equals()对“键”作比较的hash map
Set
继承自Conllection
真正数学意义上的集合抽象,不包含重复元素,更准确的说是不满足e1.equals(e2)的元素。
从实现方式上来看,Set很像Map的马甲。
- HashSet:基于HashMap的Set实现。底层基于散列表,为实现快速查找
- LinkedHashSet:基于LinkHashMap实现,具有与HashSet同样的查询速度,内部使用链表维护元素的插入的次序。
- TreeSet:类似于TreeMap,底层基于树型结构,保存次序的Set
- EnumSet:值为枚举类型的Set。
- BitSet:值为比特类型的Set。
Queue/Deques
- ArrayDeque:Deque是基于有首尾指针的数组(环形缓冲区)实现的。和LinkedList
不同,这个类没有实现List接口。因此,如果没有首尾元素的话就不能取出任何元素。这个类比LinkedList要好一些,因为它产生的垃圾数量较少(在扩展的时候旧的数组会被丢弃)。 - Stack:一种后进先出的队列。不要在生产代码中使用,使用别的Deque来代替(ArrayDeque比较好)。
- PriorityQueue:一个基于优先级的队列。使用自然顺序或者制定的比较器来排序。他的主要属性——poll/peek/remove/element会返回一个队列的最小值。同样PriorityQueue还实现了Iterable接口,队列迭代时不进行排序(或者其他顺序)。在需要排序的集合中,使用这个队列会比TreeSet等其他队列要方便。
并发类线程类集合
List
- CopyOnWriteArrayList:list的实现每一次更新都会产生一个新的隐含数组副本,所以这个操作成本很高。通常用在遍历操作比更新操作多的集合,比如listeners/observers
集合。
Queues/deques
- ArrayBlockingQueue:基于数组实现的一个有界阻塞队,大小不能重新定义。所以当你试图向一个满的队列添加元素的时候,就会受到阻塞,直到另一个方法从队列中取出元素。
- ConcurrentLinkedDeque / ConcurrentLinkedQueue:基于链表实现的无界队列,添加元素不会堵塞。但是这就要求这个集合的消费者工作速度至少要和生产这一样快,不然内存就会耗尽。严重依赖于CAS(compare-and-set)操作。
- DelayQueue:无界的保存Delayed
元素的集合。元素只有在延时已经过期的时候才能被取出。队列的第一个元素延期最小(包含负值——延时已经过期)。当你要实现一个延期任务的队列的时候使用(不要自己手动实现——使用ScheduledThreadPoolExecutor) - LinkedBlockingDeque / LinkedBlockingQueue:可选择有界或者无界基于链表的实现。在队列为空或者满的情况下使用ReentrantLock-s
。 - LinkedTransferQueue:基于链表的无界队列。除了通常的队列操作,它还有一系列的transfer
方法,可以让生产者直接给等待的消费者传递信息,这样就不用将元素存储到队列中了。这是一个基于CAS操作的无锁集合。 - PriorityBlockingQueue:PriorityQueue的无界的版本。
- SynchronousQueue:一个有界队列,其中没有任何内存容量。这就意味着任何插入操作必须等到响应的取出操作才能执行,反之亦反。如果不需要Queue接口的话,通过Exchanger类也能完成响应的功能。
Maps
- ConcurrentHashMap:get操作全并发访问,put操作可配置并发操作的哈希表。并发的级别可以通过构造函数中concurrencyLevel参数设置(默认级别16)。该参数会在Map内部划分一些分区。在put操作的时候只有更新的分区是锁住的。这种Map不是代替HashMap的线程安全版本——任何 get-then-put的操作都需要在外部进行同步。
- ConcurrentSkipListMap:基于跳跃列表(Skip List)的ConcurrentNavigableMap实现。本质上这种集合可以当做一种TreeMap的线程安全版本来使用。
Sets
- ConcurrentSkipListSet:存储线程安全的Set。
- CopyOnWriteArraySet:存储线程安全的Set。
集合工具
Arrays:Java中专门用来处理数组的工具
- Arrays.asList:可以从 Array 转换成 List。可以作为其他集合类型构造器的参数。
- Arrays.sort:对整个数组或者数组的一部分进行排序。也可以使用此方法用给定的比较器对对象数组进行排序。
- Arrays.toString:打印数组的内容。
Collections:Java中专门用来处理集合的工具
- Collections.addAll:添加一些元素或者一个数组的内容到集合中。
- Collections.disjoint:检查两个集合是不是没有相同的元素。
- Collections.fill:用一个指定的值代替集合中的所有元素。
- Collections.frequency:集合中有多少元素是和给定元素相同的。
- Collections.replaceAll:将集合中的某一元素替换成另一个元素。
- Collections.reverse:颠倒排列元素在集合中的顺序。如果你要在排序之后使用这个方法的话,在列表排序时,最好使用Collections.reverseOrder
比较器。 - Collections.rotate:根据给定的距离旋转元素。
- Collections.sort:将集合按照自然顺序或者给定的顺序排序。
- Collections.swap:交换集合中两个元素的位置(多数开发者都是自己实现这个操作的)。
集合相关的面试题
请简单介绍些Java 集合
List、Set、Map是这个集合体系中最主要的三个接口。其中List和Set继承自Collection接口。Set不允许元素重复。HashSet和TreeSet是两个主要的实现类。List有序且允许元素重复。ArrayList、LinkedList和Vector是三个主要的实现类。Map和Collection接口不同。Map是key对value的映射集合,其中key列就是一个集合。key不能重复,但是value可以重复。HashMap、TreeMap和Hashtable是三个主要的实现类。
Comparable和Comparator区别
- Comparable:可以认为内部比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较的,至于具体和另一个实现了Comparable接口的类如何比较,则依赖compareTo方法的实现,compareTo方法也被称为自然比较方法。如果开发者add进入一个Collection的对象想要Collections的sort方法帮你自动进行排序的话,那么这个对象必须实现Comparable接口。compareTo方法的返回值是int,
- Comparator:可以认为外比较器,在这两种情况下:
- 一个对象不支持自己和自己比较(没有实现Comparable接口),但是又想对两个对象进行比较
- 一个对象实现了Comparable接口,但是开发者认为compareTo方法中的比较方式并不是自己想要的那种比较方式
网友评论