Java Collection 集合面试题及详细答案(实战完整版)_第1页
Java Collection 集合面试题及详细答案(实战完整版)_第2页
Java Collection 集合面试题及详细答案(实战完整版)_第3页
Java Collection 集合面试题及详细答案(实战完整版)_第4页
Java Collection 集合面试题及详细答案(实战完整版)_第5页
已阅读5页,还剩2页未读, 继续免费阅读

下载本文档

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

文档简介

JavaCollection集合面试题及详细答案(实战完整版)一、基础概念类1、说一说Java集合的整体架构?Java集合主要分为两大派系:Collection单列集合和Map双列集合,顶层都是接口,底下是具体实现类,整体架构清晰、职责分明。Collection单列集合主要分三大分支:List:有序、可重复、有索引。常用实现:ArrayList、LinkedList、VectorSet:无序、不可重复、无索引。常用实现:HashSet、LinkedHashSet、TreeSetQueue:队列结构,先进先出。常用实现:ArrayDeque、LinkedListMap双列集合:存储键值对(key-value),key唯一、value可重复。常用实现:HashMap、LinkedHashMap、TreeMap、Hashtable。另外还有工具类Collections,专门用来操作集合,和Collection接口不是一回事。2、Collection和Collections的区别?Collection:是顶层接口,是所有单列集合的父接口,定义了List、Set、Queue的通用方法,比如add、remove、size、clear等。Collections:是工具类,全是静态方法,专门用来操作集合。可以实现集合排序、打乱顺序、线程安全包装、空集合返回等功能。简单说:Collection是集合的规范,Collections是操作集合的工具。3、List、Set、Queue核心区别?集合类型有序性可重复性索引适用场景List有序(存入顺序和取出顺序一致)可重复有索引,可通过下标访问需要频繁查询、根据下标操作元素Set大部分无序(LinkedHashSet有序)不可重复无索引去重场景、唯一性数据存储Queue先进先出顺序可重复无普通索引队列任务、消息排队、限流缓冲二、List集合高频面试题1、ArrayList和LinkedList的区别?(必考)底层结构ArrayList底层是动态扩容数组;LinkedList底层是双向链表。查询效率ArrayList支持随机访问,通过下标直接定位元素,查询速度极快;LinkedList必须从头节点或尾节点遍历查找,查询效率很低。增删效率ArrayList中间、头部增删需要移动大量元素,效率低;尾部新增效率很高。LinkedList只需要修改节点指针,任意位置增删效率更高。内存占用ArrayList会预留扩容空间,存在内存冗余;LinkedList每个节点都要存储前后节点地址,单个元素占用内存更大。使用场景日常开发优先用ArrayList,大部分场景都是查询多、增删少;只有频繁在头部、中间增删元素时才用LinkedList。2、ArrayList扩容机制详细说一下?JDK1.8及以上的ArrayList扩容规则:创建空参ArrayList时,初始不会直接创建长度为10的数组,而是先赋值一个空数组,节省内存。第一次调用add方法添加元素时,初始化数组容量为10。当数组元素个数达到容量上限时,触发扩容,每次扩容为原容量的1.5倍。扩容时会创建新数组,通过数组拷贝把旧元素复制到新数组,再替换底层数组。如果一次性添加大量元素,1.5倍扩容不够用时,会直接扩容到刚好容纳当前所有元素的容量,避免多次扩容。3、ArrayList为什么线程不安全?怎么解决?ArrayList所有方法都没有加锁,多线程并发写入时会出现问题:多个线程同时add,可能出现元素覆盖、数据丢失并发扩容时可能出现数组越界异常最终导致集合实际元素个数和预期不符解决方案:使用Vector(效率低,不推荐)使用Collections.synchronizedList包装(适合低并发)推荐使用CopyOnWriteArrayList,读写分离,读不加锁、写加锁,高并发性能更好4、Vector和ArrayList的区别?Vector线程安全,方法加了synchronized锁;ArrayList线程不安全Vector每次扩容2倍;ArrayList扩容1.5倍,内存利用率更高Vector初始容量就是10;ArrayList空参创建初始为空数组,首次赋值才初始化10Vector效率极低,现在基本不用三、Set集合高频面试题1、HashSet去重原理?HashSet底层本质是HashMap,添加元素时,其实是把元素作为HashMap的key,value是固定的空对象。去重核心依赖两个方法:hashCode()和equals()。去重流程:新增元素时,先调用对象的hashCode计算哈希值,确定存储位置如果该位置没有元素,直接存入如果该位置已有元素,再调用equals方法对比内容equals返回true,判定为重复元素,不存入;返回false,发生哈希冲突,链式存储所以自定义对象想要HashSet去重,必须重写hashCode和equals方法,否则会默认使用父类Object的方法,无法实现内容去重。2、HashSet、LinkedHashSet、TreeSet区别?HashSet:无序、不重复,查询效率高,底层HashMap,适合通用去重场景LinkedHashSet:有序(保留存入顺序)、不重复,底层是LinkedHashMap,比HashSet多维护了双向链表,性能略低,需要去重且保留顺序时使用TreeSet:自然排序、不重复,底层TreeMap,可按照元素大小自动排序,支持自定义比较器,适合需要排序的去重场景3、TreeSet排序规则?自定义类怎么实现排序?TreeSet是可排序集合,默认按照元素自然顺序排序,两种排序方式:自然排序:自定义类实现Comparable接口,重写compareTo方法,定义默认排序规则比较器排序:创建TreeSet时传入Comparator比较器,优先级高于自然排序,适合临时自定义排序如果既没有实现Comparable,也没有传入比较器,添加元素会直接报类型转换异常。同时TreeSet也是通过compare方法判断去重,返回0就判定为重复。四、Map集合高频面试题1、HashMap底层原理(JDK1.8重点)JDK1.8HashMap底层是数组+链表+红黑树的结构,核心是哈希表。存储流程:通过key的hashCode计算哈希值,经过扰动函数优化,算出数组下标下标位置为空,直接存入键值对下标位置有元素,发生哈希冲突,挂在链表尾部当链表长度大于等于8,且数组容量大于等于64时,链表转换为红黑树,提升查询效率当红黑树节点数量小于等于6时,重新退化为链表,减少树结构维护成本默认初始容量16,默认负载因子0.75,达到阈值(容量*负载因子)触发扩容,每次扩容2倍。2、为什么负载因子是0.75?负载因子是平衡空间利用率和查询效率的关键参数。如果负载因子太大(比如1):数组填满才扩容,空间利用率高,但哈希冲突会大量增多,链表变长,查询效率暴跌如果负载因子太小(比如0.5):扩容频繁,冲突少、效率高,但大量空间闲置,内存浪费严重0.75是官方测试的最优值,完美平衡了空间和时间效率3、JDK1.7和JDK1.8HashMap的核心区别?结构:1.7只有数组+链表;1.8新增红黑树结构插入方式:1.7头插法;1.8尾插法,解决了并发扩容的循环链表死循环问题扩容优化:1.8扩容时不需要重新计算哈希,通过高位判断拆分节点,效率更高扰动函数:1.8扰动更简洁,减少哈希冲突4、HashMap、LinkedHashMap、TreeMap、Hashtable区别?HashMap:无序、key唯一、线程不安全、效率高,日常开发首选LinkedHashMap:有序(存入顺序),底层多维护双向链表,可实现LRU缓存淘汰策略TreeMap:可排序,按键的大小自动排序,底层红黑树Hashtable:线程安全、效率极低,不允许key、value为null,基本被淘汰5、HashMap为什么允许一个key为null,多个value为null?key为null时,HashMap会固定存入数组下标0的位置,所以只能存一个nullkey,后续nullkey会覆盖原有数据。而value没有唯一性约束,所以可以多个value为null。Hashtable不允许key和value为null,直接抛空指针异常。6、HashMap线程不安全的表现及解决方案?不安全表现:并发put导致数据覆盖、数据丢失;JDK1.7并发扩容出现循环链表,死循环CPU100%;并发读写导致节点数据异常。解决方案:Collections.synchronizedMap:低并发可用,效率一般ConcurrentHashMap(推荐):分段锁思想(1.7)、CAS+synchronized锁(1.8),高并发性能优异五、集合常见坑点&实战面试题1、集合遍历过程中为什么不能增删元素?普通for遍历、增强for循环、迭代器遍历时,直接调用集合add/remove方法,会触发ConcurrentModificationException并发修改异常。原因:集合内部维护modCount修改次数和expectedModCount预期次数,遍历过程中增删会改变modCount,和预期值不匹配,直接抛异常。解决方式:使用迭代器自带的remove方法使用for循环普通下标遍历(慎用,容易漏遍历或越界)JDK8+使用removeIf方法删除元素(最简洁安全)2、Arrays.asList坑点有哪些?返回的List是Arrays内部静态类,不是ArrayList,没有重写add、remove方法,调用会直接抛异常该集合和原数组绑定,修改数组元素,集合元素也会跟着变不支持基本数据类型数组转换,会把整个数组当成一个元素正确用法:需要newArrayList<>(Arrays.asList())包装一层,转为正常ArrayList。3、ArrayList空参和有参构造的区别?空参构造:初始为空数组,首次add才扩容为10,节省初始化内存有参构造(指定容量):直接创建对应容量的数组,适合提前知道元素数量的场景,避免多次扩容,提升效率4、怎么快速实现集合去重?普通对象:newLinkedHashSet<>(list),有序去重自定义对象:重写hashCode、equals后用Set去重,或JDK8Stream流式去重Stream去重:list.stream().distinct().collect(Collector

温馨提示

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

最新文档

评论

0/150

提交评论