ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java集合夺命十连问?

2022-03-19 20:04:30  阅读:134  来源: 互联网

标签:Java HashMap ArrayList 元素 链表 夺命 线程 数组 十连问


Java集合夺命十连问?

文章目录

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

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

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

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

线程安全:

  • Hashtable:比HashMap多了个线程安全。
  • concurrentHashMap:是一个高效、线程安全的集合。
  • Vector:比ArrayList多了个同步化机制。
  • Stack:栈,是线程安全的,继承于Vector。

线程不安全的:

  • HashMap
  • ArrayList
  • LinkedList
  • HashSet
  • TreeSet
  • TreeMap

3、ArrayList与LinkedList异同点?

  • **线程安全:**都是不同步的,不保证线程安全;
  • **底层数据结构:**Arraylist底层是Object数组,LinkedList底层是双向循环链表;
  • 插入和删除是否受元素影响: Arraylist采用数组存储,插入和删除元素的时间复杂度受元素位置影响,如:执行add(E e)方法,默认追加到此列表的末尾,O(1),在指定位置i插入和删除元素,O(n - i),i 以及第i个元素之后n-i个元素都要执行向后/向前移一位操作。LinkedList采用链表存储,插入、删除时间复杂度不受元素位置的影响,都是近似O(1)。
  • 快速随机访问: ArrayList实现了RandmpAccess接口,有随机访问,(get(int index)方法)
  • 内存空间占用: ArrayList空间浪费主要在list列表的结尾会预留一定的容量空间,LinkedList的空间花费体现在它每一个元素都要消耗比ArrayList更多的空间
  • (因为要存放直接后继和直接前驱以及数据)

4、ArrayList与Vector区别?

  • Vector是线程安全的,在关键的方法上都加了synchronized关键字,保证线程的安全性
  • ArrayList在底层数组不够用时在原来基础上扩展0.5倍,Vector扩展1倍,ArrayList有利于节约空间

5、ArrayList的扩容机制?

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

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

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

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

  • 链表长度超过8,数组长度大于64时,链表会转化为红黑树。
  • 当数组长度小于64时,会优先扩容数组,不会转换红黑树,减少搜索时间

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有