ArrayList知识点(面试)

        上一篇我们说了hashmap的相关知识点,这一篇我们再说一些ArrayList的相关知识,因为ArrayList也是我们项目中比较常用的。

ArrayList(底层是数组)

底层工作原理
  • 首先,在构造ArrayList的时候会先看有没有指定容量,如果没有,则会先构造一个空数组,如果有,则会根据指定容量创建数组。

  • 在插入数据的时候,会先判断当前数组是否有足够的空间插入新数据,如果没有则会按照1.5倍的扩容标准进行扩容,同时如果容量足够,或再判断插入的位置有没有越界,以及该位置是否有元素

  • 在获取元素的时候同样也是先判断当前下标是否有越界,没有才能从数组中获取元素。

扩容机制
  1. 首先,ArrayList初始化的长度为10,如果插入的数据长度超过10则会自动触发扩容机制

  2. ArrayList会创建一个比原来数组长1.5倍的新数组,然后通过Arrays.copyof方法将原来的数组copy到新数组中

  3. 最后将新元素插入到新数组中

线程不安全是怎么解决的

先看一段代码

 @Test
     void testArrayList() {
         List<Integer> list = new ArrayList<>(12);
         list.add(1);
         list.add(2);
         list.add(3);
         System.out.println(list);
 //        遍历元素
         Thread t1 = new Thread(() -> {
             for (Integer integer : list) {
                 System.out.println(integer);
             }
         });
 //              新增元素
         Thread t2 = new Thread(() -> {
             for (int i = 4; i < 8; i++) {
                 list.add(i);
             }
         });
         t1.start();
         t2.start();
     }

以上代码运行后结果如下:

ArrayList在遍历的时候会去调用Collection中的next方法,然后通过checkForComodification()方法检查modCount和expectedModeCount是否相等,若不等则抛出ConcurrentModificationException,在上面的代码中我们对于list在遍历的同时也在增加数组中对的元素,modCount和expectedModeCount肯定不相等啦,所以就报错了。

modCount表示集合被修改的次数,每修改一次次数加1,而expectedModeCount是迭代器的属性,在迭代器创建时被赋予和modCount一样的值

其实在这里也是用到了fail-fast(快速失效)系统,这里简单说明一下这个是什么

fail-fast和fail-safe是什么意思?

fail-fast简单通俗的来讲就是在做系统设计的时候考虑异常情况,如果有异常情况,则抛出异常并且不会执行后面的代码

 public int divide(int dividend,int divisor){
     if(divisor == 0){
         throw new RuntimeException("divisor can't be zero");
     }
     return dividend/divisor;
 }

        以上的代码中,如果divisor为0,我们就会抛出一个异常并终止程序继续运行下面的代码,这样做的好处是一方面可以停止运行复杂的代码,另一方面,可以将一些异常单独进行处理。

        fail-safe就是为了避免触发fail-fast机制引发出来的异常,用java中一些带有fail-safe机制的集合类来控制。

        这样的集容器在遍历的时候会先拷贝一份出来而不是直接在原集合上进行操作,java.util.concurrent下的包都是fail-safe机制的,可以在多线程下进行并发修改(remove/add),就比如下面要说到的CopyOnWriteArrayList也是这种机制

        但是,通过这样的方式虽然是可以防止ConcurrentModificationException异常的,但是不能通过迭代器遍历元素,即元素中的元素如果发生改变,迭代器是不知道的,迭代器拿到的只是刚开始集合中的元素。

所以这个时候我们可以对其进行加锁

使用synchronized进行加锁

@Test
     void testArrayList() {
         List<Integer> list = new ArrayList<>(12);
         list.add(1);
         list.add(2);
         list.add(3);
         System.out.println(list);
 //        遍历元素
         Thread t1 = new Thread(() -> {
             synchronized (list){
                 for (Integer integer : list) {
                     System.out.println(integer);
                 }
             }
 ​
         });
 //              新增元素
         Thread t2 = new Thread(() -> {
             synchronized (list) {
                 for (int i = 4; i < 8; i++) {
                     list.add(i);
                 }
             }
         });
         t1.start();
         t2.start();
     }

使用ReentrantLock进行加锁

 @Test
     void testArrayList() {
         List<Integer> list =new ArrayList<>(12);
         list.add(1);
         list.add(2);
         list.add(3);
         System.out.println(list);
         Lock lock=new ReentrantLock();
         // 遍历元素
         Thread t1 = new Thread(() -> {
 //            加锁
             lock.lock();
                 for (Integer integer : list) {
                     System.out.println(integer);
                 }
 //                释放锁
             lock.unlock();
         });
         // 新增元素
         Thread t2 = new Thread(() -> {
 //            加锁
             lock.lock();
             for (int i = 4; i < 8; i++) {
                 list.add(i);
             }
 //            释放锁
             lock.unlock();
         });
         t1.start();
         t2.start();
     }

        或者可以使用Collections.synchronizedxxxx来解决,把创建list的那行代码改成List<Integer> list = Collections.synchronizedList(new ArrayList<>())就行了

或者使用 CopyOnWriteArrayList来实现

  @Test
     void testArrayList() {
         List<Integer> list = new CopyOnWriteArrayList<>();
         list.add(1);
         list.add(2);
         list.add(3);
         System.out.println(list);
         // 遍历元素
         Thread t1 = new Thread(() -> {
             for (Integer integer : list) {
                 System.out.println(integer);
             }
         });
         // 新增元素
         Thread t2 = new Thread(() -> {
             for (int i = 4; i < 8; i++) {
                 list.add(i);
             }
         });
         t1.start();
         t2.start();
     }

这里扩展一下什么是Copy-On-Write?

        简称COW,其基本思路是一开始大家共享一个内容,后来如果有人来修改这个资源,这时就会先copy一份出来(延时懒惰策略),在这份中进行修改,修改完成后再把原来的容器指向这份新的容器。

序列化是怎么解决的

        在序列化中,如果被序列化的类中定义了readObject和writeObject方法,则虚拟机就会尝试去通过用户自定义的这两个方法进行序列化,对于自定义的序列化方法好处是可以在序列化的过程中动态修改序列化的值

        如果类中没有定义,则会用ObjectOutPutStream中默认的DefaultReadStream和DefaultWriteStream方法。

好了,现在再来说一下面试中最常被问到的内容

ArrayList和LinkList有什么区别?
  • 从地址上来说,ArrayList底层是一个数组,因此对于数组这种数据结构的话,它的地址是连续的,而对于LinkList来说,它的底层是一个循环双向链表的结构,地址就不是连续的。

  • 从操作上来讲,ArrayList在查询元素方面快于LinkList,且时间复杂度可以达到O(1),而LinkList的时间复杂度达到了O(n);但是在修改元素和增加元素上来讲,ArrayList时间复杂度达到了O(n),LinkList时间复杂度为O(1).

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

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

相关文章

音视频开发29 FFmpeg 音频编码- 流程以及重要API,该章节使用AAC编码说明

此章节的一些参数&#xff0c;需要先掌握aac的一些基本知识&#xff1a;​​​​​​aac音视频开发13 FFmpeg 音频 --- 常用音频格式AAC&#xff0c;AAC编码器&#xff0c; AAC ADTS格式 。_ffmpeg aac data数据格式-CSDN博客 目的&#xff1a; 从本地⽂件读取PCM数据进⾏AAC格…

FL论文专栏|设备异构、异步联邦

论文&#xff1a;Asynchronous Federated Optimization&#xff08;12th Annual Workshop on Optimization for Machine Learning&#xff09; 链接 实现Server的异步更新。每次Server广播全局Model的时候附带一个时间戳&#xff0c;Client跑完之后上传将时间戳和Model同时带回…

【办公类-50-01】20240620自主游戏观察记录表19周内容打乱

背景需求&#xff1a; 又到了期末&#xff0c;各种班级资料需要提交。 有一份自主游戏观察记录需要写19周&#xff08;每周2次&#xff09;的观察记录&#xff0c;并根据参考书填写一级、三级、五级的评价指标。 去年中六班的时候&#xff0c;我很认真的手写了21周的户外游戏…

基于CST的连续域束缚态(BIC)设计与机制研究

关键词&#xff1a;太赫兹&#xff0c;超表面&#xff0c;连续域束缚态&#xff0c;CST&#xff0c;高Q 束缚态的概念最先出现于量子力学中&#xff0c;当粒子被势场约束在特定的区域内运动&#xff0c;即在无限远处波函数等于零的态叫束缚态&#xff0c;例如势阱中的粒子就处…

Map集合之HashMap细说

最近在看面试题&#xff0c;看到了hashmap相关的知识&#xff0c;面试中问的也挺多的&#xff0c;然后我这里记录下来&#xff0c;供大家学习。 Hashmap为什么线程不安全 jdk 1.7中&#xff0c;在扩容的时候因为使用头插法导致链表需要倒转&#xff0c;从而可能出现循环链表问…

百度ai人脸识别项目C#

一、项目描述 本项目通过集成百度AI人脸识别API&#xff0c;实现了人脸检测和识别功能。用户可以上传图片&#xff0c;系统将自动识别人脸并返回识别结果。 二、开发环境 Visual Studio 2019或更高版本.NET Framework 4.7.2或更高版本AForge.NET库百度AI平台人脸识别API 三、…

Django 模版变量

1&#xff0c;模版变量作用 模板变量使用“{{ 变量名 }}” 来表示模板变量前后可以有空格&#xff0c;模板变量名称&#xff0c;可以由数字&#xff0c;字母&#xff0c;下划线组成&#xff0c;不能包含空格模板变量还支持列表&#xff0c;字典&#xff0c;对象 2&#xff0c;…

一文搞懂Linux信号【下】

目录 &#x1f6a9;引言 &#x1f6a9;阻塞信号 &#x1f6a9;信号保存 &#x1f6a9;信号捕捉 &#x1f6a9;操作信号集 1.信号集操作函数 2.其它操作函数 &#x1f6a9;总结&#xff1a; &#x1f6a9;引言 在观看本博客之前&#xff0c;建议大家先看一文搞懂Linux信…

React hydrateRoot如何实现

React 服务器渲染中&#xff0c;hydrateRoot 是核心&#xff0c;它将服务器段的渲染与客户端的交互绑定在一起&#xff0c;我们知道 React 中 Fiber Tree 是渲染的的核心&#xff0c;那么 React 是怎么实现 hydrateRoot 的呢&#xff1f;首先我们验证一下&#xff0c;hydrateRo…

期货交易豆粕品种详细分析

文章目录 1、豆粕期货标准&#xff08;2024年6月22号数据&#xff09;2、豆粕是什么3、豆粕1、5、9合约区别4、影响豆粕的价格因素1、大豆的供应情况。2、豆粕的季节性3、油粕比&#xff08;豆油和豆粕的价格关系 &#xff09; 5、美国大豆的生产/库存炒作6、豆粕双方&#xff…

uniapp实现路由拦截——遇到问题(三)

uniapp路由拦截开发过程中遇到问题 文章目录 uniapp路由拦截开发过程中遇到问题App 无法退出应用监听返回数据结构解决方式模拟原生物理返回键提示不提示&#xff0c;直接退出应用 微信小程序 登录成功返回页面报错效果图不同平台来源页面数据结构解决方式 App 无法退出应用 安…

2005年上半年软件设计师【上午题】试题及答案

文章目录 2005年上半年软件设计师上午题--试题2005年上半年软件设计师上午题--答案2005年上半年软件设计师上午题–试题

C++/Qt 小知识记录7

工作中遇到的一些小问题&#xff0c;总结的小知识记录&#xff1a;C/Qt 小知识7 编译FFMPEG遇到的问题CMakeLists.txt配置FFMPEG的依赖方式&#xff1a; x264在Windows下编译生成*.libVS编译Qt工程时&#xff0c;遇到提示Change Qt Version的情况在QtOsg的窗口上嵌入子窗口&…

面试官:请你实现三栏布局并且优先加载中间内容 我:稳啦- ̗̀(๑ᵔ⌔ᵔ๑)

前言 三栏布局是网页设计中一种经典布局方式&#xff0c;它将页面分为三个垂直部分&#xff1a;左栏、中栏和右栏&#xff0c;三栏在同一行显示。 这种布局模式在很多网站的首页或内容密集型页面中非常常见&#xff0c;因为它能够有效地组织信息&#xff0c;提供良好的用户体…

【产品应用】一体化步进伺服电机在吊装机器人中的应用

随着工业自动化和智能制造的发展&#xff0c;吊挂式智能巡检机器人逐渐成为许多工业场景中的重要角色。这类机器人不仅能够提升工作效率&#xff0c;减少人工干预&#xff0c;还能在复杂或危险环境中完成巡检任务。在这些机器人的设计与制造中&#xff0c;一体化步进伺服电机扮…

jrebel安装使用教程(2022.4.1版本)

本方法适用于jrebel2022.4.1版本&#xff0c;之后的版本不再适用。 1.下载插件 下载地址 2.安装插件 可以通过idea内部安装 也可以将插件解压进idea的安装目录下的plugins。 3.激活 Team URL中填入 https://jrebel.qekang.com/{guid}这里提供两个guid生成地址&#xf…

Redis学习|Redis基础知识、Redis五大数据类型、Redis三种特殊数据类型、Redis事务

Redis基础知识 redis默认有16个数据库&#xff0c;并且这个数量可以在conf配置文件中更改 默认使用的是第0个 可以使用 select 进行切换数据库! key *查看数据库所有的key 清除当前数据库 flushdb 清除全部数据库的内容FLUSHALL 为什么redis是6379!(了解一下即可!) Redis 是…

Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的

文章目录 Elasticsearch聚合查询说明空值率查询DSL Elasticsearch聚合基础知识扩展Elasticsearch聚合概念Script 用法Elasticsearch聚合查询语法指标聚合&#xff08;Metric Aggregations&#xff09;桶聚合&#xff08;Bucket Aggregations&#xff09;矩阵聚合&#xff08;Ma…

福州大学 2022~2023 学年第 1 学期考试 A 卷压轴题参考答案

题目&#xff1a; 定义一个抽象类Structure&#xff08;含有纯虚函数type函数&#xff0c;用以显示当前结构的类型&#xff1b; 含有show函数&#xff09;&#xff0c; 在此基础上派生出Building类, 用来存储一座楼房的层数、房间数以及它的总平方米数。 建立派生 类House&am…

Type-C连接器厂商对检测实验室的要求及重要性解析

Type-C连接器厂商对检测实验室的要求与重要性 Type-C连接器作为一种高速、全功能的接口标准&#xff0c;被广泛应用于各类电子产品中。作为Type-C连接器的制造商&#xff0c;对于产品的质量和性能要求是至关重要的。为了确保产品符合规范并满足市场需求&#xff0c;Type-C连接…