研究生 java_Java面试-集合

目录

Collection

List

ArrayList

Vector

LinkedList

Set

HshSet

TreeSet

LinkedHashSet

Queue

Map

HashMap

ConcurrentHashMap

HashTable

TreeMap

LinkedHashMap

1. Colection

1.1 List

1.1.1 ArrayList

底层由数组实现;

插入代价大:O(n);

适合进行查询操作:O(1);

线程不安全;

实例化ArrayLisr时不初始化容量,第一次调用add()方法时进行长度初始化,初始长度:10;

扩容:容量不足时扩容,使用向右移位,则为当前容量的1.5倍;

int newCapacity = oldCapacity + (oldCapacity >> 1);

1.1.2 Vector

底层由数组实现;

支持线程同步(synchronized);

效率低于ArrayList(由于支持线程同步)

初始化时则初始化容量:10;

扩容:每次扩容为原来两倍;

int newCapacity = oldCapacity * 2;

1.1.2 LinkedList

链表结构

插入、删除操作速度快O(n);

1.2 Set

1.2.1 HashSet

不按照存入顺序存储

当 hashcode相等 && equals返回true 时使用链表向下顺延;

1.2.2 TreeSet

1.2.3 LinkedHshSet

2 Map

2.1 HashMap

2.1.1 java 7

非线程安全

底层实现:数组+链表

重要参数:

Capacity:数组容量,保持2n,初始值为16,扩容后为当前容量2倍;(为什么为2n:为了使散列更均匀,极端情况下查询效率将由O(1)下降为O(n))

LoadFactor:负载因子,默认为0.75;

Threadhold:扩容阈值,Threadhold = Capacity * LoadFactor,当存储量超过扩容阈值时,Hashmap将进行扩容。

2.1.2 java 8

非线程安全

底层实现:数组+链表+红黑树

引入红黑树,查询效率由O(n)下降为O(logn)

1、put(key, value)中直接调用了内部的putVal方法,并且先对key进行了hash操作;

2、putVal方法中,先检查HashMap数据结构中的索引数组表是否位空,如果是的话则进行一次resize操作;

3、以HashMap索引数组表的长度减一与key的hash值进行与运算,得出在数组中的索引,如果索引指定的位置值为空,则新建一个k-v的新节点;

4、如果不满足的3的条件,则说明索引指定的数组位置的已经存在内容,这个时候称之碰撞出现;

5、在上面判断流程走完之后,计算HashMap全局的modCount值,以便对外部并发的迭代操作提供修改的Fail-fast判断提供依据,于此同时增加map中的记录数,并判断记录数是否触及容量扩充的阈值,触及则进行一轮resize操作;

6、在步骤4中出现碰撞情况时,从步骤7开始展开新一轮逻辑判断和处理;

7、判断key索引到的节点(暂且称作被碰撞节点)的hash、key是否和当前待插入节点(新节点)的一致,如果是一致的话,则先保存记录下该节点;如果新旧节点的内容不一致时,则再看被碰撞节点是否是树(TreeNode)类型,如果是树类型的话,则按照树的操作去追加新节点内容;如果被碰撞节点不是树类型,则说明当前发生的碰撞在链表中(此时链表尚未转为红黑树),此时进入一轮循环处理逻辑中;

8、循环中,先判断被碰撞节点的后继节点是否为空,为空则将新节点作为后继节点,作为后继节点之后并判断当前链表长度是否超过最大允许链表长度8,如果大于的话,需要进行一轮是否转树的操作;如果在一开始后继节点不为空,则先判断后继节点是否与新节点相同,相同的话就记录并跳出循环;如果两个条件判断都满足则继续循环,直至进入某一个条件判断然后跳出循环;

9、步骤8中转树的操作treeifyBin,如果map的索引表为空或者当前索引表长度还小于64(最大转红黑树的索引数组表长度),那么进行resize操作就行了;否则,如果被碰撞节点不为空,那么就顺着被碰撞节点这条树往后新增该新节点;

10、最后,回到那个被记住的被碰撞节点,如果它不为空,默认情况下,新节点的值将会替换被碰撞节点的值,同时返回被碰撞节点的值(V)。

1、在jdk1.7中,在多线程环境下,扩容时会造成环形链或数据丢失;

2、在jdk1.8中,在多线程环境下,会发生数据覆盖的情况。

树化与链化

链表内元素 ≥ 8

数组长度<64:扩容数组;

数组长度 ≥ 64:链表树化;

链表内元素<6

红黑树链化;

2.2 ConcurrentHashMap

2.2.1 java 7

底层实现:Segment + ReentrantLock + 分段锁

并行度:16,最多支持16个线程并发写(并行数由Segment数量决定)

2.2.2 java 8

底层实现: 数组 + CAS + Synchronized

ConcurrentHashMap之put方法

1、计算hashcode;

2、table为空,则执行初始化,默认长度16;(基于CAS)

3、否则,计算hashcode在数组中对应的下标,并获取下标对应的头结点;

4、头结点为空,添加头结点;(基于CAS)

5、头结点不为空,但头结点值为 MOVED  ,表示正在扩容,帮助其扩容线程扩容(基于CAS)

6、否则,头结点不为空,且未处于扩容状态,尝试添加新结点(基于Synchronized)

7、判断当前桶内节点数量是否大于阈值,大于则扩容 (基于CAS)

链表内元素 ≥ 8

数组长度<64:扩容数组;

数组长度 ≥ 64:链表树化;

链表内元素<6

红黑树链化;

参考:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值