Java中各种集合的异同与使用


Collection< E >是所有集合类的祖先 我们从这个类往下延伸

1.List


不同点:

名称 数据结构 安全性 插入和删除(时间复杂度) getIndex 内存空间占用
ArrayList 数组 非同步,不安全 首尾O(1),index O(n-i)) 高效 结尾会预留一定的空间
LinkedList 双向链表 非同步,不安全 O(n) 较慢 每一个元素都耗时
Vector(淘汰) 数 组 线程安全(synchronized) ----- ----- -----
  • ArrayList增删没有想象中慢,ArrayList的增删底层调用的copyOf()被优化过,加上现代CPU对内存可以块操作,普通大小的ArrayList增删比LinkedList更快。

2.Set

  • HashSet
  • LinkedHashSet
  • TreeSet

不同点:

名称 顺序 基础
HashSet 无序 基于HashMap
LinkedHashSet 自动排序 基于TreeMap
TreeSet 维护“插入顺序” 基于HashSet,是HashSet的扩展
  • Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false

3.Map

不同点:

名称 实现 继承 是否允许null值 扩容方式 存储方式
HashMap 实现Map接口 继承 AbstractMap 类 允许key和value为null值 size*2,且size必定为2^n 1.如果冲突数量于8,则是以链表方式解决冲突。2.如果当冲突大于等于8时,就会将冲突的Entry转换为红黑树进行存储。3如果当数量小于6时,则又转化为链表存储。
HashTable 实现Map接口 继承 Dictionary类 键值对都不能为空 size*2+1 链表方式存储
LinkedHashMap 实现Map接口 继承 HashMap类 允许key和value为null值 基于拉链式散列结构即由数组和链表或红黑树组成
TreeMap 实现NavigableMap接口 继承 AbstractMap类 不允许Key为null 红黑树(自平衡的排序二叉树)

已上是常见集合的梳理,但是在多线程环境下 , Vector被淘汰 , 使用synchronizedList又过于笨重

4. JUC下常用的几个线程安全容器

安全容器详解入口

1. CopyOnWriteArrayList

CopyOnWriteArrayList博客入口

2. CopyOnWriteArraySet

同CopyOnWriteArrayList

3. ConcurrentLinkedQueue

ConcurrentLinkedQueue

4. ConcurrentSkipListMap

ConcurrentSkipListMap

5. ConcurrentHashMap

ConcurrentHashMap博客入口

因为HashTable也是线程安全的,总结一下不同点:

  • 底层数据结构:
    • JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。
    • Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用 数组+链表 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的;
  • 实现线程安全的方式(重要):
    • ① 在JDK1.7的时候,ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。 到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化) 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本;
    • ② Hashtable(同一把锁) :使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方 法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用 put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。

如何选用集合?

主要根据集合的特点来选用,比如我们需要根据键值获取到元素值时就选用Map接口下的集合,
需要排序时选择TreeMap,不需要排序时就选择HashMap,需要保证线程安全就选用ConcurrentHashMap.
当我们只需要存放元素值时,就选择实现Collection接口的集合,
需要保证元素唯一时选择实现Set接口的集合比如TreeSet或HashSet,
不需要就选择实现List接口的比如ArrayList或LinkedList,
然后再根据实现这些接口的集合的特点来选用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章