List、Set、Map 高频面试题及详细答案(实战版)_第1页
List、Set、Map 高频面试题及详细答案(实战版)_第2页
List、Set、Map 高频面试题及详细答案(实战版)_第3页
List、Set、Map 高频面试题及详细答案(实战版)_第4页
List、Set、Map 高频面试题及详细答案(实战版)_第5页
已阅读5页,还剩2页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

List、Set、Map高频面试题及详细答案(实战版)一、基础核心面试题1、说一说List、Set、Map的核心区别?答案:三者是Java集合框架的三大核心分支,核心差异集中在元素有序性、重复性、存储结构三点:1.List(列表)有序(插入顺序和遍历顺序一致)、允许元素重复、支持根据索引下标操作元素。底层主要是数组、链表结构,适合频繁查询、遍历的场景。常见实现类:ArrayList、LinkedList、Vector。2.Set(集合)无序(部分实现类有序)、不允许元素重复、无索引下标,不能通过下标获取元素。底层大多基于Map实现,适合去重场景。常见实现类:HashSet、LinkedHashSet、TreeSet。3.Map(映射)以键值对(key-value)形式存储,key唯一不可重复,value可重复;无索引,遍历需要通过key或entry集合。常见实现类:HashMap、LinkedHashMap、TreeMap、HashTable。极简总结:List可重复有序,Set不可重复无序,Map键唯一、值可重复。2、List、Set、Map分别默认初始容量、扩容机制?答案:1.ArrayList默认初始容量10;扩容因子1.5倍。原容量+原容量右移一位(oldCapacity+oldCapacity/2)。2.HashSet底层依托HashMap,默认初始容量16,负载因子0.75,扩容2倍。3.HashMap默认初始容量16,负载因子0.75;当元素个数>容量*负载因子时,扩容为原容量2倍。4.Vector默认初始容量10,扩容默认翻倍(2倍),线程安全但效率低。3、什么是负载因子?为什么HashMap负载因子是0.75?答案:负载因子是集合扩容的阈值,计算公式:元素个数/数组容量。当比值超过设定值,集合触发扩容。0.75是时间和空间的平衡值:1.负载因子过小(如0.5):频繁扩容,浪费内存空间,效率低;2.负载因子过大(如1.0):数组塞满才扩容,哈希冲突概率大幅升高,链表过长,查询效率下降;3.0.75既能减少扩容次数、节省空间,又能控制哈希冲突概率,保证查询和写入效率最优。二、List专项高频题1、ArrayList和LinkedList的区别?工作中怎么选择?答案:核心区别:1.底层结构:ArrayList基于动态数组;LinkedList基于双向链表。2.查询效率:ArrayList支持随机访问,根据下标查询速度极快;LinkedList只能从头遍历,查询效率低。3.增删效率:ArrayList增删会触发数组拷贝、移位,效率低;LinkedList只需要修改节点指针,无需移动元素,增删效率高。4.内存占用:ArrayList会预留冗余容量,存在空间浪费;LinkedList每个节点存储数据和前后指针,单个元素占用内存更大。5.线程安全:两者均非线程安全。使用场景选择:1.绝大多数业务场景:优先用ArrayList(日常查询、遍历居多);2.频繁头尾增删、极少查询的场景:使用LinkedList。2、ArrayList为什么线程不安全?会出现什么问题?答案:ArrayList的add、扩容等方法没有加锁,多线程并发操作时会出现安全问题:1.元素覆盖:两个线程同时执行赋值操作,后一个线程会覆盖前一个线程的结果,导致元素丢失;2.数组越界异常:多线程同时判断容量,都认为无需扩容,同时添加元素,超出数组最大容量,抛出ArrayIndexOutOfBoundsException;3.数据不一致:最终集合元素数量少于实际写入数量。解决方案:使用Vector、Collections.synchronizedList、CopyOnWriteArrayList。3、CopyOnWriteArrayList原理及适用场景?答案:底层基于写时复制机制:写操作时不直接修改原数组,而是复制出一个新数组,在新数组上完成增删改,之后将原数组引用指向新数组;读操作直接读取原数组,无锁。特点:读写分离、读不加锁、写加锁,线程安全;读效率极高,写效率低。适用场景:读多写少的并发场景,比如配置缓存、静态数据列表;不适合大量写入的场景。三、Set专项高频题1、HashSet、LinkedHashSet、TreeSet的区别?答案:1.HashSet底层HashMap,无序、不重复,查询写入效率高,是最常用的Set集合;不保证元素顺序。2.LinkedHashSet继承自HashSet,底层LinkedHashMap,保证插入顺序,去重且有序,效率略低于HashSet。3.TreeSet底层TreeMap,基于红黑树,元素自然排序或自定义排序,默认升序;增删查询效率略低,适合需要排序的去重场景。2、HashSet去重原理?为什么重写equals必须重写hashCode?答案:HashSet去重流程:1.添加元素时,先调用对象的hashCode()计算哈希值,确定数组存储位置;2.如果该位置无元素,直接存入;3.如果该位置有元素,调用equals()对比内容;4.equals返回true,判定元素重复,放弃存入;返回false,发生哈希冲突,挂载链表/红黑树。重写规则原因:如果只重写equals不重写hashCode,两个内容相同的对象,默认hashCode基于对象地址计算,哈希值不同,集合会判定为两个不同对象,无法去重,出现重复数据,违背Set特性。3、TreeSet去重和排序规则?答案:TreeSet去重不依赖hashCode和equals,完全依赖比较器返回值:1.compareTo/compare返回0:判定元素重复,不存入;2.返回正数:元素后置;3.返回负数:元素前置。排序方式两种:一是实现Comparable接口重写compareTo(自然排序);二是创建集合时传入Comparator比较器(自定义排序,优先生效)。四、Map专项高频题1、HashMap、HashTable、ConcurrentHashMap区别?答案:1.HashMap非线程安全;key、value均可为null;初始容量16,扩容2倍;效率最高,单线程首选。2.HashTable线程安全(全局锁);key、value均不能为null;初始容量11,扩容2倍+1;效率极低,基本废弃,不推荐使用。3.ConcurrentHashMap线程安全;key、value不可为null;JDK1.8采用CAS+synchronized锁,锁粒度细化,只锁当前链表节点,并发效率高;多线程场景首选。2、JDK1.7和JDK1.8HashMap的核心区别?答案:1.数据结构1.7:数组+单向链表;1.8:数组+单向链表+红黑树。链表长度≥8且数组容量≥64时,链表转为红黑树;树节点≤6时,退化为链表。2.哈希冲突解决1.7头插法,多线程扩容容易出现循环链表,造成死循环;1.8尾插法,避免了循环链表问题。3.扩容机制1.7重新计算所有元素哈希位置;1.8优化扩容,元素只需判断高位哈希,只需分到原位置或原位置+旧容量位置,效率更高。4.锁机制1.7分段锁;1.8取消分段锁,采用CAS+synchronized。3、HashMap为什么线程不安全?JDK1.8还存在死循环问题吗?答案:线程不安全问题:多线程并发put会出现数据覆盖、元素丢失;并发扩容会引发数据错乱。死循环问题:JDK1.7头插法会导致链表倒置,多线程扩容产生循环链表,触发死循环。JDK1.8改为尾插法,链表顺序不变,彻底解决了扩容死循环问题,但依旧线程不安全,仍会出现数据覆盖丢失。4、HashMap的key可以用哪些类型?为什么不能用可变对象?答案:推荐使用不可变类型:String、Integer、Long等包装类。不推荐自定义可变对象作为key。原因:对象存入HashMap后,如果修改了对象的成员属性,会导致hashCode值改变。后续根据原key获取元素时,计算出的哈希位置和存储位置不一致,无法找到元素,出现数据丢失、查询为空的问题。不可变对象哈希值固定,彻底规避该问题。5、LinkedHashMap的有序性原理?怎么实现LRU缓存?答案:LinkedHashMap继承HashMap,底层在哈希表基础上维护了一条双向链表,记录元素插入顺序或访问顺序。1.默认插入有序:遍历顺序和存入顺序一致;2.开启访问有序(accessOrder=true):每次访问元素后,将元素移至链表尾部。LRU缓存实现:重写removeEldestEntry方法,设定最大缓存容量。当元素数量超过阈值时,自动删除链表头部最久未访问的元素,实现最近最少使用的缓存淘汰策略。五、综合压轴面试题1、工作中List、Set、Map如何选型?答案:1.需要存储重复数据、有序、频繁查询遍历:选ArrayList;2.频繁头尾增删、极少查询:选LinkedList;3.数据去重、无需有序:选HashSet;4.数据去重且保留插入顺序:选LinkedHashSet;5.数据去重且需要排序:选TreeSet;6.键值对存储、单线程:选HashMap;7.键值对存储、多线程并发:选ConcurrentHashMap;8.需要有序键值对:选LinkedHashMap;9.需要按键排序:选TreeMap。2、为什么不推荐使用Vector、HashTable?答案:1.两者都是老旧JDK集合类,方法全部加synchronized全局锁,锁粒度极大;2.并发场景下线程竞争激烈,吞吐量极低,性能极差;3.有更好的替代方案:Vector替换为CopyOnWriteArrayList,HashTable替换为ConcurrentHashMap;4.扩容机制死板,Vector固定翻倍,HashTable扩容效率低,适配性差。3、HashMap中nul

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论