概述
- 主要梳理HashMap的知识,其他常用的集合简单的说一下特点
ArrayList
- 非线程安全,有序
- 初始容量10,加载因子1,扩容1.5倍
linkedList
- 本质是双向链表
- 非线程安全,有序
- 初始容量10,加载因子0.75,扩容1.5倍
- 相对于ArrayList,LinkedList适合增删操作频繁的场景
Vector
- 线程安全
- 初始容量10,加载因子1,扩容2倍
ArrayList与Vector的区别:
Vector中绝大部分方法都使用了同步关键字(synchronized)
HashSet
- 非线程安全,无序并且不允许重复元素
- 初始容量16,加载因子0.75,扩容2倍
Map
HashMap
特点
- 非线程安全,遍历时顺序是不确定的
- 默认长度16,加载因子0.75,扩容2倍
put方法:
- 执行步骤:
先通过key计算hash值得到插入的索引位置(若key为null,则索引值为0),若该位置已存储数据,那么判断key是否相同,相同即覆盖,不同则如果首结点是红黑树,按照红黑树方法插入元素,如果是首结点是链表,则链表方法插入,插入时判断是否超过容量8,是则红黑树插入 - put过程中可能执行的扩容方法(resize):
hashMap有初始容量(默认16)和加载因子(默认0.75);那么存储容量超过 12= 16* 0.75时就触发扩容方法;而执行扩容是新建一个原来容量2倍的HashMap,并把原来的就map里面的值复制到新的map中,这时是重新计算hash值来存储数据,所以说resize方法是很消耗性能的;因此在已知map存储y元素个数的情况下,尽量手动指定初始容量
这时有些人会问为什么不把加载因子(loadFactor)设置大一些(比如1),这样就能存更多数据,减少resize的可能?
因为这样会增加产生hash冲突的可能性,从而查询数据时间增加;而如果加载因子太小,则又会浪费空间,hash表中存储的数据比较稀疏
map.get(key)
- 先计算key的hash值确定位置,获取位置的第一结点,如果是就返回,不是就next,拿第二个,判断是否是红黑树结点,是就查询红黑树,不是则查链表
ConcurrentHashMap
- 线程安全
- 使用了cas + synchronized (cas乐观锁,比较并替换)
是否是第一个object,是则cas直接插入,不是则直接给链表的第一个object加上synchronized锁,这里会一直给第一个object加锁直到操作了第一个object,或者改变了map的大小
LinkedHashMap
- 是HashMap的子类,保存了插入的顺序,遍历时按照插入顺序(默认)或者访问次序排序
HashTable
- 线程安全
- 初始容量11,加载因子0.75,扩容2倍