ArrayList知识点(面试)

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

ArrayList(底层是数组)

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

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

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

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

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

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

线程不安全是怎么解决的

先看一段代码

 @Testvoid 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进行加锁

@Testvoid 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进行加锁

 @Testvoid 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来实现

  @Testvoid 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).

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

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

相关文章

人人讲视频如何下载

一、工具准备 1.VLC media player 2.谷歌浏览器 二、视频下载 1.打开人人讲网页&#xff0c;需要下载的视频 谷歌浏览器打开调试窗口 搜索m3u8链接 拷贝到VLCplayer打开网络串流方式打开测试是否能正常播放 2.下载视频 能正常播放后&#xff0c;切换播放为转换选择mp4格式…

24年火爆全网的企业信贷产品-民生惠详解

今年&#xff0c;民生惠企业信贷产品非常火爆&#xff01;客户想申请这信用贷款前&#xff0c;先确认下自己是不是在白名单里。有些地区还能加进白名单&#xff0c;不在的话就别申请了&#xff0c;这是专门给受邀的小微企业的。 这款产品的细节是这样的&#xff1a; 额度&am…

visual studio 创建c++项目

目录 环境准备&#xff1a;安装 visual studiovisual studio 创建c项目Tips&#xff1a;新建cpp文件注释与取消注释代码 其他初学者使用Visual Studio开发C和C时常遇到的3个坑 环境准备&#xff1a;安装 visual studio 官网&#xff1a;https://visualstudio.microsoft.com/zh…

【十三】图解mybatis缓存模块之装饰器模式

图解mybatis缓存模块之装饰器模式 简介 之前有写过一篇博客介绍过mybatis的缓存模块设计【九】mybatis 缓存模块设计-CSDN博客 &#xff0c;当时着重讲解的是mybatis种一级缓存和二级缓存&#xff0c;本次博客补充讲解一下装饰器模式的应用&#xff0c;本篇主要分两部分讲解&a…

kotlin智能类型转换

1、在kotlin这中&#xff0c;定义如下类型&#xff0c;在判断不为null的语句里边&#xff0c;会发生类型转换&#xff1a; fun main(){var a:String? "XXX" // a 类型为 String? 可能为 null// 在if 语句中&#xff0c;a 的类型为 Stringif(a ! null){println(a.l…

动态ARP

定义 动态ARP表项由ARP协议通过ARP报文自动生成和维护&#xff0c;可以被老化&#xff0c;可以被新的ARP报文更新&#xff0c;可以被静态ARP表项覆盖。 动态ARP适用于拓扑结构复杂、通信实时性要求高的网络。 ARP地址解析过程 动态ARP通过广播ARP请求和单播ARP应答这两个过…

使用 Kubernetes 部署 MinIO 和 Trino

Trino&#xff08;以前称为 Presto&#xff09;是一个 SQL 查询引擎&#xff0c;而不是 SQL 数据库。Trino 避开了 SQL 数据库的存储组件&#xff0c;只专注于一件事 - 超快的 SQL 查询。Trino 只是一个查询引擎&#xff0c;不存储数据。相反&#xff0c;Trino与各种数据库交互…

GWO-CNN-SVM,基于GWO灰狼优化算法优化卷积神经网络CNN结合支持向量机SVM数据分类(多特征输入多分类)

GWO-CNN-SVM&#xff0c;基于GWO灰狼优化算法优化卷积神经网络CNN结合支持向量机SVM数据分类(多特征输入多分类) 1. GWO灰狼优化算法 灰狼优化算法&#xff08;Grey Wolf Optimizer, GWO&#xff09;是一种启发式优化算法&#xff0c;模拟了灰狼群体的社会行为&#xff0c;包…

天马学航——智慧教务系统(移动端)开发日志六

天马学航——智慧教务系统(移动端)开发日志六 日志摘要&#xff1a;统一身份认证设计&#xff0c;修复了选课信息错乱的问题 界面设计 实现思路 使用 Java 和 Jedis 完成实现&#xff1a; 步骤一&#xff1a;添加 Jedis 依赖 首先需要在项目中添加 Jedis 依赖&#xff0c;…

使用海康威视的SDK,利用WPF设计一个网络摄像头的显示控制程序(上位机)

目录 一、下载海康威视的SDK 1.1 关于SDK 1.2 关于API 1.3 关于DLL 1.4 下载海康威视的SDK 1.5 关于网络高清摄像机 二、对下载的SDK进行调试 三、利用Visual Studio打开项目的解决方案 3.1 Visual Studio 2022下载 3.2 关于句柄 四、打开WPF进行ui页面设计 4.1 关…

react笔记-03react-router篇

本文章是react的路由笔记 一、react路由&#xff08;v5版本&#xff09; 1. 什么是路由&#xff08;前端&#xff09;&#xff1f; 一个路由就算一个映射关系&#xff08;key: value)key为路径&#xff0c;value为组件 2. 前端路由的工作原理 根据浏览器历史记录&#xff…

双例集合(三)——双例集合的实现类之TreeMap容器类

Map接口有两个实现类&#xff0c;一个是HashMap容器类&#xff0c;另一个是TreeMap容器类。TreeMap容器类的使用在API上于HashMap容器类没有太大的区别。它们的区别主要体现在两个方面&#xff0c;一个是底层实现方式上&#xff0c;HashMap是基于Hash算法来实现的吗&#xff0c…

什么是电商大数据?主流电商大数据的采集||关键性技术|电商API接口接入说明

大数据的时代早已到来&#xff0c;然而想要全方位掌握大数据&#xff0c;务必要掌握大数据造成的时代特征&#xff0c;之前大数据被视为废物&#xff0c;如今被视为财产。主流电商大数据的采集&#xff0c;电商API接口的接入在大多数人理解中&#xff0c;是企业用数据来优化自己…

HackTheBox-Linux基础

Linux 结构 历史 许多事件导致了第一个 Linux 内核的创建&#xff0c;并最终创建了 Linux 操作系统 &#xff08;OS&#xff09;&#xff0c;从 1970 年 Ken Thompson 和 Dennis Ritchie&#xff08;当时都在 AT&T 工作&#xff09;发布 Unix 操作系统开始。伯克利软件发行…

微信小程序毕业设计-餐厅点餐系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

OCC显示渲染结构剖析

1.Display显示 2.Drawer 3.Graphics 4.InteractiveContext 5.Render 6.Selection 7.View

图像分割(四)---(图像显示、灰度直方图和三维灰度图综合分析选取最佳分割方法)

一、引言 对彩色图像进行分割的一种常用方法&#xff0c;是先把彩色图像转灰度图像&#xff0c;然后再选择合适的阈值进行二值分割。但有时彩色图像转灰度图像后不具有典型的双峰特性&#xff0c;二值分割效果不好。本文章提出一种确定彩色图像分割方法的新思路。首先读入一幅彩…

以太坊==给合约转入/查询合约剩余/合约转给某账户/结构体/MAP

转入 必须要定义该函数&#xff0c;或者定义fallback // 接收以太币 receive() external payable {} // Corrected Line // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;contract SimpleStorage {uint256 private storedData;// 事件&#xff0c;用于通知数据变更e…

Java-异常:不恰当的异常转换、不充分的日志记录、过度或不当的异常捕获

Java-异常&#xff1a;不恰当的异常转换、不充分的日志记录、过度或不当的异常捕获 Java-异常&#xff1a;不恰当的异常转换、不充分的日志记录、过度或不当的异常捕获一、前期准备二、案例分析1、不恰当的异常转换2、不充分日志记录3、过度或不当的异常捕获 三、正确处理方式1…

Open WebUI – 本地化部署大模型仿照 ChatGPT用户界面

Open WebUI介绍&#xff1a; Open WebUI 是一个仿照 ChatGPT 界面&#xff0c;为本地大语言模型提供图形化界面的开源项目&#xff0c;可以非常方便的调试、调用本地模型。你能用它连接你在本地的大语言模型&#xff08;包括 Ollama 和 OpenAI 兼容的 API&#xff09;&#xf…