编程语言
首页 > 编程语言> > Java集合夺命十连问?

Java集合夺命十连问?

作者:互联网

Java集合夺命十连问?

文章目录

1、引出集合,常见的集合有哪些?

接口体系:List、Set、Queue、Map

类体系:ArrayList、LinkedList、Hashset、TreeSet、LinkedList、HashMap、TreeMap

2、线程安全的集合有哪些?

线程安全:

线程不安全的:

3、ArrayList与LinkedList异同点?

4、ArrayList与Vector区别?

5、ArrayList的扩容机制?

ArrayList扩容的本质是计算出新的扩容数组size后实例化,将原来的数组复制到新数组中去,默认情况下,新容量是原容量的1.5倍

6、HashMap的底层数据结构是什么?

JDK1.7的时候是数组加链表,数组是HashMap的主体,链表是为了解决哈希冲突存在的。

JDK1.8的时候是数组+链表+红黑树,链表过长会影响HashMap的性能,所以达到一定条件会进行转换:

7、为了解决哈希冲突,不直接使用红黑树?而选择先用链表,再转红黑树?

因为红黑树,需要左旋、右旋、变色来保持平衡,而单链表不需要,此时单链表能够保证查询性能,当元素大于8个的时候,链表为O(n),红黑树为O(logn),这时需要红黑树加快查询效率,但是新增节点的效率降低了。

开始的时候用红黑树的结构,元素太少,新增效率又比较慢,无疑是浪费性能

8、HashMap的put方法流程?

  1. 首先根据key值计算hash值,找到数组存储的下标
  2. 如果数组是空的,调用resize进行初始化
  3. 如果没有哈希冲突,直接放在对应的数组下标
  4. 如果有冲突,且key已经存在,覆盖掉value;
  5. 如果冲突后,发现该节点是红黑树,将节点挂在树上;
  6. 如果冲突后是链表判断链表是否大于8,如果大于8且数组容量小于64,进行扩容,如果链表节点大于8且数组容量大于64,将这个结构转换成红黑树,否则链表插入键值对,若key存在,覆盖掉value.

9、HashMap的resize方法的执行过程?

两种情况会调用resize()方法:

  1. 第一次调用HashMap的put方法时,会调用resize方法对table数组进行初始化,如果不传入指定值默认大小为16
  2. 扩容会调用resize,size > threshold时,table数组大小翻倍。

每次扩容之后容量都是翻倍的,扩容后将原数组中所有元素找到新数组中合适的位置。

当我们把table[i]位置的所有Node迁移到newtab中去的时候:这里面的node要么在newtab的i位置(不变),要么在newtab的i + n位置。我们可以:把table[i]这个桶中的node拆分成两个链表l1和l2:如果hash & n = 0,那么当前这个node被连接到l1链表上;否则连接到l2链表上,这样,遍历完table[i]处的所有node的时候,我们就得到了两个链表l1 和 l2,这时newtab[i] = l1 ,newtab[i + n] = l2,这就完成了table[ i ]位置所有node的迁移,这也是HashMap容量一定是2的整数次幂带来的方便之处。

10、HashMap为什么线程不安全?

多线程下扩容死循环。JDK1.7中的HashMap使用头插法插入元素,多线程的环境下,扩容的时候有可能出现环形链表,JDK1.8使用尾插法,不会出现环形链表的问题。

多线程的put可能导致元素丢失。多线程同时执行put操作,如果计算出来的索引位置是相同的,会造成前一个key被后一个key覆盖,导致元素的丢失。
put和get并发时,可能导致get为null.线程1执行put时,因为元素个数超过threshold而导致rehash,线程2此时执行get,有可能导致这个问题。

标签:Java,HashMap,ArrayList,元素,链表,夺命,线程,数组,十连问
来源: https://blog.csdn.net/qq_50754735/article/details/123601192