一、ArrayList VS. LinkedList
1.1 底层数据结构
ArrayList: 数组(初始容量为10,扩容为 max{1.5倍,需要的容量}) LinkedList: 双向链表(不需要扩容)
1.2 查改效率
ArrayList: O(1) 随机访问
(Collection中的binarySearch对实现了RandomAccess的对象使用index-for循环get遍历比Iterator快,详细:blog.csdn.net/qq_42595077…
LinkedList:O(n) 可选择从前或从后查询 (LinkedList使用Iterator比For循环get遍历快)
1.3 增删效率
如果增删在尾部,ArrayList、LinkedList是O(1) (ArrayList更快)
如果增删在头部,LinkedList更快
如果增删在中间,ArrayList O(n)需要移动后面的所有元素,而LinkedList找到索引位置后改变节点指向
但是还需要注意ArrayList可能会涉及到扩容
1.4 空间占用
LinkedList 每个Node需要保存prev和next
二、HashSet
2.1 底层
HashMap :数组+链表+红黑树 存储键值对
HashSet: HashMap (Key为集合元素,value全都是一个object PRESENT)
2.2 查询(注意没有get方法)
contains(Object o)调用map的containsKey(o);
2.3 增删
add方法调用map的put方法
remove方法调用map的remove方法 返回true / false;
2.4 遍历
直接调用map的keySet的迭代器
和HashMap的比较
HashSet实现Set接口,存储对象,删除返回true / false
HashMap实现Map接口,存储键值对, 删除返回value
三、HashMap
3.1 底层:
数组+链表+红黑树
3.2 put流程
3.3 HashMap为什么线程不安全
JDK1.7是因为链表头插造成在多线程扩容时顺序翻转产生死循环链表 JDK1.8后采用尾插不会造成死循环,但会造成数据丢失问题:当table[i] == null时,正好有多线程插入,线程1和2都判断了可以直接插入,而这时2被挂起,1插入之后,2又直接覆盖掉1的数据。
3.4 ConcurrentHashMap vs. HashMap vs. Hashtable
| 区别 | ConcurrentHashMap | HashMap | Hashtable |
|---|---|---|---|
| 线程安全性 | 线程安全 | 线程不安全 | 线程安全 |
| 键值可否为NULL | 不能 | 能 | 不能 |
| 求下标方法 | hash&(len-1) | hash&(n-1) | hashCode%len |
| 扩容 | 先检查、*2 | 插入后检查、*2 | 先检查、 *2+1 |
| 初始容量 | 16 | 16 | 11 |
四、TreeMap
- 底层:红黑树
- 使用场景:需要key排序或者构造比较器自定义排序,可以保证遍历顺序和插入顺序一致
- 缺点:TreeMap 遍历 O(logn)