栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java集合夺命十连问?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java集合夺命十连问?

Java集合夺命十连问?

文章目录

Java集合夺命十连问?

1、引出集合,常见的集合有哪些?2、线程安全的集合有哪些?3、ArrayList与linkedList异同点?5、ArrayList的扩容机制?6、HashMap的底层数据结构是什么?7、为了解决哈希冲突,不直接使用红黑树?而选择先用链表,再转红黑树?8、HashMap的put方法流程?9、HashMap的resize方法的执行过程?10、HashMap为什么线程不安全?

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

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

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

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

线程安全:

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

线程不安全的:

HashMapArrayListlinkedListHashSetTreeSetTreeMap 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方法流程?
    首先根据key值计算hash值,找到数组存储的下标如果数组是空的,调用resize进行初始化如果没有哈希冲突,直接放在对应的数组下标如果有冲突,且key已经存在,覆盖掉value;如果冲突后,发现该节点是红黑树,将节点挂在树上;如果冲突后是链表判断链表是否大于8,如果大于8且数组容量小于64,进行扩容,如果链表节点大于8且数组容量大于64,将这个结构转换成红黑树,否则链表插入键值对,若key存在,覆盖掉value.
9、HashMap的resize方法的执行过程?

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

    第一次调用HashMap的put方法时,会调用resize方法对table数组进行初始化,如果不传入指定值默认大小为16扩容会调用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,有可能导致这个问题。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/774428.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号