Collection 和 Map 是集合框架的根接口
Collection 是单列集合,Map是双列集合
1. Collection集合
1.1 List集合
ArrayList、LinkedList、Vector
ArrayList | LinkedList | Vector | |
---|---|---|---|
底层实现 | 数组 | 双向链表 | 数组 |
同步性 | 不同步,线程不安全 | 不同步,线程不安全 | 线程安全 |
特点 | 高效,支持随机访问,查询快,增删慢 | 高效,增删快,查询慢 | 低效,查询快,增删慢 |
默认容量 | 10 | / | 10 |
扩容机制 | 1.5n | / | 2n |
- LinkedList,不会出现扩容问题,不用维护每个元素的index,比较适合随机位的增删,因为其链表结构,查询是要进行线性扫描,所以会比较慢
- ArrayList,根据index进行随机查找效率很高,在中间位置新增或删除元素的时候,还需要操作index,所以效率会比较低
1.2 Set集合
HashSet、TreeSet、LinkedHashSet
HashSet | TreeSet | LinkedHashSet | |
---|---|---|---|
底层实现 | HashMap-keySet | TreeMap的KeySet | LinkedHashMap |
特点 | 不重复,无序,线程不安全 | 不重复,有序(自然排序/自定义排序),线程不安全 | 不重复,有序(以元素的插入顺序维护链表),线程不安全 |
null值 | 允许,只能有一个null | 不允许,因为null无法比较 | 允许 |
时间复杂度 | add(),remove(),contains() = O(1) | add(),remove(),contains() = O(logn) |
Set集合是如何做到去重的?
向HashSet中添加元素的时候,
首先计算元素的 hashcode 值,然后通过扰动计算按位与的方式计算出这个元素的存储位置;
如果这个位置为空,就将元素添加进去;如果不为空,则用 equals 方法比较元素是否相等;
👉🏿 hashcode相等,equals不相等的元素,我们称发生了 哈希碰撞;
HashSet会将发生 哈希碰撞 的元素以 链表 的方式存储在同一个hash桶中;
2. Map集合
HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap、HashTable
- TreeMap:基于红黑树实现;
- HashMap:基于hash表实现;
- HashTable:与HashMap类似,但是线程安全。但是现在不建议使用;
- ConcurrentHashMap:实现线程安全,引入了分段锁,效率更高。
- LinkedHashMap:使用双向链表来维护元素的顺序,顺序是插入顺序或者最少使用顺序。
HashMap | HashTable | TreeMap | |
---|---|---|---|
底层实现 | 哈希表(数组+链表) | 哈希表(数组+链表) | 红黑树 |
安全性 | 线程不安全 | 线程安全 | 线程不安全 |
null值 | 允许Key和Value为null,但只能有一个Key为null,且存放在哈希表的0角标位置 | 不允许key,value = null | value允许为null,当未实现 Comparator 接口时,key 不可以为null当实现 Comparator 接口时,若未对 null 情况进行判断,则可能抛 NullPointerException 异常。如果针对null情况实现了,可以存入,但是却不能正常使用get()访问,只能通过遍历去访问 |
hash | 使用hash(Object key)扰动函数对 key 的 hashCode 进行扰动后作为 hash 值 | 直接使用 key 的 hashCode() 返回值作为 hash 值 | |
容量 | 默认是24,且一定是2n | 默认是11 | |
扩容 | 2n,且哈希桶的下标使用&运算代替了取模 | 2n+1,哈希桶下标是直接用取模运算 |
1.7 和 1.8 的 HashMap区别
1.7 | 1.8 | |
---|---|---|
存储结构 | 数组+链表 | 数组+链表+红黑树 |
初始化方法 | 单独函数:inflateTable() | 直接集成到扩容函数中:resize() |
hash值计算方式 | 扰动处理:9次扰动=4次位运算 + 5次异或运算 | 扰动处理:2次扰动=1次位运算+1次异或运算 |
存放数据的规则 | 无冲突时,存放数组;冲突时存放链表 | 无冲突时,存放数组;冲突&链表长度>8,树化并存放红黑树;冲突&链表长度<6,存放单链表; |
插入数据的方式 | 头插法(先将原位置的数据后移一位,再插入数据到该位置) | 尾插法(直接插入链表尾部/红黑树) |
扩容后存储位置的计算方式 | 全部按照原来方法进行计算(即hashCode ->> 扰动函数 ->> (h&length-1)) | 按照扩容后的规律计算(即扩容后的位置=原位置 or 原位置 + 旧容量) |
3. Base
👉🏿 Collections:
是个java.util下的类,是针对集合类的一个工具类,提供一系列静态方法,实现对集合的查找、排序、替换、线程安全化(将非同步的集合转换成同步的)等操作
Collection:
是个java.util下的接口,它是各种集合结构的父接口,继承于它的接口主要有Set和List,提供了关于集合的一些操作,如插入、删除、判断一个元素是否其成员、遍历等
集合的选择和使用:
主要根据集合的特点来选用,比如我们需要根据键值获取到元素值时就选用Map接口下的集合,需要排序时选择TreeMap,不需要排序时就选择HashMap,需要保证线程安全就选用ConcurrentHashMap;
当我们只需要存放元素值时,就选择实现Collection接口的集合,需要保证元素唯一时选择实现Set接口的集合比如TreeSet或HashSet,不需要就选择实现List接口的比如ArrayList或LinkedList,然后再根据实现这些接口的集合的特点来选用