Java最全面试题专题---2、Java集合容器(1)

集合容器概述

什么是集合

**集合框架:**用于存储数据的容器。
集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。

**接口:**表示集合的抽象数据类型。接口允许我们操作集合时不必关注具体实现,从而达到“多态”。在面向对象编程语言中,接口通常用来形成规范。

**实现:**集合接口的具体实现,是重用性很高的数据结构。

**算法:**在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算的方法,例如查找、排序等。这些算法通常是多态的,因为相同的方法可以在同一个接口被多个类实现时有不同的表现。事实上,算法是可复用的函数。它减少了程序设计的辛劳。
集合框架通过提供有用的数据结构和算法使你能集中注意力于你的程序的重要部分上,而不是为了让程序能正常运转而将注意力于低层设计上。

通过这些在无关API之间的简易的互用性,使你免除了为改编对象或转换代码以便联合这些API而去写大量的代码。 它提高了程序速度和质量。

集合的特点

集合的特点主要有如下两点:

  • 对象封装数据,对象多了也需要存储。集合用于存储对象。
  • 对象的个数确定可以使用数组,对象的个数不确定的可以用集合。因 为集合是可变长度的。

集合和数组的区别

  • 数组是固定长度的;集合可变长度的。
  • 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存 储引用数据类型。
  • 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同 数据类型。

**数据结构:**就是容器中存储数据的方式。
对于集合容器,有很多种。因为每一个容器的自身特点不同,其实原理在于每个容器的内部数据结构不同。
集合容器在不断向上抽取过程中,出现了集合体系。在使用一个体系的原则:参阅顶层内容。建立底层对象。

使用集合框架的好处

  • 容量自增长;
  • 提供了高性能的数据结构和算法,使编码更轻松,提高了程序速度和质
    量;
  • 允许不同 API 之间的互操作,API之间可以来回传递集合;
  • 可以方便地扩展或改写集合,提高代码复用性和可操作性。
  • 通过使用JDK自带的集合类,可以降低代码维护和学习新API成本。

常用的集合类有哪些?

Map接口和Collection接口是所有集合框架的父接口:

  • Collection接口的子接口包括:Set接口和List接口
  • Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等
  • Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
  • List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等

List,Set,Map三者的区别?List、Set、Map 是否继承自 Collection 接口?List、Map、Set 三个接口存取元素时,各有什么特点?

在这里插入图片描述
Java 容器分为 Collection 和 Map 两大类,Collection集合的子接口有Set、List、Queue三种子接口。我们比较常用的是Set、List,Map接口不是collection的子接口。
Collection集合主要有List和Set两大接口

  • List:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重 复,可以插入多个null元素,元素都有索引。常用的实现类有ArrayList、LinkedList 和 Vector。

  • Set:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。

Map是一个键值对集合,存储键、值和之间的映射。 Key无序,唯一;value 不要求有序,允许重复。Map没有继承于Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
Map 的常用实现类:HashMap、TreeMap、HashTable、LinkedHashMap、ConcurrentHashMap

集合框架底层数据结构

Collection

  1. List
  • Arraylist: Object数组
  • Vector: Object数组
  • LinkedList: 双向循环链表
  1. Set
    HashSet(无序,唯一):基于 HashMap 实现的,底层采用 HashMap 来保
    存元素
  • LinkedHashSet: LinkedHashSet 继承与 HashSet,并且其内部是通过LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 Hashmap 实现一样,不过还是有一点点区别的。
  • TreeSet(有序,唯一): 红黑树(自平衡的排序二叉树。)
    Map
  • HashMap: JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突).JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间
  • LinkedHashMap:LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
  • HashTable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
  • TreeMap: 红黑树(自平衡的排序二叉树)

哪些集合类是线程安全的?

  • vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
  • statck:堆栈类,先进后出。
  • hashtable:就比hashmap多了个线程安全。
  • enumeration:枚举,相当于迭代器。

Java集合的快速失败机制 “fail-fast”?

是java集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。
例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出ConcurrentModificationException 异常,从而产生fail-fast机制。
原因:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出
异常,终止遍历。

解决办法:

  1. 在遍历过程中,所有涉及到改变modCount值得地方全部加上
    synchronized。
  2. 使用CopyOnWriteArrayList来替换ArrayLis

怎么确保一个集合不能被修改?

可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang.UnsupportedOperationException 异常。
示例代码如下:

1 List<String> list = new ArrayList<>();
2 list. add("x");
3 Collection<String> clist = Collections. unmodifiableCollection(list);
4 clist. add("y"); // 运行时此行报错
5 System. out. println(list. size());

Collection接口

List接口

迭代器 Iterator 是什么?

Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的Enumeration,迭代器允许调用者在迭代过程中移除元素。

Iterator 怎么使用?有什么特点?

Iterator 使用代码如下:

1 List<String> list = new ArrayList<>();
2 Iterator<String> it = list. iterator();
3 while(it. hasNext()){
4 String obj = it. next();
5 System. out. println(obj);
6 }

Iterator 的特点是只能单向遍历,但是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。

如何边遍历边移除Collection 中的元素?

边遍历边修改 Collection 的唯一正确方式是使用 Iterator.remove() 方法,如下:

1 Iterator<Integer> it = list.iterator();
2 while(it.hasNext()){
3 *// do something*
4 it.remove();
5 }

一种最常见的错误代码如下:

1 for(Integer i : list){
2 list.remove(i)
3 }

运行以上错误代码会报 ConcurrentModificationException 异常。这是因为当使用 foreach(for(Integer i : list)) 语句时,会自动生成一个iterator 来遍历该list,但同时该 list 正在被 Iterator.remove() 修改。Java 一般不允许一个线程在遍历 Collection 时另一个线程修改它。

Iterator 和 ListIterator 有什么区别?

  • Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
  • Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
  • ListIterator 实现 Iterator 接口,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?Java 中 List 遍历的最佳实践是什么?

遍历方式有以下几种:

  1. for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。
  2. 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。
  3. foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。

最佳实践:Java Collections 框架中提供了一个 RandomAccess 接口,用来标记 List 实现是否支持 Random Access。

  • 如果一个数据集合实现了该接口,就意味着它支持 Random Access,按位置读 取元素的平均时间复杂度为O(1),如ArrayList。
  • 如果没有实现该接口,表示不支持 Random Access,如LinkedList。

推荐的做法就是,支持 Random Access 的列表可用 for 循环遍历,否则建议用 Iterator 或 foreach 遍历。

说一下 ArrayList 的优缺点

ArrayList的优点如下:

  • ArrayList 底层以数组实现,是一种随机访问模式。ArrayList 实现了 RandomAccess 接口,因此查找的时候非常快。
  • ArrayList 在顺序添加一个元素的时候非常方便。 ArrayList 的缺点如下:
  • 删除元素的时候,需要做一次元素复制操作。如果要复制的元素很多,那么就会 比较耗费性能。
  • 插入元素的时候,也需要做一次元素复制操作,缺点同上。 ArrayList 比较适合顺序添加、随机访问的场景。

如何实现数组和 List 之间的转换?

  • 数组转 List:使用 Arrays. asList(array) 进行转换。
  • List 转数组:使用 List 自带的 toArray() 方法。
    代码示例:
1 // list to array
2 List<String> list = new ArrayList<String>();
3 list.add("123");
4 list.add("456");
5 list.toArray();
6
7 // array to list
8 String[] array = new String[]{"123","456"};
9 Arrays.asList(array);

ArrayList 和 LinkedList 的区别是什么?

  • 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。
  • 随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
  • 增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。
  • 内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
  • 线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;

综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。

补充:数据结构基础之双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

ArrayList 和 Vector 的区别是什么?

这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合

  • 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而ArrayList 是非线程安全的。
  • 性能:ArrayList 在性能方面要优于 Vector。
  • 扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。

Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。
Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。

插入数据时,ArrayList、LinkedList、Vector谁速度较快?阐述 ArrayList、Vector、LinkedList 的存储性能和特性?

ArrayList、LinkedList、Vector 底层的实现都是使用数组方式存储数据。数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。

Vector 中的方法由于加了 synchronized 修饰,因此 Vector是线程安全容器,但性能上较ArrayList差。

LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但插入数据时只需要记录当前项的前后项即可,所以 LinkedList插入速度较快。

多线程场景下如何使用ArrayList?

ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的synchronizedList 方法将其转换成线程安全的容器后再使用。例如像下面这样:

1 List<String> synchronizedList = Collections.synchronizedList(list);
2 synchronizedList.add("aaa");
3 synchronizedList.add("bbb");
4
5 for (int i = 0; i < synchronizedList.size(); i++) {
6 System.out.println(synchronizedList.get(i));
7 }

为什么 ArrayList 的elementData 加上 transient 修饰?

ArrayList 中的数组定义如下:

1 private transient Object[] elementData;

可以看到 ArrayList 实现了 Serializable 接口,这意味着 ArrayList 支持序列化。transient 的作用是说不希望 elementData 数组被序列化,重写了writeObject 实现:

1 private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOE
xception{
2 *// Write out element count, and any hidden stuff*
3 int expectedModCount = modCount;
4 s.defaultWriteObject();
5 *// Write out array length*
6 s.writeInt(elementData.length);
7 *// Write out all elements in the proper order.*
8 for (int i=0; i<size; i++)
9 s.writeObject(elementData[i]);
10 if (modCount != expectedModCount) {
11 throw new ConcurrentModificationException();
12 }

每次序列化时,先调用 defaultWriteObject() 方法序列化 ArrayList 中的非transient 元素,然后遍历 elementData,只序列化已存入的元素,这样既加快了序列化的速度,又减小了序列化之后的文件大小。

List 和 Set 的区别

List , Set 都是继承自Collection 接口
List 特点:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。
Set 特点:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是HashSet、LinkedHashSet 以及 TreeSet。
另外 List 支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。
Set和List对比
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文件扩展名修改:txt文本如何批量修改为word文档格式,高效修改一步到位

在日常工作中&#xff0c;经常要处理各种类型的文本文件&#xff0c;其中txt文件和Word文档是最为常见的两种格式。有时候&#xff0c;要将大量的txt文件修改为Word文档格式&#xff0c;以便在Microsoft Word中打开、编辑和排版。虽然可以手动将txt文件重命名为.docx格式&#…

InsCode实践分享:如何实现自动化代码审查和质量控制?

文章目录 文章目录 概要 整体架构流程 InsCode的解释 技术展示 小结 概要 InsCode是一款面向中小型企业的代码审查和自动化质量控制工具。本文将分享如何使用InsCode来实现自动化代码审查和质量控制&#xff0c;帮助企业在代码开发和维护过程中降低风险&#xff0c;提高效率和…

Volatility3内存取证工具安装及入门在Linux下的安装教程

1-1. Volatility3简介 Volatility 是一个完全开源的工具&#xff0c;用于从内存 (RAM) 样本中提取数字工件。支持Windows&#xff0c;Linux&#xff0c;MaC&#xff0c;Android等多类型操作系统系统的内存取证。 针对竞赛这块&#xff08;CTF、技能大赛等&#xff09;基本上都…

PP和PVC可以相互粘接吗?

PP&#xff08;聚丙烯&#xff09;和PVC&#xff08;聚氯乙烯&#xff09;是两种不同类型的塑料&#xff0c;它们的化学性质和表面特性不同&#xff0c;因此直接的粘接会比较困难。这是因为它们的分子结构和化学成分不太相容&#xff0c;不易产生牢固的粘接。通常情况&#xff…

使用NVM切换不同版本的node

什么情况会切换不同版本 今天在拉取一个项目之后需要安装一下依赖&#xff0c;然后就出现了下边的问题&#xff1a; 可以看出我目前node是18.18.0&#xff0c;该项目需要8 || 10 || 12 || 14 || 16 || 17&#xff0c;那我总不能去把node卸载再重新下个版本&#xff0c;那么现…

查询优化与事务处理——触发器、事务、锁

一、认识触发器&#xff1a; 触发器是在对表进行插入&#xff0e;更新或删除操作时自动执行的存储过程。触发器通常用于强制业务规则&#xff0c;是--种高级约束&#xff0e;可以定义比用CHECK约束更为复杂的约束&#xff0c;可执行复杂的SQL语句〈如F/WHLE/CASE)&#xff0c;…

OpenHarmony创新赛人气投票活动,最佳人气作品由你来定!

12月1日至12月15日 十大入围作品线上投票激战正酣 最佳人气作品&#xff0c;由你来定&#xff01; 投票链接&#xff1a;OpenHarmony创新赛人气作品投票正式开启——最佳人气作品&#xff0c;由你来定&#xff01; - 文章 OpenHarmony开发者论坛

C语言leetcode集训二:字符串(1):字符串遍历

今天集训的内容是字符串中的字符串遍历题&#xff0c;仍然是简单题&#xff0c;但也可以掌握一些字符串所必要的知识&#xff0c;加深对字符串的理解&#xff0c;关于字符数组和字符串&#xff0c;字符串的输入输出在这就不再做过多赘述&#xff0c;关于字符串的问题&#xff0…

《IT圈里的“鄙视链”:看不起谁又被谁看不起?》

文章目录 每日一句正能量前言一、编程语言篇二、工具篇三、操作系统篇四、硬件篇五、职场篇后记 每日一句正能量 人的结构就是相互支撑&#xff0c;众人的事业需要每个人的参与。 前言 每个领域都存在着错综复杂的鄙视链,这一点在IT 领域更为突出。从编程语言、工具&#xff0…

简单的 u-popup 弹出框

uniapp中的popup组件可以用于弹出简单的提示框、操作框、菜单等。它可以通过position属性控制弹出框的位置&#xff0c;不同的position值会使得弹出框呈现不同的弹出形式 目录 一、实现思路 二、实现步骤 ①view部分展示 ②JavaScript 内容 ③css中样式展示 三、效果展示 …

C++连接mysql(改进)

使用vs2019对window11中的数据库进行连接 1. 配置连接环境 首先需要把mysql中的头文件和库文件放入到c项目工程中 1.打开安装MySQL的目录&#xff0c;在windows系统中如果是默认路径&#xff0c;应该和我的是一样的&#xff1a;C:\Program Files\MySQL\MySQL Server 8.0 2.找到…

某音上很火的圣诞树分享

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 效果截图&#xff08;这里不给动态了&#xff0c;某音到处都是了&#xff09;&#xff1a; 源代码&#xff1a; <script src"…

LeetCode-1008. 前序遍历构造二叉搜索树【栈 树 二叉搜索树 数组 二叉树 单调栈】

LeetCode-1008. 前序遍历构造二叉搜索树【栈 树 二叉搜索树 数组 二叉树 单调栈】 题目描述&#xff1a;解题思路一&#xff1a;题目大致意思就是给定一个二叉树的前序遍历&#xff0c;求对应的二叉搜索树。一种比较特殊的点是「二叉搜索树」的中序遍历的结果是【有序序列】&am…

智慧水利-城市水循环可视化助力城市水资源可持续发展

2021年《中华人民共和国国民经济和社会发展第十四个五年规划和2035年远景目标纲要》明确指出&#xff1a;构建智慧水利体系&#xff0c;以流域为单元提升水情测报和智能调度能力。水利部按照“需求牵引、应用至上、数字赋能、提升能力”总要求&#xff0c;编制了《“十四五”智…

深入理解强化学习——马尔可夫决策过程:预测与控制

分类目录&#xff1a;《深入理解强化学习》总目录 预测&#xff08;Prediction&#xff09;和控制&#xff08;Control&#xff09;是马尔可夫决策过程里面的核心问题。预测&#xff08;评估一个给定的策略&#xff09;的输入是马尔可夫决策过程 < S , A , R , P , γ > …

中职网络安全应急响应—Server2228

应急响应 任务环境说明: 服务器场景:Server2228(开放链接) 用户名:root,密码:p@ssw0rd123 1. 找出被黑客修改的系统别名,并将倒数第二个别名作为Flag值提交; 通过用户名和密码登录系统 在 Linux 中,利用 “alias” 命令去查看当前系统中定义的所有别名 flag:ss …

LeetCode:1631. 最小体力消耗路径(SPFA Java)

目录 1631. 最小体力消耗路径 题目描述&#xff1a; 实现代码与解析&#xff1a; BFSDP 原理思路&#xff1a; 1631. 最小体力消耗路径 题目描述&#xff1a; 你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights &#xff0c;其中 heights[row][col] 表…

python 爬虫 m3u8 视频文件 加密解密 整合mp4

文章目录 一、完整代码二、视频分析1. 认识m3u8文件2. 获取密钥&#xff0c;构建解密器3. 下载ts文件4. 合并ts文件为mp4 三、总结 一、完整代码 完整代码如下&#xff1a; import requests import re import os from tqdm import tqdm from Crypto.Cipher import AES# 创建临…

通过Jmeter压测存储过程

一、存储过程准备&#xff1a; 1、建立一个空表&#xff1a; 1 CREATE TABLE test_data ( id NUMBER, name VARCHAR2(50), age NUMBER ); 2、建立一个存储过程&#xff1a; CREATE OR REPLACE PROCEDURE insert_test_data(n IN NUMBER) ASBEGIN--EXECUTE IMMEDIATE trunca…

打工人副业变现秘籍,某多/某手变现底层引擎-Stable Diffusion 黑白老照片上色修复

在这个时代,我们习惯于拥有高清、色彩丰富的照片,然而,那些古老的黑白色老照片由于年代的久远,往往会出现模糊、破损等现象。 那么今天要给大家介绍的是,用 Stable Diffusion 来修复老照片。 前段时间 ControlNet 的除了上线了“IP-Adapter”模型以外还增加另一个…