Collection和Map篇
1、数组和集合的区别
数组 | 集合 | |
---|---|---|
长度的区别 | 长度固定 | 长度可变 |
内容不变 | 数组存储的同一种类型的元素 | 可以存储不同类型的元素 |
数据类型 | 基础数据和引用数据类型 | 引用数据类型 |
特点 | 有序,可重复 | 有序,可重复 |
2、集合和迭代器
迭代器是便利集合的一种方式,依赖于集合而存在的
结论: 遍历集合(Collection)的元素都可以使用iterator
,iterator
实际上就是在遍历集合
3、常用List集合
ArrayList
-
底层数据结构是数组,线程不安全
-
允许元素重复和为null
-
0.5倍扩容
-
访问速度快
-
如果所有操作都针对末尾,增删速度比LinkList要快
LinkedList
- 底层数据结构是链表,线程不安全
- 操作位置位于中间,增删速度比ArrayList要快
Vector
- 底层数据结构是数组,线程安全
- 允许元素重复和为null
- 每个方法处都声明了
synchronized
关键字 getLast()
和deleteLast()
这两个方法并不是原子性的 多线程执行会报错
CopyOnWriteList
-
底层线程安全,可以用于高并发读写
-
在执行
add()
操作时并不是对原本数组进行追加修改,而是将List复制并交予另外的集合操作,将操作好的集合赋值给新的集合public boolean add(E e) { // 加锁 final ReentrantLock lock = this.lock; lock.lock(); try { // 得到原数组的长度和元素 Object[] elements = getArray(); int len = elements.length; // 复制出一个新数组 Object[] newElements = Arrays.copyOf(elements, len + 1); // 添加时,将新元素添加到新数组中 newElements[len] = e; // 将volatile Object[] array 的指向替换成新数组 setArray(newElements); return true; } finally { lock.unlock(); } }
,之后将处理好的新集合进行返回
-
缺点
- 数据一致性,CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性
- 内存占用高
4、常用Set集合
HashSet
-
底层数据结构是哈希表(哈希表: 每个元素为链表的数组,也可以叫HashMap)+红黑树
-
非线程同步
TreeSet
-
有序,不允许为null,内部有comparaTo执行
-
底层数据结构是红黑树(自平衡的红黑树)
-
保证元素的排序方式
-
非线程同步
LinkedHashSet
- 底层数据结构由HashMap和双向链表组成
- 非线程同步
5、常用Map集合
HashMap
-
允许为null
-
在jdk8中HashMap的底层是:数组+链表(散列表)+红黑树
-
默认装载因子默认是0.75(数组),无论是初始化打了还是初始化小了对我们HashMap的性能都不好
- 装载因子初始值打了,可以减少散列表再散列(扩容的次数),但同时会导致散列冲突的可能性变大,避免散列冲突,散列冲突(hash冲突)也是耗性能的一个操作,红黑树会自动触发平衡
- 装载因子初始值小了,可以减少散列冲突的可能性,但同时扩容的次数可以能就会变频繁,影响性能
-
初始容量的默认值是16(数组),它也一样,无论初始化大了还是小了,对我们的HashMap都会有影响的
-
容量过大,那么遍历时我们的速度就会影响
-
初始容量国小,散列表再扩散(扩容的次数)可能就变得多,扩容耗费性能
-
LinkedHashMap
-
LinkedHashMap并没有重写HashMap的put方法,而是吧put方法内部的newNode()方法重写了,LinkedHashMap调用父类的put方法,里面回调的是重写后的newNode()
-
LinkedHashMap可以设置两种遍历顺序
- 访问顺序
- 插入顺序(默认)
-
LinkHashMap遍历的是内部维护的双向链表,所以说初始容量对LinkedHashMap遍历是不受影响的
-
允许为null
TreeMap
- 由于底层是红黑树,那么时间复杂度可以保证为log(n)
- key不能为null,因为每个key插入时都需要执行comparaTo 方法,对比一方不能为null
- HashMap中判断key的存储位置,采用的是计算hash值,将数据放入红黑树中,但是在TreeMap中,传入的key会执行comparaTo方法,得出结果1,0,-1, 从而判断该新的数据节点位置,之后采用中序遍历所有数据
HaskTable
- 同步安全的,锁全部,内部所有方法都加了
synchronized
关键字 - hashtable有contains方法,Hashmap改成了
containsKey
和containValue
ConcurrentHashMap
- 底层结构是散列表(数组 + 链表) + 红黑树,和hashMap一样
- HashTable是将所有的方法进行同步,效率低下,而ConcurrentHashMap作为一个高并发容器,他是通过部分锁定+CAS算法来进行实现线程安全的,CAS算法也可以认为是乐观锁的一种
- get方法是非阻塞的,无锁的,重写了其中的node类,通过valatile修饰next来实现每次获取最新设置的值
- ConcurrentHashMap的key和value都不能为null
- 注解:例如上图 16个数组表示有16个线程组,map初始化内部只会让一个线程进行初始化操作
Hash碰撞
hash碰撞指多个key值计算至同一个bucket桶上了,导致该桶下的链表长度过长,查找时间从O(1)到O(n)
插入put过程
首先,初始化 HashMap(懒加载模式,只有put的时候才会初始化HashMap),提供了有参构造和无参构造。
容器默认的数组大小 initialCapacity 为 16,也可自己设置,HashMap 会根据我们传入的容量计算一个大于等于该容量的最小的2的N次方,例如传 9,容量为16。
1、通过HashMap自己提供的Hash算法算出当前key的hash值
2、通过计算出hash值去调用indexFor方法计算当前对象应该存储在数组的几号位置
3、判断size是否已经达到了当前阈值(当前数组大小 x 负载因子,以初始16为例,则阈值为16 x 0.75),如果没有,继续插入操作;如果已经达到阈值,则先进行数组扩容,将数组长度扩容为原来的2倍
4、将当前对应的Hash,key,value封装成一个Entry,去数组中查找当前位置有没有元素,如果没有,放在这个位置上,如果此位置已经存在链表,那么遍历链表,如果链表上某个节点的key与当前key进行equals比较后结果为true,则把原来节点上的value返回,将当前新的value替换原来的value,如果遍历完链表,没有找到key与当前key与当前key equeals为true的,就把刚才封装的新的Entry中next指向当前链表的始节点,例如图中数组[3]下的[002]位置,002就是计算的hash值
5、默认情况下使用链表节点,当同一个索引位置的节点在新增后达到9个(阈值8),如果此时长度大于64,则会出发链表节点转红黑树节点;如果数组长度小于64,则不会出发链表转红黑树,而是会进行扩容,因为此时数据量还比较小
面试题提升
ArrayList集合加入1万条数据,应该怎么提高效率
ArrayList的默认初始容量为10,要插入大量数据的时候需要不断扩容,而扩容是非常影响性能的。因此,现在明确了10万条数据了,我们可以直接在初始化的时候就设置ArrayList的容量!
为什么HashMap中String、Integer这样的包装类适合作为Key
1、String和Integer等这些类都被final修饰,具有不变性;也保证了key的不变性,并且内部重写了equals和hashCode方法,不容易出现hash计算错误
2、String和Integer保证了hash值得不可变性和准确性,有效减少了hash碰撞
3、String和Integer一定重写了equals和hashCode方法
ConcurrentHashMap和Hashtable的区别
HashTable
是阻塞模式的,总是能获取最新的更新,好处是当线程A大量更新数据,期间线程B调用get,线程B就会被阻塞,直到线程A更新完毕,坏处是所有调用都要排除,效率比较低
ConcurrentHashMap
是非阻塞模式,在更新时会局部锁住某部分数据,但不会把整个表都锁住,同步读取操作则是完全非阻塞的,好处是在保证合理的同步前提下,效率高,坏处就是读取时不能保证反映最近的更新,线程A更新了Map中的数据,期间线程B只能读取到线程A已经更新完成的数据
Array 和 ArrayList 有什么区别?什么时候该用 Array 而不是 ArrayList 呢?
Array可以容纳基本类型和对象,而ArrayList只能容纳对象
Array指定大小后不可变,而ArrayList大小是可变的
Array没有提供ArrayList那么多功能,比如addAll,removeAll和iterator等
参考文档
https://blog.csdn.net/qq_38534524/article/details/123340822
https://reurl.cc/eX954W