Java 框架集合

180 阅读3分钟

1. 集合概览

容器主要包含 Collection 和 Map 两种

image.png

框架底层数据结构

List

  • ArrayList : Object[] 数组
  • Vector : Object[] 数组,线程安全
  • LinkerList : 双向链表

Set

  • HashSet:基于 HashMap 的实现,底层采用 HashMap 来保存元素
  • LinkedHashSet : HashSet 的子类,内部是通过 LinkedHashMap 来实现的
  • TreeSet(有序): 红黑树

Map

  • HashMap : 由数组+链表组成的(JDK1.7),JDK1.8 增加红黑树,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。
  • LinkedHashMap : 继承自 HashMap,增加一条双向链表,使得上面的结构可以保持键值顺对的插入顺序,同时对链表进行相应的操作实现访问顺序。
  • Hashtable : 数组+链表组成
  • TreeMap : 红黑树

如何选用集合

  1. 需要根据 key 获取元素时选用 Map,一般使用 HashMap,需要排序使用 TreeMap,需要保持顺序使用感 LinkedHashMap,需要线程安全使用 ConcurrentHashMap
  2. 只需要存放元素是就使用 Collenction 接口的集合,一般使用实现 List 接口的比如 ArrayListLinkedList,需要保证元素唯一使用实现 Set 接口的集合,比如 HashSetTreeSet

2. ArrayList

ArrayList 实现了 List 接口,底层通过数组实现,有一个容量(capacity),代表底层数组的实际大小,默认值为 10。向容器添加元素时,若容量不足,则自动增加底层数组的大小,为原先的 1.5 倍。

ArrayList 与 LinkedList 区别?

  1. ArrayList 底层使用 Object 数组,LinkedList 底层使用双向链表
  2. ArrayList 可以快速随机访问
  3. 对于插入和删除操作,LinkedList 优于 ArrayList
  4. 内存空间占用:LinkedList 的每一个元素都要存储前驱和后继的引用,ArrayList 需要预留一定的容量空间

Fail-Fast 机制

Fail-Fast 是快速失败机制,通过记录 modCount 参数来实现,在面对并发修改,或者在遍历过程中修改容器元素,迭代器很快就会完全失败,抛出异常

3. HashMap 的底层实现

JDK1.8 之前 HashMap 底层是 数组加链表 的结合。HashMap 通过 key 的 hashCode() 经过扰动函数之后得到 hash 值,然后通过 (n-1) & hash 判断当前元素的存放位置,如果不存在直接存放,如果当前位置存在元素,判断该元素与存入的元素 hash 值和 key 是否相同,如果相同直接覆盖,不相同通过拉链法解决冲突。

JDK1.8 之后在解决哈希冲突发生了变化,当链表长度大于阈值(默认 8),将链表转换为红黑树。

HashMap 的数组长度为什么是 2 的幂次方

因为存放元素的位置是通过 (n - 1) & hash 计算的,n 是数组长度。对除数取余的操作,如果除数是 2 的幂次方等价于与其除数减一的与(&)操作,也就是 hash%length==hash&(length-1),而且 & 相对于 % 运算效率高。

ConcurrentHashMap

JDK1.7 使用分段锁实现,JDK1.8 使用数组+链表+红黑树数据结构和 CAS 原子操作实现 ConcurrentHashMap