JAVA:集合框架常见的面试题和答案

1、List接口的常见实现类有哪些?

答: 常见的List接口实现类包括:

  • ArrayList: 基于动态数组实现的List,支持快速随机访问。
  • LinkedList: 基于链表实现的List,支持快速的插入和删除操作。
  • Vector: 一个线程安全的动态数组,通常不建议使用,可以用ArrayList代替。
  • Stack: 继承自Vector,表示一个后进先出(LIFO)的堆栈。

2、ArrayList和LinkedList的区别是什么?

  • 数据结构实现:ArrayList :基于数组,便于按 index 访问,超过数组需要扩容,扩容成本较高。LinkedList:使用链表实现,无需扩容。
  • 随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
  • 增加和删除效率:在非首尾的增删操作,LinkedList 要比ArrayList 效率要高,因为ArrayList 增删操作要影响数组内的其他数据的下标。
  • 内存空间占用:LinkedList 比 ArrayList 更占内存,因为LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
  • 线程安全:ArrayList 和 LinkList 都是不同步的,不保证线程安全。
  • 综合来说,需要频繁读取集合中的元素时,更推荐使用 Arrayist,而在增删操作较多时,更推荐使用 LinkedList。
  • LinkedList 的双向链表是链表的一种,它的每个数据结点中都有2 个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便的访问它的前驱结点和后继结点。

3、Map接口的常见实现类有哪些?

答: 常见的Map接口实现类包括:

  • HashMap: 基于哈希表实现的Map,提供了快速的查找性能。
  • TreeMap: 基于红黑树实现的有序Map,按键的自然顺序或者定制的顺序进行排序。
  • LinkedHashMap: 基于哈希表和双向链表实现的Map,可以按照插入顺序或者访问顺序进行遍历。
  • Hashtable: 一个线程安全的哈希表,通常不建议使用,可以用HashMap代替。
  • ConcurrentHashMap: 一个线程安全的哈希表,支持并发操作。

4、HashTable,HashMap,TreeMap区别?

  • HashTable线程同步,HashMap,TreeMap非线程同步。
  • HashTable,TreeMap不允许<键,值>有空值,HashMap允许<键,值>有空值。
  • HashTable中hash数组的默认大小是11,增加方式的old*2+1,HashMap中hash数组的默认大小是16,增长方式一定是2的指数倍。
  • TreeMap能够把它保存的记录根据键排序,默认是按升序排序,因此如果你的键需要有序,建议使用TreeMap代替HashMap。

5、加载因子(扩容因子)为何默认是0.75?

  • 在空间占用与查询时间之间取得了较好的权衡
  • 大于这个值,空间节省了,但是链表可能过长就会影响性能
  • 小于这个值,冲突减少了,但是扩容就会比较频繁,空间占用多并且扩容也会消耗性能

6、LinkedHashMap的应用,底层,原理

答:LinkedHashMap维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序(insert-order)或者是访问顺序,其中默认的迭代访问顺序就是插入顺序,即可以按插入的顺序遍历元素,这点和HashMap有很大的不同。
LRU算法可以用LinkedHashMap实现。

7、HashMap 的底层数据结构是怎样的 ?

JDK1.8 之前

  • JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是链表散列。
  • HashMap 通过 key 的 hashCode 经过扰动函数处理过后得到hash 值,然后通过(n-1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。
  • 所谓扰动函数指的就是 HashMap 的 hash 方法。使用 hash 方法也就是扰动函数是为了防止一些实现比较差的 hashCode() 方法 换句话说使用扰动函数之后可以减少碰撞。

JDK1.8 之后

  • 当链表长度大于阈值(默认为 8)时,会首先调用 treeifyBin()方法。这个方法会根据HashMap 数组来决定是否转换为红黑树。只有当数组长度大于或者等于64的情况下,才会执行转换红黑树操作,以减少搜索时间。否则,就是只是执行resize() 方法对数组扩容。

8、HashMap 的扩容机制是怎样的?

一般情况下,当元素数量超过阈值时便会触发扩容。每次扩容的容量都是之前容量的2倍。HashMap 的容量是有上限的,必须小于 1<<30,即 1073741824。如果容量超出了这个数,则不再增长,且阈值会被设置为 Integer.MAX_VALUE。

JDK7 中的扩容机制

  • 空参数的构造函数:以默认容量、默认负载因子、默认阈值初始化数组。内部数组是空数组。
  • 有参构造函数:根据参数确定容量、负载因子、阈值等。
  • 第一次 put 时会初始化数组,其容量变为不小于指定容量的2 的幂数,然后根据负载因子确定阈值。
  • 如果不是第一次扩容,则 新容量=旧容量 x 2 ,新阈值=新容量x 负载因子。JDK8 的扩容机制
  • 空参数的构造函数:实例化的 HashMap 默认内部数组是null,即没有实例化。第一次调用 put 方法时,则会开始第一次初始化扩容,长度为 16。
  • 有参构造函数:用于指定容量。会根据指定的正整数找到不小于指定容量的2的幂数,将这个数设置赋值给阈值(threshold)。第一次调用 put 方法时,会将阈值赋值给容量,然后让 阈值 = 容量 x 负载因子。
  • 如果不是第一次扩容,则容量变为原来的 2 倍,阈值也变为原来的2 倍。(容量和阈值都变为原来的 2 倍时,负载因子还是不变)。
    此外还有几个细节需要注意:
  • 首次 put 时,先会触发扩容(算是初始化),然后存入数据,然后判断是否需要扩容;
  • 不是首次 put,则不再初始化,直接存入数据,然后判断是否需要扩容;

9、ConcurrentHashMap 的存储结构是怎样的?

  • Java7 中 ConcurrnetHashMap 使用的分段锁,也就是每一个Segment 上同时只有一个线程可以操作,每一个 Segment 都是一个类似 HashMap 数组的结构,它可以扩容,它的冲突会转化为链表。但是 Segment 的个数一但初始化就不能改变,默认Segment的个数是 16 个。
  • Java8 中的 ConcurrnetHashMap 使用的 Synchronized 锁加CAS 的机制。结构也由Java7 中的 Segment 数组 + HashEntry 数组 + 链表 进化成了Node 数组+链表/红黑树,Node 是类似于一个 HashEntry 的结构。它的冲突再达到一定大小时会转化成红黑树,在冲突小于一定数量时又退回链表。

10、用过 ConcurrentHashMap,讲一下他和HashTable 的不同之处?

  • HashTable 就是实现了 HashMap 加上了 synchronized,而ConcurrentHashMap底层采用分段的数组+链表实现,线程安全
  • ConcurrentHashMap 通过把整个 Map 分为 N 个 Segment,可以提供相同的线程安全,但是效率提升 N 倍,默认提升 16 倍。
  • 并且读操作不加锁,由于 HashEntry 的 value 变量是 volatile 的,也能保证读取到最新的值。
  • Hashtable 的 synchronized 是针对整张 Hash 表的,即每次锁住整张表让线程独占,ConcurrentHashMap 允许多个修改操作并发进行,其关键在于使用了锁分离技术
  • 扩容:段内扩容(段内元素超过该段对应 Entry 数组长度的75%触发扩容,不会对整个Map 进行扩容),插入前检测需不需要扩容,有效避免无效扩容

11、比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同

  • HashSet 是 Set 接口的主要实现类 ,HashSet 的底层是HashMap,线程不安全的,可以存储 null 值;
  • LinkedHashSet 是 HashSet 的子类,能够按照添加的顺序遍历;
  • TreeSet 底层使用红黑树,元素是有序的,排序的方式有自然排序和定制排序。

12、Comparable 和 Comparator 的区别?

  • comparable 接口实际上是出自 java.lang 包 它有一个 compareTo(Object obj)方法用来排序
  • comparator 接口实际上是出自 java.util 包它有一个 compare(Object obj1, Objectobj2)方法用来排序
    一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo()方法或compare()方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写 compareTo()方法和使用自制的Comparator 方法或者以两个 Comparator 来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的 Collections.sort()。

13、什么是哈希冲突?

答:当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们就把它叫做碰撞(哈希碰撞)。

14、CopyOnWriteArrayList与ArrayList、Vector的区别

答:CopyOnWriteArrayList与ArrayList、Vector有以下主要区别:

  • 线程安全性:CopyOnWriteArrayList是线程安全的,而ArrayList不是;Vector也是线程安全的,但它使用全局锁,导致性能较差。
  • 读写性能:CopyOnWriteArrayList具有较高的并发读性能,但写操作性能较差,因为每次写操作都需要复制一个新的副本。ArrayList具有较高的读写性能,但在多线程环境下可能出现线程安全问题。Vector的读写性能较差,因为它使用全局锁。
  • 内存占用:CopyOnWriteArrayList在写操作时需要复制一个新的副本,因此可能导致较高的内存占用。ArrayList和Vector的内存占用相对较低。
  • 实时性:CopyOnWriteArrayList的迭代器只能获取到写操作前的数据副本,因此在迭代过程中无法获取实时数据。ArrayList和Vector的迭代器可以获取实时数据,但在多线程环境下可能会导致线程安全问题。

15、如何将Map转换为List?

答: 可以使用ArrayList的构造函数或者addAll方法将Map转换为List。

使用构造函数:

List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet());

使用addAll方法:

List<Map.Entry<K, V>> list = new ArrayList<>();
list.addAll(map.entrySet());

16、LinkedHashSet和CopyOnWriteArraySet的区别

答:LinkedHashSet和CopyOnWriteArraySet是Java集合框架中不同的实现类,它们具有不同的特性和适用场景。

LinkedHashSet:

  • 内部实现:
    LinkedHashSet 是基于哈希表和双向链表实现的,它继承自HashSet,保留了元素插入的顺序。
  • 有序性:
    LinkedHashSet 保持了元素插入的顺序,因此可以按照插入顺序进行遍历。
  • 性能:
    由于它的底层实现依赖于哈希表,因此查找元素的速度非常快。
  • 线程安全:
    LinkedHashSet 是非线程安全的。
  • 适用场景:
    当你需要保留元素插入的顺序,并且不需要考虑线程安全时,可以使用LinkedHashSet。

CopyOnWriteArraySet:

  • 内部实现:
    CopyOnWriteArraySet 是基于CopyOnWriteArrayList实现的,它是一个线程安全的Set。
  • 线程安全:
    CopyOnWriteArraySet 是线程安全的,它的所有修改操作都是在一个新的副本上进行的,而不会影响原始集合。
  • 写时复制:
    当需要对集合进行修改时,CopyOnWriteArraySet 会先复制一个新的数组,然后在新的数组上进行修改,最后将新的数组替换原始数组。
  • 适用场景:
    当你需要在多线程环境下保证安全地对集合进行修改时,可以使用CopyOnWriteArraySet。它适用于读多写少的场景。

17、Java中Queue接口的常见实现类有哪些?

答: 常见的Queue接口实现类包括LinkedList、PriorityQueue和ArrayDeque。

18、LinkedList和ArrayDeque之间有什么区别?

  • LinkedList 是一个双向链表实现的队列,可以作为队列和双端队列使用。
  • ArrayDeque 是一个基于动态数组实现的双端队列,它的性能比LinkedList稍好,但不支持索引访问。

19、PriorityQueue是什么?它是如何工作的?

答: PriorityQueue 是一个优先级队列,它根据元素的优先级来确定出队顺序。默认情况下,PriorityQueue 是一个最小堆实现,可以通过提供一个自定义的Comparator来实现最大堆。

20、队列和栈有什么区别?

  • 队列是一种先进先出(FIFO)的数据结构,只允许在队列的一端插入元素,在另一端删除元素。
  • 栈是一种后进先出(LIFO)的数据结构,只允许在栈的一端插入和删除元素。

21、如何在多线程环境中使用BlockingQueue?

答案: 可以通过创建一个BlockingQueue实例,然后在生产者线程中使用put方法向队列中添加元素,在消费者线程中使用take方法获取元素。

BlockingQueue<ElementType> queue = new LinkedBlockingQueue<>();
// 生产者线程
queue.put(element);
// 消费者线程
ElementType element = queue.take();

22、ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?

  • ConcurrentLinkedQueue 是一个基于非阻塞算法实现的非阻塞队列,它在高并发环境下表现良好。
  • LinkedBlockingQueue 是一个基于锁实现的阻塞队列,它可以在队列为空或者满时阻塞线程。

23、如何实现一个自定义的优先级队列?

答案: 可以使用PriorityQueue并提供一个自定义的比较器(Comparator)来实现一个自定义的优先级队列。

PriorityQueue<Element> priorityQueue = new PriorityQueue<>(new MyComparator()

24、ArrayBlockingQueue和LinkedBlockingQueue的区别

答:ArrayBlockingQueue和LinkedBlockingQueue是Java中两种不同类型的阻塞队列实现,它们有一些重要的区别。

ArrayBlockingQueue:

  • 内部实现:
    ArrayBlockingQueue 是一个基于数组实现的有界阻塞队列,它按照先进先出(FIFO)的原则对元素进行排序。
  • 容量限制:
    ArrayBlockingQueue 在创建时需要指定一个固定的容量,即队列中可以存放的最大元素数量。
  • 阻塞特性:
    当队列已满时,ArrayBlockingQueue 会阻塞等待直到有空间可以放置新元素。
    当队列为空时,尝试从中获取元素的操作会被阻塞等待,直到队列中有新的元素。
  • 性能:
    由于底层是基于数组实现的,因此在性能上比LinkedBlockingQueue更高效,但它的容量是固定的。

LinkedBlockingQueue:

  • 内部实现:
    LinkedBlockingQueue 是一个基于链表实现的无界阻塞队列,它按照先进先出(FIFO)的原则对元素进行排序。
  • 容量限制:
    LinkedBlockingQueue 的容量理论上可以是无限大,因此它不会因为达到最大容量而阻塞。
  • 阻塞特性:
    当队列为空时,尝试从中获取元素的操作会被阻塞等待,直到队列中有新的元素。
    当队列已满时,LinkedBlockingQueue 会阻塞等待直到有空间可以放置新元素。
  • 性能:
    由于底层是基于链表实现的,相对于ArrayBlockingQueue来说,它在高并发场景下可能会略显低效。
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/122637.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Java的流浪动物救助管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

Qt中实现页面切换的两种方式

文章目录 方式一 &#xff1a;使用QStackedWidget讲解代码结构main.cpp完整代码运行结果&#xff1a; 方式二 &#xff1a;代码结构完整代码mainwindow.hnewmainwindow.hmain.cppmainwindow.cppnewmainwindow.cppmainwindow.uinewmainwindow.ui 效果 方式一 &#xff1a;使用QS…

docker 部署 若依 Ruoyi springboot+vue分离版 dockerCompose

本篇从已有虚拟机/服务器 安装好dokcer为基础开始讲解 1.部署mysql 创建conf data init三个文件夹 conf目录存放在mysql配置文件 init目录存放着若依数据库sql文件&#xff08;从navicat导出的并非若依框架自带sql&#xff09; 创建一个属于本次若依部署的网段&#xff08;只…

sql-50练习题6-10

sql练习题6-10题 前言数据库表结构介绍学生表课程表成绩表教师表 0-6 查询"李"姓老师的数量0-7 查询学过"李四"老师授课的同学的信息0-8 查询没学过"李四"老师授课的同学的信息0-9 查询学过编号为"01"并且也学过编号为"02"的…

Redis(09)| Reactor模式

我们在使用Redis的时候&#xff0c;通常是多个客户端连接Redis服务器&#xff0c;然后各自发送命令请求(例如Get、Set)到Redis服务器&#xff0c;最后Redis处理这些请求返回结果。 从上一篇博文《Redis&#xff08;08&#xff09;| 线程模型》中知道Redis是单线程。Redis除了处…

数据结构——栈与队列

目录 1. 中缀表达式转换为后缀表达式 2. 括号匹配问题 3. 栈实现队列 4. 约瑟夫环 1. 中缀表达式转换为后缀表达式 【问题描述】 输入一个中缀表达式&#xff0c;表达式中有、-、*、/四种运算以及&#xff08;、&#xff09;&#xff0c;表达式中的其他符号为大写的字母。实…

QT webengine显示HTML简单示例

文章目录 参考示例1TestWebenqine.promainwindow.hmainwindow.cppmain.cpp效果 示例2 (使用setDevToolsPage函数)main.cpp效果 参考 QT webengine显示HTML简单示例 示例1 编译器 : Desktop Qt 5.15.2 MSVC2019 64bit编辑器: QtCreator代码: TestWebenqine.pro # TestWeben…

pycharm运行R语言脚本(win10环境下安装)

文章目录 简介1. pycharm安装插件2. 安装R语言解释器2.1下载安装包2.2具体安装过程 3.编辑环境变量4 检验是否安装成功&#xff1a;5.安装需要的library6.pycharm中配置安装好的R语言解释器 简介 pycharm 安装 R language for Intellij R language for Intellij 是一个插件&am…

震惊!原来BUG是这么理解的!什么是BUG?软件错误(BUG)的概念

较为官方的概念&#xff1a; 当且仅当规格说明是存在的并且正确&#xff0c;程序与规格说明之间的 不匹配才是错误。 当需求规格说明书没有提到的功能&#xff0c;判断标准以最终用户为准&#xff1a;当程序没有实现其最终用户合理预期的 功能要求时&#xff0c;就是软…

【Python 零基础入门】常用内置函数 初探

【Python 零基础入门】内容补充 1 常用内置函数 Python 简介为什么要学习内置函数数据类型和转换int(): 转为整数float(): 转为浮点数list(): 转为列表tuple(): 转换为元组set():转换为集合dict(): 创建字典: 数学运算abs(): 绝对值pow(): 幂运算round(): 四舍五入min(): 最小值…

NPM【问题 01】npm i node-sass@4.14.1报错not found: python2及Cannot download问题处理

node-sass安装问题处理 1.问题2.处理2.1 方案一【我的环境失败】2.2 方案二【成功】2.3 方案三【成功】 1.问题 gyp verb which failed Error: not found: python2 # 1.添加Python27的安装路径到环境变量 gyp verb check python checking for Python executable "python…

leetcode:1154. 一年中的第几天(python3解法)

难度&#xff1a;简单 给你一个字符串 date &#xff0c;按 YYYY-MM-DD 格式表示一个 现行公元纪年法 日期。返回该日期是当年的第几天。 示例 1&#xff1a; 输入&#xff1a;date "2019-01-09" 输出&#xff1a;9 解释&#xff1a;给定日期是2019年的第九天。 示例…

51单片机实验:数码管动态显示00-99

1、实验要求 利用STC89C52RC单片机开发板实现&#xff1a;使用2位数码管循环显示00-99&#xff0c;每次间隔1s&#xff0c;并且当计数到20时&#xff0c;则蜂鸣器鸣响1次。 2、实验分析 程序实现分析&#xff1a; 1、定义数码管位选引脚&#xff08;P2.4、P2.5、P2.6、…

idea上怎么将新创建项目转为maven项目

场景 在刚创建的一个项目中&#xff0c;往往没有被识别为maven项目&#xff0c;怎么做呢&#xff1f; 方法 然后选maven&#xff0c;这样这个项目就变成了maven项目

TYWZOJ 种树苗 待定题解

文章目录 题目描述输入格式输出格式样例样例输入样例输出 数据范围与提示思路与部分实现完整代码 题目描述 在游戏 Minecraft 中&#xff0c;玩家可以通过种树来使木材再生。玩家需要将树苗种在泥土上&#xff0c;然后等待它长成大树&#xff0c;期间可以利用骨粉来催熟树苗。…

UE4 体积云制作 学习笔记

首先Noise本来就是一张噪点图 云的扰动不能太大&#xff0c;将Scale调小&#xff0c;并将InputMin调整为0 形成这样一张扰动图 扰动需要根据材质在世界的位置进行调整&#xff0c;所以Position需要加上WorldPosition 材质在不同世界位置&#xff0c;噪点不同 除以一个数&#…

UI组件库基础

UI组件库 全局组件* 全局注册组件 & 并且使用了require.context 模块化编程 & webpack打包 const install(Vue)>{const contextrequire.context(.,true,/\.vue$/)context.keys().forEach(fileName>{const modulecontext(fileName)Vue.component(module.default.n…

云起无垠典型案例入选《2023软件供应链安全洞察》报告

近日&#xff0c;历时6个月&#xff0c;由ISC编制的《2023软件供应链安全洞察》报告&#xff08;以下简称《报告》&#xff09;正式对外发布。《报告》围绕软件供应链安全现状、技术内核、治理指南、落地实践展开&#xff0c;以期为行业从业者提供有价值的信息和洞见&#xff0…

1.1 计算机安全概念

思维导图&#xff1a; 前言&#xff1a; 第1章: 计算机与网络安全概念笔记 1. 学习目标 了解保密性、完整性和可用性的关键安全需求。了解OSI的X.800安全架构。识别和举例说明不同的安全威胁和攻击。掌握安全设计的基本准则。熟悉攻击面和攻击树的使用。了解与密码标准相关的…

2024年最新水果音乐制作软件FL Studio21需要多少钱呢?

水果&#xff0c;全称Fruity Loop Studio&#xff0c;简称FL Studio。是一款全能的音乐制作软件&#xff0c;经过二十多年的演化更迭&#xff0c;其各项功能非常的先进。其开创性的Pat\song模式&#xff0c;也为初学者的学习提供了便利。那么水果音乐制作软件FL Studio21需要多…