java面试题-集合篇

Collection

1.Collection有哪些类?

Java集合框架中的Collection接口是所有集合类的基础接口,定义了一些基本的集合操作,如添加元素、删除元素、判断是否包含某个元素等。常见的集合类包括List、Set和Queue。

List

List接口定义了按照索引访问和操作元素的方法。它允许元素重复,并且有序。在List中可以使用get()和set()方法访问指定位置的元素,使用add()和remove()方法添加和删除元素。

常见的List实现类有:

  • ArrayList:ArrayList 是一个基于动态数组的实现,支持随机访问,插入和删除操作效率低。

  • LinkedList:底层使用双向链表实现,插入和删除操作效率高,但随机访问效率低。

  • Vector:与ArrayList类似,但是线程安全,效率较低。

Set

Set接口表示一个不允许有重复元素的集合,实现类必须重写equals()方法和hashCode()方法。常见的Set实现类有:

  • HashSet:底层使用哈希表实现,无序,元素唯一。

  • LinkedHashSet:底层使用哈希表和链表实现,有序,元素唯一。

  • TreeSet:底层使用红黑树实现,有序,元素唯一。

Queue

Queue接口表示一个先进先出(FIFO)的队列。常见的Queue实现类有:

  • LinkedList:底层使用链表实现,效率较高,LinkedList实现了Queue接口,它支持在队列的头部和尾部进行元素的添加和删除操作,因此可以被用作栈、队列和双端队列。。

  • PriorityQueue:是一种基于优先级堆的Queue,它保证了每次取出的元素都是队列中优先级最高的元素。。

需要注意的是,这些集合类都是基于Object的,如果需要在集合中存储特定类型的元素,需要使用泛型。例如,List表示一个只包含字符串元素的List。

2.讲一下ArrayList的底层实现?

ArrayList 的底层实现基于数组,它继承了 AbstractList 抽象类并实现了 List 接口。下面是一些关于 ArrayList 的底层实现的细节:

  1. 数组:ArrayList 的内部实现是一个数组,使用数组实现可以方便地进行随机访问,根据索引直接访问指定位置的元素。

  2. 自动扩容:ArrayList 可以自动扩容以适应动态变化的容量需求,每次扩容会增加 50% 的容量。

  3. 元素的添加:ArrayList 中的 add(E e) 方法会在末尾添加一个元素,如果当前容量不足,则会进行扩容。

  4. 元素的删除:ArrayList 中的 remove(int index) 方法会删除指定索引位置的元素,将该位置后面的元素向前移动一位。

3.ArrayList自动扩容的具体实现?

当调用ArrayList的add方法时,如果当前列表中的元素数量已经达到容量的极限,那么就需要自动扩容。扩容的过程就是创建一个新的数组,并将原来数组中的元素复制到新数组中。

默认情况下,ArrayList的容量是10。当第一个元素被添加时,内部数组会被初始化为长度为10的数组。当添加第11个元素时,原始数组将会被复制到一个新的长度为15的数组中,容量增加了50%。如果再添加元素,当超过了15个元素时,内部数组将再次扩容到新的长度为22的数组中。

当使用ensureCapacity方法增加数组容量时,ArrayList使用给定参数的最大值和当前容量的大小来决定新的容量大小。

private void ensureCapacityInternal(int minCapacity) {// 判断是否需要扩容if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);
}private void ensureExplicitCapacity(int minCapacity) {modCount++;// 判断是否需要扩容if (minCapacity - elementData.length > 0) {grow(minCapacity);}
}private void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0) {newCapacity = minCapacity;}if (newCapacity - MAX_ARRAY_SIZE > 0) {newCapacity = hugeCapacity(minCapacity);}elementData = Arrays.copyOf(elementData, newCapacity);
}

扩容操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。

4.ArrayList的Fail-Fast机制?

在 Java 中,如果使用集合类的迭代器来遍历集合元素,而同时修改了集合中的元素,就有可能会发生 ConcurrentModificationException 异常。这是因为 Java 集合类的迭代器是快速失败(fail-fast)机制,如果在迭代集合时集合发生了结构性变化(例如添加或删除元素),迭代器就会立即抛出异常,而不是等到迭代完成再抛出异常。

ArrayList 是一个支持随机访问的序列容器,底层使用数组实现,所以在对 ArrayList 进行并发操作时,可能会出现不同步的问题,因此 ArrayList 也使用了快速失败机制来保证线程安全。

具体来说,如果在对 ArrayList 进行迭代操作的同时,对其进行增删改操作,会导致 ArrayList 的 modCount(修改次数)和迭代器的 expectedModCount(预期的修改次数)不一致,迭代器会立即抛出 ConcurrentModificationException 异常。

以下是一个简单的示例代码,用来演示 ArrayList 快速失败机制的工作原理:

List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7));
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {Integer element = iterator.next();if (element == 2) {list.remove(element);}
}

在上面的示例代码中,我们在迭代过程中删除了元素 2,这会导致 ConcurrentModificationException 异常的抛出。为了避免出现这种情况,我们可以使用 Iterator 的 remove() 方法来进行元素的删除,或者使用线程安全的集合类,例如 CopyOnWriteArrayList。


MAP

1.Map有哪些实现类?

Java中的Map接口定义了一个键值对映射的数据结构,可以通过给定的键快速查找对应的值。Map接口有很多实现类,常见的有以下几种:

  1. HashMap:基于哈希表实现的Map,支持null键和null值,非线程安全的。

  2. LinkedHashMap:基于哈希表和双向链表实现的Map,可以按照插入顺序或者访问顺序遍历键值对,非线程安全的。

  3. TreeMap:基于红黑树实现的Map,键值对按照自然顺序或者自定义顺序排序,非线程安全的。

  4. ConcurrentHashMap:线程安全的HashMap,使用分离锁来控制并发访问,支持高并发,可以通过一定的控制减小锁的竞争。

  5. Hashtable:早期Java版本中提供的线程安全的哈希表,支持null键和null值,但是效率较低,已经被ConcurrentHashMap取代。

  6. Properties:Hashtable的子类,用来读取和写入属性文件,通常用于读取配置文件。

除了以上这些常见的实现类,还有一些其他的实现类,比如WeakHashMap、IdentityHashMap、EnumMap等,不过它们使用的较少,一般只在特定场景下使用。

2.HashMap的底层实现(jdk7&jdk8)?

JDK7 的底层实现

在 JDK7 中,HashMap 是通过数组和链表的结合来实现的。其基本思路是:将 key 通过哈希函数映射为数组下标,将 value 存储在对应的数组元素中。如果不同的 key 映射到了同一个数组下标,就会以链表的形式存储在该数组元素中。

HashMap 在 JDK7 中的底层结构主要由两部分组成:一个 Entry 数组和一个链表。其中,Entry 是 HashMap 的基本单元,它包含了 key、value 和指向下一个 Entry 的指针。当使用 put() 方法向 HashMap 中添加元素时,会根据 key 的哈希值计算出在数组中的位置,然后将 Entry 添加到该位置的链表中。如果两个不同的 key 哈希值相同,那么它们会被放到同一个链表中,形成一个链表结构。这就是 JDK7 中 HashMap 的基本实现原理。

然而,这种实现方式有一个严重的问题:当链表过长时,查询效率会大大降低,因为需要遍历整个链表才能找到对应的元素。在极端情况下,当所有的元素都映射到了同一个数组下标,HashMap 的时间复杂度就会退化到 O(n),这就是所谓的哈希冲突问题。

JDK8 的底层实现

JDK8 中的 HashMap 对 JDK7 中的实现进行了优化,主要是通过引入红黑树来解决链表过长的问题。当链表长度超过一定阈值时(默认为 8),链表就会转换为红黑树。这样,在查询时,如果在链表中需要遍历的节点数量超过了阈值,就会使用红黑树进行快速查找,从而提高了查询的效率。

在 JDK8 中,HashMap 的底层结构主要由三部分组成:一个数组、一个链表和一个红黑树。当使用 put() 方法向 HashMap 中添加元素时,如果对应数组下标上已经存在元素,就会进行以下操作:

  • 如果该元素是一个链表,就将新元素追加到链表的末尾。

  • 如果该元素是一个红黑树,就在树中查找 key 对应的节点,然后将节点的 value 替换成新的 value。如果树中不存在对应的节点,就将新元素添加到树中。

  • 如果该元素为 null,就直接在该数组的位置插入新的 Entry。

在 JDK8 中,HashMap 的 get() 方法的实现方式也发生了变化。在查询时,先根据 key 的哈希值计算出在数组中的位置,然后判断该位置上的元素是否为 null。如果为 null,则返回 null;如果不为 null,则判断该元素是链表还是红黑树。如果是链表,则遍历链表寻找对应的元素;如果是红黑树,则在树中进行查找。

JDK8 中 HashMap 的优化主要体现在两个方面:

  1. 引入红黑树,解决链表过长的问题,提高了查询效率。当链表长度超过一定阈值时,将链表转换为红黑树,避免了链表过长时查询效率下降的问题。

  2. 除了对链表和红黑树的优化之外,JDK 8 还对哈希函数进行了改进。在 JDK 8 中,对于 key 的 hash 值,不再采用传统的取模运算(%)计算哈希桶的索引,而是采用了一种新的方式,使用 key 的 hash 值高位和低位进行异或运算,以此来增加哈希桶的分布性。这种新的方式能够更好地抵抗哈希冲突,从而提高了 HashMap 的性能。

  3. HashMap 将插入元素时使用的方式从头插法改为了尾插法,更好地支持并发操作。在多线程环境下,头插法容易导致多线程竞争同一个桶位,从而导致链表成环。成环后会导致链表转换成红黑树的操作失败,进而影响整个 HashMap 的性能。而尾插法不会导致链表成环,因此在多线程环境下更为安全。

总的来说,JDK8 中 HashMap 的底层实现相比于 JDK7 发生了较大的变化,通过引入红黑树和优化哈希算法,提高了 HashMap 的性能和稳定性。

3.HashSet的底层实现?

HashSet 是基于 HashMap 实现的,底层是一个 HashMap 对象。在 HashSet 中,所有元素都是存储在一个 HashMap 的键上,而这个键的值则是一个静态的 Object 常量(通常是一个 dummy Object)。因此,HashSet 的实现过程可以简单概括为将所有元素作为 HashMap 的 key 存储,而 value 为一个静态的 Object 对象。

具体来说,HashSet 就是在 HashMap 的基础上去掉了 value,只保留了 key。在使用 HashSet 时,我们只需要调用 HashMap 的 put() 方法,把元素作为 key 插入 HashMap 中,value 则使用一个常量对象(例如 private static final Object PRESENT = new Object())来占位即可。

相比于 HashMap,HashSet 的实现过程更为简单,因为它只需要存储键而不需要存储值。因此,HashSet 在大多数情况下比 HashMap 更加高效。同时,由于 HashSet 也是基于 HashMap 实现的,因此它们的底层实现也非常相似,可以复用 HashMap 的很多特性。

以下是 HashSet 的部分源码:

public class HashSet<E>extends AbstractSet<E>implements Set<E>, Cloneable, java.io.Serializable
{// HashSet 底层就是一个 HashMap,所有元素作为 key 存储在 HashMap 中private transient HashMap<E,Object> map;// 常量对象,用于占位private static final Object PRESENT = new Object();public HashSet() {map = new HashMap<>();}public boolean add(E e) {return map.put(e, PRESENT)==null;}
}

可以看到,在 HashSet 中,我们只需要调用 HashMap 的 put() 方法来将元素插入到 HashMap 中。这样做的好处是可以节省很多重复代码,而且可以复用 HashMap 的很多特性。同时,由于 HashSet 只存储键而不存储值,因此在大多数情况下比 HashMap 更加高效。

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

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

相关文章

国内 网络安全沙箱

CSRF攻击 CSRF攻击概述&#xff1a; CSRF&#xff08;Cross Site Request Forgery, 跨站域请求伪造&#xff09;是一种网络的攻击方式&#xff0c;它在 2007 年曾被列为互联网 20 大安全隐患之一。其他安全隐患&#xff0c;比如 SQL 脚本注入&#xff0c;跨站域脚本攻击等在近…

Web3 的虚实融合之路:从虚拟交互到元宇宙构建

在这个数字技术日新月异的时代&#xff0c;我们正站在 Web3 的门槛上&#xff0c;见证着互联网的又一次革命。Web3 不仅仅是技术的迭代&#xff0c;它代表了一种全新的交互方式和价值创造模式。本文将探讨 Web3 如何推动虚拟交互的发展&#xff0c;并最终实现元宇宙的构建&…

项目中菜单按照层级展示sql

效果如图&#xff1a; 直接上脚本 查四级菜单 select EFT_FLAG,MENU_ID, CASE LEN(MENU_LVL)WHEN 4THEN MENU_NAME ELSE - END AS MENU_NAME1, CASE LEN(MENU_LVL)WHEN 8THEN MENU_NAME ELSE - END AS MENU_NAME2, CASE LEN(MENU_LVL)WHEN 12THEN MENU_NAME ELSE - END …

Reasoning in High Gear 推理加速发展

Reasoning in High Gear 推理加速发展 关键信息&#xff1a;OpenAI推出GPT - 3 - mini&#xff0c;它是GPT - 1模型后续版本&#xff0c;在速度、成本及特定领域能力上有显著优势。 模型特性 推理强度可选&#xff1a;提供低、中、高三个推理 “强度” 级别&#xff0c;不同级别…

Linux驱动层学习:LED 驱动开发

前置知识&#xff1a; 1、地址映射 MMU 全称叫做 Memory Manage Unit&#xff0c;也就是内存管理单元。 MMU 主要完成的功能如下&#xff1a; ①、完成虚拟空间到物理空间的映射。 ②、内存保护&#xff0c;设置存储器的访问权限&#xff0c;设置虚拟存储空间的缓冲特性。 第…

数据挖掘智能Agent

&#x1f917; CodeGenie - 智能编程助手 数据处理和分析对于数据分析工作人员来说&#xff0c;往往既复杂又令人头疼&#xff0c;需要耗费大量精力进行重复性工作。为了解决这一问题&#xff0c;我们开发了一款集成了自然语言处理和代码生成功能的智能编程助手——CodeGenie。…

【C++】Vector容器

为什么要学习vector&#xff1f; 1. 上一章分享了string&#xff0c;而string实际上是一个管理字符的顺序表。 2. 而除了字符以外&#xff0c;我们经常用到整形数组&#xff0c;所以我们需要针对其他类型数据的顺序表。 3. vector实际上也是一个顺序表&#xff0c;而且主要用来…

国内 ChatGPT Plus/Pro 订阅教程

1. 登录 chat.openai.com 依次点击 Login &#xff0c;输入邮箱和密码 2. 点击升级 Upgrade 登录自己的 OpenAI 帐户后&#xff0c;点击左下角的 Upgrade to Plus&#xff0c;在弹窗中选择 Upgrade plan。 如果升级入口无法点击&#xff0c;那就访问这个网址&#xff0c;htt…

Winform禁止高分辨下缩放布局成功方法

Windows自动缩放布局会导致窗体上的按钮和文本挤在一起根本看不清楚。 那么该如何解决呢&#xff1f; 具体操作步骤如下&#xff1a; 1、在项目属性上切换到【安全性】菜单&#xff0c;勾选【启用ClickOnce安全设置】&#xff0c;然后立刻取消勾选&#xff1b; 为了生成app.…

数据结构——Makefile、算法、排序(2025.2.13)

目录 一、Makefile 1.功能 2.基本语法和相关操作 &#xff08;1&#xff09;创建Makefile文件 &#xff08;2&#xff09;编译规则 &#xff08;3&#xff09;编译 &#xff08;4&#xff09;变量 ①系统变量 ②自定义变量 二、 算法 1.定义 2.算法的设计 &#xff…

Xcode证书密钥导入

证书干嘛用 渠道定期会给xcode证书&#xff0c;用来给ios打包用&#xff0c;证书里面有记录哪些设备可以打包进去。 怎么换证书 先更新密钥 在钥匙串访问中&#xff0c;选择系统。(选登录也行&#xff0c;反正两个都要导入就是了)。 mac中双击所有 .p12 后缀的密钥&#xff…

span标签 鼠标移入提示框 el-tooltip element-ui

<el-tooltip :content"item.value" placement"top"><span>{{ item.valueHidden }}</span></el-tooltip>

[创业之路-300]:进一步理解货币与金钱, 货币与货币政策

目录 一、货币 1.1 概述 1、货币的定义 2、货币的形态演变 3、货币的职能 4、货币的价值衡量 1.2 货币的分层 1、货币分层的目的与意义 2、货币分层的划分标准与层次 3、各国货币分层的实践 4、货币分层的影响与应用 1.3、M0、M1、M2变化对股市的影响 1、M0变化对…

pnpm的使用

pnpm的使用 1.安装和使用2.统一包管理工具下载依赖 1.安装和使用 pnpm:performant npm &#xff0c;意味“高性能的npm”。 pnpm由npm/yarn衍生而来,解决了npm/yarn内部潜在的bug,极大的优化了性能,扩展了使用场景。被誉为“最先进的包管理工具”。 pnpm安装指令: npm i -g p…

vue+springboot+webtrc+websocket实现双人音视频通话会议

前言 最近一些时间我有研究&#xff0c;如何实现一个视频会议功能&#xff0c;但是找了好多资料都不太理想&#xff0c;最终参考了一个文章 WebRTC实现双端音视频聊天&#xff08;Vue3 SpringBoot&#xff09; 只不过&#xff0c;它的实现效果里面只会播放本地的mp4视频文件&…

nginx播放视频(auth_request鉴权)

学习链接 Nginx通过auth_request结合Springboot实现静态文件下载鉴权 nginx搭建直播推流服务&推流拉流鉴权 步骤 1、安装nginx 这里nginx的版本是nginx-1.24.0 ./configure --with-http_ssl_module --with-stream --with-stream_ssl_module --with-http_auth_req…

【论文笔记】ZeroGS:扩展Spann3R+GS+pose估计

spann3r是利用dust3r做了增量式的点云重建&#xff0c;这里zeroGS在前者的基础上&#xff0c;进行了增量式的GS重建以及进行了pose的联合优化&#xff0c;这是一篇dust3r与GS结合的具有启发意义的工作。 abstract NeRF和3DGS是重建和渲染逼真图像的流行技术。然而&#xff0c;…

Webpack相关优化总结

在使用webpack时提供了各种配置&#xff0c;这里结合在业务中常用的配置汇总一下可以进行的一系列的webpack优化 缩小文件搜索范围 其原理是在构建时&#xff0c;会以用户配置的Entry为开始依次递归遍历每个Module&#xff0c;在遍历每个Module时会调用相应合适的Loader对原模…

【操作系统】操作系统结构

内核 什么是内核&#xff1f; 内核作为应用程序连接硬件设备的桥梁&#xff0c;使得应用程序只需关心与内核交互&#xff0c;不用关心硬件细节。 内核有哪些能力呢&#xff1f; 内核是怎么工作的&#xff1f; Linux 的设计 MultiTask SMP ELF ELF 的意思是可执行文件链接格式…

【无线感知会议系列-22 】Vivisecting Mobility Management in 5G Cellular Networks

这篇是发表在SIGCOMM上的一篇paper 研究方向国内一些移动应用APP厂商&#xff1a;比如抖音,腾讯可以借鉴一下&#xff0c;和终端 厂商联合开发&#xff0c;提高其QOE。 摘要 随着5G技术对多种无线电频段和不同部署模式&#xff08;例如独立组网&#xff08;SA&#xff09;与…