大厂java面试题——集合篇(1)

💴哈喽,大家好丫,你们的小郭子又来啦 ~

今天我们来聊一聊java面试中的【集合问题】

                                        

话不多说,直接上干货,嘻嘻嘻 ~

目录

💴哈喽,大家好丫,你们的小郭子又来啦 ~

1. ArrayList 和 LinkedList 的区别?

2. ArrayList 的扩容机制?

3. Array 和 ArrayList 有何区别?

4. 什么时候更适合用 Array?

5. HashMap 的实现原理/底层数据结构?JDK1.7 和 JDK1.8

6. HashMap 的 put 方法的执行过程?

7. HashMap 的 get 方法的执行过程?

8. JDK1.8之后,HashMap头插法改为尾插法?


1. ArrayList 和 LinkedList 的区别?

ArrayList:底层是基于数组实现的,查找快,增删较慢;

LinkedList:底层是基于链表实现的。确切的说是循环双向链表(JDK1.6 之前是双向循环链表、JDK1.7 之后取消了循环),查找慢、增删快。LinkedList 链表由一系列表项连接而成,一个表项包含 3 个部分:元素内容、前驱表和后驱表。链表内部有一个 header 表项,既是链表的开始也是链表的结尾。header 的后继表项是链表中的第一个元素,header 的前驱表项是链表中的最后一个元素。ArrayList 的增删未必就是比 LinkedList 要慢

2. ArrayList 的扩容机制?

当使用 add 方法的时候首先调用 ensureCapacityInternal 方法,传入 size+1 进去,检查是否需要扩充 elementData 数组的大小;

newCapacity = 扩充数组为原来的 1.5 倍(不能自定义),如果还不够,就使用它指定要扩充的大小 minCapacity ,然后判断 minCapacity 是否大于 MAX_ARRAY_SIZE(Integer.MAX_VALUE – 8) ,如果大于,就取 Integer.MAX_VALUE;

扩容的主要方法:grow;

ArrayList 中 copy 数组的核心就是 System.arraycopy 方法,将 original 数组的所有数据复制到 copy 数组中,这是一个本地方法。

3. Array 和 ArrayList 有何区别?

  1. Array 可以容纳基本类型和对象,而 ArrayList 只能容纳对象;
  2. Array 是指定大小的,而 ArrayList 大小是不固定的。

4. 什么时候更适合用 Array?

如果列表的大小已经指定,大部分情况下是存储和遍历它们;

对于遍历基本数据类型,尽管 Collections 使用自动装箱来减轻编码任务,在指定大小的基本类型的列表上工作也会变得很慢;

如果你要使用多维数组,使用 [ ] [ ] 比 List< < > > 更容易。

5. HashMap 的实现原理/底层数据结构?JDK1.7 和 JDK1.8

JDK1.7:Entry数组 + 链表

JDK1.8:Node 数组 + 链表/红黑树,当链表上的元素个数超过 8 个并且数组长度 >= 64 时自动转化成红黑树,节点变成树节点,以提高搜索效率和插入效率到 O(logN)。Entry 和 Node 都包含 key、value、hash、next 属性。

6. HashMap 的 put 方法的执行过程?

当我们想往一个 HashMap 中添加一对 key-value 时,系统首先会计算 key 的 hash 值,然后根据 hash 值确认在 table 中存储的位置。

若该位置没有元素,则直接插入。否则迭代该处元素链表并依次比较其 key 的 hash 值。如果两个 hash 值相等且 key 值相等(e.hash = = hash && ((k = e.key) = = key || key.equals(k))),则用新的 Entry 的 value 覆盖原来节点的 value。

如果两个 hash 值相等但 key 值不等 ,则进行插入操作。

不过呢,插入操作在 JDK1.7 和 JDK1.8 是有所不同的,JDK1.7 底层采用数组+链表,插入时采用头插法,JDK1.8,底层采用数组 + 链表 / 红黑树,并且把头插法改成了尾插法,主要是为了减少线程安全的问题

另外,当链表长度大于8,且数组长度大于64时,会把链表转化为红黑树处理,这个时候,就无关是头插还是尾插了,得按照红黑树的规则来插了。

7. HashMap 的 get 方法的执行过程?

通过 key 的 hash 值找到在 table 数组中的索引处的 Entry,然后返回该 key 对应的 value 即可。

在这里能够根据 key 快速的取到 value 除了和 HashMap 的数据结构密不可分外,还和 Entry 有莫大的关系。HashMap 在存储过程中并没有将 key,value 分开来存储,而是当做一个整体 key-value 来处理的,这个整体就是Entry 对象。同时 value 也只相当于 key 的附属而已。

存储的过程中,系统根据 key 的 HashCode 来决定 Entry 在 table 数组中的存储位置,在取的过程中同样根据 key 的 HashCode 取出相对应的 Entry 对象(value 就包含在里面)。

8. JDK1.8之后,HashMap头插法改为尾插法?

1.头插法在并发下有致命问题,就是可能形成数据环,get 数据时死循环,而在 1.8 之前因为处理 hash 冲突的方式是用链表存放数据,使用头插法可以提升一定效率。

但是在 1.8 之后这个效率提升就可有可无了,链表长度超过 7 就要考虑升级红黑树了,所以哪怕进行尾插遍历次数也会很有限,效率影响不大。

2.就是因为 1.8 之后数据结构的变动,当链表长度达到阈值,升级为红黑树后头插法就不适用了,因为构建红黑树需要进行比对更新序列,也就不能去说是头插法还是尾插了

💴好啦,今天的分享到这里就结束啦 ~

💴觉得我分享的文章不错的话,可以关注一下哦,嘻嘻嘻

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值