容器
一.容器
二.Map
Map接口常见的实现类有HashMap、LinkedHashMap、TreeMap和ConcurrentHashMap
1.底层实现
HashMap | 数组+链表/红黑树 |
LinkedHashMap | 数组+链表+双向链表|
TreeMap | 红黑树 |
ConcurrentHashMap | 数组+链表/红黑树 |
2.HashMap
①数组的大小大于64且大于8就链表就转变为红黑树
②扩容为两倍(16)
③必须为2的幂,减少hash冲突
④加载因子是0.75
⑤1.7是头插法,1.8是尾插法
⑥有一个键可以为null
(1)大小是2次幂
HashMap的大小只能是2次幂的,假设你传一个10进去,实际上最终HashMap的大小是16,你传一个7进去,HashMap最终的大小是8,具体的实现在tableSizeFor
可以看到。我们把元素放进HashMap的时候,需要算出这个元素所在的位置(hash)。在HashMap里用的是位运算来代替取模,能够更加高效地算出该元素所在的位置。为什么HashMap的大小只能是2次幂,因为只有大小为2次幂时,才能合理用位运算替代取模。
(2)put
在put
的时候,首先对key做hash运算,计算出该key所在的index。如果没碰撞,直接放到数组中,如果碰撞了,需要判断目前数据结构是链表还是红黑树,根据不同的情况来进行插入。假设key是相同的,则替换到原来的值。最后判断哈希表是否满了(当前哈希表大小*
负载因子),如果满了,则扩容。
(3)get
在get
的时候,还是对key做hash运算,计算出该key所在的index,然后判断是否有hash冲突,假设没有直接返回,假设有则判断当前数据结构是链表还是红黑树,分别从不同的数据结构中取出.
①判断首节点是否为想要get的Node
②如果首节点不是则判断是不是红黑树,如果是则以红黑树的方式遍历查找
③如果首节点是链表类型,则以链表的方式遍历查找
(4)HashMap和HashTable
HashMap | HashTable |
线程不安全 | 线程安全 |
效率高 | 效率低 |
可以有一个key为null | 不允许存在null的key |
扩容为一倍 | 扩容为一倍+1 |
默认容量为16 | 默认为11 |
(5)HashTable和ConcurrentHashMap的区别
ConcurrentHashMap的put方法加锁优化了,锁的精度提高了,速度也就提高了。
https://www.php.cn/java/base/469764.html
3.LinkedHashMap
HashMap是无序的,当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了。
其实在日常开发中LinkedHashMap用得不多。我在实习的时候,就用到了一处,导出Excel表时Mybatis查询返回类型就是LinkedHashMap,因为它能让返回的数据严格有序。
4.TreeMap
红黑树
①首节点一点是黑色
②叶子节点也是黑色
③红色节点不可相连
④每条路径上的黑色节点数量一点要相等
5.ConcurrentHashMap
线程安全,跟HashMap差不多,就是在高并发的时候使用
三.List
ArrayList | LinkedList |
数组 | 链表 |
默认为0,add时才会初始化大小为10 | |
动态扩容,1.5倍 |
1.ArrayList
是由底层的数据结构来决定的,在日常开发中,遍历的需求比增删要多,即便是增删也是往往在List的尾部添加就OK了。像在尾部添加元素,ArrayList的时间复杂度也就O(1)。ArrayList的增删底层调用的
copyOf()
被优化过,现代CPU对内存可以块操作,ArrayList的增删一点儿也不会比LinkedList慢
2.LinkedList
队列是用双向链表实现的
Queue<> queue = new LinkedList<>();
既然说到队列就提一嘴栈,栈底层使用Vector实现的,这是历史遗留问题,一开始java写的Vector不太行。
因为Vector是当初JAVA曾经写得不太行的类,所以Stack也不太行。
Vector不行是因为效率不太行,很多方法都用了synchronized修饰,
虽然线程安全,但是像ArrayDeque,LinkedList这些线程不安全的,
在需要安全的时候也可以用Collections.synchronizedCollection()
转化成线程安全的,所以Vector就没什么用处了
四.队列
在实现普通队列时,如何选择用 LinkedList 还是 ArrayDeque 呢?
总结来说就是推荐使用 ArrayDeque,因为效率高,而 LinkedList 还会有其他的额外开销
什么情况下你要选择用 LinkedList 呢? 答:如果版本是Java 6 以前。因为 ArrayDeque 在 Java 6 之后才有的。。 为了版本兼容的问题,实际工作中我们不得不做一些妥协。。
ArrayList和LinkedList的区别
- ArrayDeque 是一个可扩容的数组,LinkedList 是链表结构;
- ArrayDeque 里不可以存 null 值,但是 LinkedList 可以;
- ArrayDeque 在操作头尾端的增删操作时更高效,但是 LinkedList 只有在当要移除中间某个元素且已经找到了这个元素后的移除才是 O(1) 的;
- ArrayDeque 在内存使用方面更高效。
所以,只要不是必须要存 null 值,就选择 ArrayDeque 吧!
四.Set
这个好像没什么好说的 0.0