【面试高高手】 —— Java集合篇(23题)

文章目录

    • 1.Java中常见集合有哪些 ?
    • 2. 说说你对Java集合是怎么理解的?
    • 3.请你说一下List,Set,Map三者的特点是 ?
    • 4.在实际开发过程中如何更好的选择集合 ?
    • 5. ArrayList和Vector区别 ?
    • 6. ArrayList和LinkedList之间的区别是什么?
    • 7.HashSet和TreeSet的区别是什么?
    • 8. HashMap和Hashtable之间的区别是什么?
    • 9.什么是迭代器(Iterator)?它的作用是什么?
    • 10.如何在Java中创建不可变集合?
    • 11.如何遍历一个Map?
    • 12.CopyOnWriteArrayList是什么 ?
    • 13.List的遍历例方式该如何选择?
    • 14.ArrayList的扩容机制?
    • 15.CopyOnWriteArrayList有啥优缺点 ?
    • 16.CopyOnWriteArrayList的实现原理是什么 ?
    • 17.CopyOnWriteArrayList为什么并发安全且性能比Vector好 ?
    • 18.HashSet是如何检查重复的 ?
    • 19.ConcurrentHashMap特点和底层原理?
    • 20.如何将数组转换为List?
    • 21.HashSet和LinkedHashSet内部有什么区别?
    • 22.如何在集合中查找元素是否存在?
    • 23.线程安全的集合有哪些?他们的底层实现?

1.Java中常见集合有哪些 ?

  • Collection
    • List :支持有序、可重复的元素,ArrayList、LinkedList、Vector。
    • Set:无序,不允许重复元素,常用实现类有 HashSet、LinkedHashSet、TreeSet。
    • Queue:队列
    • Deque :双端队列
  • Map
    • HashMap
    • LinkedHashMap
    • HashTable:类似于 HashMap,但是是线程安全的,不推荐使用,可以使用 ConcurrentHashMap 代替。

2. 说说你对Java集合是怎么理解的?

Java集合是一组用于存储和操作数据的类和接口的集合。它们是Java编程中非常重要的一部分,用于管理和组织数据,提供了各种数据结构和算法,以满足不同类型的数据存储和检索需求。以下是我对Java集合的理解:

  • 数据存储和组织:Java集合用于存储和组织数据,可以存储不同类型的数据,包括基本数据类型和对象。它们提供了各种数据结构,如列表(List)、集合(Set)、映射(Map)等,以满足不同的数据组织需求。

  • 动态大小:Java集合通常具有动态大小,可以根据需要自动扩展或缩小。这使得它们非常灵活,可以适应不同数量的数据。

  • 类型安全:Java集合是类型安全的,这意味着它们可以在编译时检查数据类型,从而减少运行时错误。

  • 高性能:Java集合类经过优化,提供了高性能的数据访问和操作方法,以确保在大规模数据集上的效率。

  • 迭代和遍历:Java集合提供了方便的迭代和遍历机制,可以轻松地访问集合中的元素。

  • 多线程支持:Java集合包括线程安全的实现,例如ConcurrentHashMap,以支持多线程环境中的并发访问。

  • 丰富的功能:Java集合提供了丰富的功能,包括排序、查找、过滤、映射等操作,以满足各种数据处理需求。

  • 常见集合类:Java中一些常见的集合类包括ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等。每个集合类都有其独特的特点和适用场景。

泛型支持:Java集合框架使用泛型来增强类型安全性,允许您在编译时指定集合中存储的元素类型。

3.请你说一下List,Set,Map三者的特点是 ?

  • List(列表):
    • 有序性:List是有序集合,它按照元素的插入顺序来维护元素。
    • 可重复性:List允许存储重复元素,同一个元素可以多次出现。
    • 访问元素:可以通过索引(位置)来访问和操作List中的元素,支持随机访问。
    • 常见实现类:ArrayList,LinkedList,Vector等。
  • Set(集合):
    • 无序性:Set是无序集合,它不维护元素的特定顺序。
    • 唯一性:Set不允许存储重复元素,每个元素在Set中只能出现一次。
    • 不支持索引:Set不支持通过索引访问元素,因为元素没有特定的位置。
    • 常见实现类:HashSet,LinkedHashSet,TreeSet等。
  • Map(映射):
    • 键-值对:Map是键值对的集合,每个元素都包含一个唯一的键和与之相关联的值。
    • 键的唯一性:Map中的键是唯一的,同一个键不能对应多个值。
    • 通过键访问:可以通过键来访问和操作Map中的值,而不是通过位置。
    • 常见实现类:HashMap,LinkedHashMap,TreeMap,HashTable等。

4.在实际开发过程中如何更好的选择集合 ?

  • 了解需求:首先,明确你的需求。了解你需要存储的数据类型、数据量、访问模式(读多写少、读写均衡、多线程访问等)以及对数据的操作需求(搜索、排序、迭代等)是选择集合的关键。

  • 有序性需求:
    如果你需要维护元素的揺序,可以选择List。
    如果元素的顺序无关紧要,可以选择Set或Map。

  • 元素唯一性需求:
    如果需要确保元素的唯一性,选择Set。
    如果需要建立键到值的映射关系,选择Map。

  • 数据量和性能:
    对于小数据量和不需要高性能的场景,通常选择任何一种集合都可以。
    对于大数据集,需要根据性能需求选择合适的数据结构,例如使用HashSet而不是ArrayList来避免重复数据的存储。
    如果需要高性能的并发访问,可以考虑使用Concurrent集合(如ConcurrentHashMap)。

  • 操作需求:
    如果需要频繁地进行插入和删除操作,考虑使用LinkedList或LinkedHashSet,因为它们在这些操作上更高效。
    如果需要快速的随机访问元素,使用ArrayList或HashMap。

  • 线程安全性:
    如果在多线程环境下访问集合,确保选择线程安全的集合类或考虑在操作上加锁以避免竞态条件。

  • 内存占用:
    考虑集合的内存占用,选择合适的数据结构以最小化内存使用。

  • 对比不同集合实现:
    Java提供了多种集合实现,例如ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等。仔细对比它们的性能和特性,选择最适合你需求的实现类。
    使用泛型:尽量使用泛型来指定集合中存储的元素类型,以增强类型安全性。

  • 考虑第三方库:有时候,第三方库中可能有更适合特定需求的集合实现,可以考虑使用这些库。

5. ArrayList和Vector区别 ?

  1. 扩容方式:
    1. ArrayList在原有容量基础上扩容0.5倍;
    2. Vector在原有容量基础上,扩容1倍;
  2. 线程安全:
    1. ArrayList是线程不安全的;
    2. Vector是线程安全的;
  3. 执行效率:
    1.Vector的方法都是由同步锁的,在方法执行期间需要加锁,解锁,所以性能会低于ArrayList。

6. ArrayList和LinkedList之间的区别是什么?

  1. 底层数据结构:ArrayList底层使用的是Object数组,LinkedList底层使用的是双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环);
  2. 插入和删除元素: ArrayList采用数组存储,插入删除时需要移动元素,所以性能较差,LinkedList采用链表存储,性能比较高;
    • 往集合中间插入数据时ArrayList比linkedList慢
    • ArrayList正好扩容的时候添加数据要比LinkedList慢
    • ArrayList要比LinkedList慢,原理同往集合中间插入数据一样,ArrayList每次删除数据都要对数组重组;
  3. 查询数据:
    • ArrayList比LinkedList快;ArrayList是数组有下标标记数据位置的,查询时世界返回对应数组下表数据即可
  4. 数据存储:数组需要一块连续的内存,链表需要的内存不需要连续。

7.HashSet和TreeSet的区别是什么?

  • 底层数据结构:HashSet使用哈希表作为底层数据结构,而TreeSet使用红黑树作为底层数据结构。

  • 元素的排序方式:HashSet中的元素是无序的,而TreeSet中的元素是有序的,且默认按照元素的自然顺序排序。如果需要按照其他方式排序,则需要在创建TreeSet时指定一个Comparator对象。

  • 元素的唯一性:HashSet中的元素是唯一的,不允许重复,而TreeSet中的元素也是唯一的,但是它是通过比较器或元素的自然顺序来判断元素是否相同的。

  • 性能:HashSet的插入、删除和查找操作的时间复杂度都是O(1),而TreeSet的这些操作的时间复杂度都是O(log n)。

因此,如果需要快速的插入、删除和查找操作,并且不需要元素有序,则可以选择HashSet。如果需要元素有序,或者需要按照其他方式进行排序,则可以选择TreeSet。

8. HashMap和Hashtable之间的区别是什么?

  • 线程安全性:
    HashMap:HashMap 不是线程安全的。多个线程可以同时访问和修改一个 HashMap 实例,这可能导致并发问题,需要额外的同步措施来确保线程安全。
    Hashtable:Hashtable 是线程安全的。它的方法是同步的,因此多个线程可以安全地访问和修改一个 Hashtable 实例。然而,这种同步可能会导致性能下降,因此在不需要线程安全性的情况下,推荐使用 HashMap。
  • null 键和值:
    HashMap:HashMap 允许键和值都为 null。
    Hashtable:Hashtable 不允许键或值为 null。如果尝试将 null 放入 Hashtable,将引发 NullPointerException。
  • 遍历方式:
    HashMap:HashMap 不保证元素的顺序,遍历的顺序不一定与元素插入的顺序一致。
    Hashtable:Hashtable 不保证元素的顺序,遍历的顺序也不一定与元素插入的顺序一致。
  • 继承关系:
    HashMap:HashMap 继承自 AbstractMap 类,实现了 Map 接口。
    Hashtable:Hashtable 继承自 Dictionary 类,实现了 Map 接口的旧版本,不建议在新代码中使用。

9.什么是迭代器(Iterator)?它的作用是什么?

迭代器是一种用于遍历集合元素的对象,它提供了一种统一的方式来访问集合中的元素,而不需要了解集合的内部结构。

10.如何在Java中创建不可变集合?

使用Collections.unmodifiableXXX方法(如unmodifiableList、unmodifiableSet)可以创建不可变集合。

11.如何遍历一个Map?

  • 使用for循环遍历map;
  • 使用迭代器遍历map;
  • 使用keySet迭代遍历map;
  • 使用entrySet遍历map。

12.CopyOnWriteArrayList是什么 ?

13.List的遍历例方式该如何选择?

14.ArrayList的扩容机制?

ArrayList 是一个数组结构的存储容器,默认情况下,设置数组长度是 10. 当然我们也可以在构建 ArrayList 对象的时候自己指定初始长度。 随着在程序里面不断的往 ArrayList 中添加数据,当添加的数据达到 10 个的时候, ArrayList 就没有多余容量可以存储后续的数据。 这个时候 ArrayList 会自动触发扩容。 扩容的具体流程很简单:

  1. 首先,创建一个新的数组,这个新数组的长度是原来数组长度的 1.5 倍。
  2. 然后使用 Arrays.copyOf 方法把老数组里面的数据拷贝到新的数组里面。 扩容完成后再把当前要添加的元素加入到新的数组里面,从而完成动态扩容的过程。

扩容时机:扩容,当添加元素时,如果元素个数+1> 当前数组长度 【size + 1 > elementData.length】时

15.CopyOnWriteArrayList有啥优缺点 ?

  1. 内存占用:如果 CopyOnWriteArrayList经常要增删改集合中的数据,执行add(),set(),remove()方法,每次都需要复制一个新数组,比较耗费内存;

  2. 数据一致性:CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性,因为增删改操作的是新数组,读取操作的是原数组。

  • 缺点:

内存开销:

CopyOnWriteArrayList 的核心特性是在写操作时复制整个底层数组,这意味着写操作会创建一个新的数组副本。这会导致大量的内存开销,尤其在列表很大的情况下。
如果列表频繁被写入,可能会导致大量的内存分配和垃圾回收开销。
写操作延迟:

由于写操作会涉及复制整个底层数组,因此写操作的时间复杂度是O(n),其中n是列表的大小。这意味着写操作可能会相对较慢,特别是在列表很大的情况下。
写操作的延迟可能会对某些实时性要求高的应用程序造成问题。

  • 优点:
    线程安全性:CopyOnWriteArrayList 提供了线程安全性。它的设计允许多个线程同时读取列表,而不需要额外的同步机制。这使得它非常适用于读多写少的场景。

避免并发修改异常:由于 CopyOnWriteArrayList 的写操作会复制底层数组,因此写操作不会影响正在进行的读操作,也不会导致并发修改异常(ConcurrentModificationException)。

一致性迭代:当你对 CopyOnWriteArrayList 进行迭代时,迭代器访问的是迭代器创建时的快照,而不会受到其他线程的修改影响。这确保了迭代的一致性,即迭代器不会抛出并发修改异常或返回不一致的数据。

简化代码:由于 CopyOnWriteArrayList 具有内置的线程安全性,你无需编写额外的同步代码,这可以简化代码并降低编程难度。

可预测的性能:在写操作时,CopyOnWriteArrayList 会复制整个底层数组,这可能会导致写操作的性能较差。然而,在读多写少的情况下,写操作的开销是可控的,而读操作的性能较高。这使得 CopyOnWriteArrayList 在特定的使用场景中表现良好。

适用于不经常变化的数据集:如果数据集很少发生变化,主要用于读取操作,CopyOnWriteArrayList 可以提供一致的、快速的读取性能。

  • 适用场景:

尽管 CopyOnWriteArrayList 有一些缺点,但它在特定的使用场景中仍然非常有用:

读多写少:

当列表的读操作比写操作频繁得多时,CopyOnWriteArrayList 可以提供高效的线程安全性,因为读操作不会受到写操作的阻塞。
数据不经常变化:

当列表的数据集不经常变化,而且主要用于读取操作时,CopyOnWriteArrayList 可以提供一致的快速读取性能。
不要求实时性:

如果应用程序对写入操作的实时性要求不高,可以容忍写操作的延迟,那么 CopyOnWriteArrayList 可能是一个合适的选择。
避免显式的同步:

如果你希望避免使用显式的同步机制(如锁),而又需要线程安全的列表,CopyOnWriteArrayList 可以提供一种简单的替代方案。
需要注意的是,不是所有的场景都适合使用 CopyOnWriteArrayList。如果列表的写操作频繁且对实时性要求高,或者列表的大小非常大,可能需要考虑其他线程安全的数据结构,例如 ConcurrentHashMap 或自定义的锁机制。因此,在选择数据结构时,应根据具体的需求和性能要求来权衡使用 CopyOnWriteArrayList 的利弊。

16.CopyOnWriteArrayList的实现原理是什么 ?

  1. CopyOnWriteArrayList的所有修改操作的底层原理都是通过创建数组的新副本来实现。
  2. 当CopyOnWriteArrayList需要被修改的时候,并不修改原有内容,而是对原有数据进行一次性复制,将修改的内容写入新的副本中,然后再将修改

17.CopyOnWriteArrayList为什么并发安全且性能比Vector好 ?

  1. Vector是增删改查方法都加了synchronized,保证同步,但是每个方法执行的时候都要去获取锁,性能就会大大降低;
  2. 而CopyOnWriteArrayList 只是在增删改上加锁,但是读不加锁,在读方面的性能就好于Vector,CopyOnWriteArrayList支持读多写少的并发情况。读写分离,写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array。

18.HashSet是如何检查重复的 ?

1.当对象加入HashSet时,HashSet会先计算对象的hashCode值来判断对象将要添加的位置,如果该位置没有其他元素,则代表不重复;
2.如果该位置存在其他元素,会比较该位置链表内的其他元素的hashCode值,如果没有相同的hashCode,代表不重复;
3.如果发现有相同的hashCode,接下来会调用equals()方法来检查这两个元素是否相同,如果equals()比较的结果是true,代表重复,否则代表不重复。

19.ConcurrentHashMap特点和底层原理?

参考:HashMap、HashTable、CurrentHashMap对比

20.如何将数组转换为List?

使用Arrays.asList(T… a)方法可以将数组转换为List。

21.HashSet和LinkedHashSet内部有什么区别?

22.如何在集合中查找元素是否存在?

使用contains(Object obj)方法可以检查集合中是否包含指定的元素。

23.线程安全的集合有哪些?他们的底层实现?

线程安全的集合有Vector、HashTable、Stack、ArrayBlockingQueue、ConcurrentHashMap、ConcurrentLinkedQueue等。

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

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

相关文章

[HD2006.X1] 打印图形(菱形换壳)——海淀区赛

题目描述 由键盘输入 N N N ,按一定的规律打印图形(见输出样例)。 输入格式 一个整数 N N N(其中 3 ≤ N ≤ 21 3≤N≤21 3≤N≤21 ), N N N 为奇数。 输出格式 如题中所描述的图形 样例 #1 样例…

Java之线程的详细解析二

2.线程同步 2.1卖票【应用】 案例需求 某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票 实现步骤 定义一个类SellTicket实现Runnable接口,里面定义一个成员变量:privat…

MySQL架构 InnoDB存储引擎

1. 什么是Mysql? 我们在开发的时候,我们都需要对业务数据进行存储,这个时候,你们就会用到MySQL、Oracal等数据库。 MySQL它是一个关系型数据库,这种关系型数据库就有Oracal、 MySQL,以及最近很火的PgSQL等。…

9月24日回顾

1.微程序控制器的组成:指令译码器、微地址寄存器(输出和暂存控制信息),时序电路、最核心的部件是控制存储器(只读ROM组成)—用来存储微指令 2.突发读写:比如说突发地址为8,那么只需…

Docker-Windows安装使用

1.下载docker https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 2.配置虚拟化环境 通过控制面板“设置”启用 Hyper-V 角色 右键单击 Windows 按钮并选择“应用和功能”。选择相关设置下右侧的“程序和功能”。选择“打开或关闭 Windows 功能”。选择“Hyper-…

ubuntu安装freeswitch 1.10.10

1、安装ffmpeg4.2 1.1、安装依赖库 sudo apt install yasm libogg-dev pkg-config libopus-dev libvpx-dev libx264-dev libx265-dev libfdk-aac-dev libsdl2-dev libfdk-aac-dev libmp3lame-dev libopencore-amrwb-dev libopencore-amrnb-dev libvorbis-dev libxvidcore-dev…

ElementUI -- Mock.js介绍和使用与首页导航栏左侧菜单搭建

1.1 mockjs介绍 Mock.js是一个用于生成随机数据和模拟接口请求的JavaScript库。它可以帮助开发人员在前端开发过程中模拟后端接口的返回数据,以便进行前端页面的开发和测试。 Mock.js有两个重要的特性风靡前端: 数据类型丰富 Mock.js提供了一套简单易用的API&#x…

查找排序部分习题 242. 有效的字母异位词 74. 搜索二维矩阵 1. 两数之和 167.两数之和 II

242. 有效的字母异位词 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。 class Solution(object):def isAnagram(self, s, t):""…

cocos creator项目构建问题

1.Build Failed: Compile error : Maximum call stack size exceeded 遇到这种问题首先要确认,一定要确认 自己的代码是否存在问题。 因为我出现这个问题就是由于代码中出现问题。 某个js文件是用于当做配置或者文本配置的时候就需要注意了,不能在旧变…

双指针算法——移动零

双指针算法——移动零😎 前言🙌题目详情:图解分析:代码分享:B站讲解视频链接: 总结撒花💞 😎博客昵称:博客小梦 😊最喜欢的座右铭:全神贯注的上吧…

红队打靶:THE PLANETS: MERCURY打靶思路详解(vulnhub)

目录 写在开头 第一步:主机发现和端口扫描 第二步:Web渗透 第三步:获取初步立足点并搜集信息 第四步:软连接劫持sudo提权 总结与思考 写在开头 本篇博客在自己的理解之上根据大佬红队笔记的视频进行打靶,详述了…

基于SSM的教师办公管理的设计与实现(有报告)。Javaee项目。

演示视频: 基于SSM的教师办公管理的设计与实现(有报告)。Javaee项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过Spring S…

你的游戏项目有这些问题吗?

在移动游戏对高品质画面的要求不断增加的背景下,我们一直专注于移动设备GPU性能的优化,以确保您的游戏体验得以最佳展现。然而,不同GPU芯片之间的性能差异以及由此可能引发的GPU瓶颈问题使得优化工作更加具有挑战性。 因此,在不久…

git报错:Failed to connect to 127.0.0.1 port 1080

Bug描述 由于在试了网上的这条命令 git config --global http.proxy socks5 127.0.0.1:1080 git config --global https.proxy socks5 127.0.0.1:1080git config --global http.proxy 127.0.0.1:1080 git config --global https.proxy 127.0.0.1:1080Bug描述:Faile…

Three.js加载360全景图片/视频

Three.js加载360全景图片/视频 效果 原理 将全景图片/视频作为texture引入到three.js场景中将贴图与球形网格模型融合,将球模型当做成环境容器使用处理视频时需要以dom为载体,加载与控制视频动作每次渲染时更新当前texture,以达到视频播放效…

基于arduino的土壤湿度检测

1.总体设计框图 本浇花系统总体上分为硬件和软件两大组成部分。硬件部分包括Arduino UNO开发板、温湿度传感器、通信模块、浇水执行系统和液晶显示等。软件部分包括Android客户端。系统结构如图1所示 本浇花系统总体上分为硬件和软件两大组成部分。硬件部分包括Arduino UN…

如何做好测试?(二)单元测试(Unit Testing, UT)

1. 单元测试的介绍: 单元测试单元测试(Unit Testing, UT),是软件测试的一种测试方法,旨在验证软件系统中的最小可测试单元(通常是函数、方法或类)的功能是否正确。它将软件系统拆分为各个独立的单元,并对每…

Node.js安装教程【附安装包资源】

文章目录 安装包下载安装流程配置环境变量检查Node.js是否安装成功指定全局模块和模块缓存的路径设置淘宝镜像全局安装cnpm(这一步可以选择是否执行) 安装包下载 安装包下载 安装流程 修改安装路径 配置环境变量 看看环境变量里面是否有Node.js的…

手把手带你体验一场属于Linux的学习之旅

手把手带你体验一场属于Linux的学习之旅 Linux是一个开源的操作系统,以性能高和稳定著称因为继承unix,在权限和网络上的设计与表现也非常优异。同时其系统开源/免费/优秀/稳定,自由高可定制,深受程序员们等代表的极客们的喜爱&…

Python入门教程48:Pycharm永久镜像源的pip配置方法

国内几个好用的Python镜像服务器地址: 清华大学镜像站:https://pypi.tuna.tsinghua.edu.cn/simple/阿里云镜像站:https://mirrors.aliyun.com/pypi/simple/中科大镜像站:https://pypi.mirrors.ustc.edu.cn/simple/中国科技大学镜…