关于ArrayList的十三连问

文章目录

  • 一、底层存储结构是什么
  • 二、初始容量
  • 三、构造方法
  • 四、扩容原理
  • 五、读写速度比较
  • 六、克隆为深克隆还是浅克隆
  • 七、多线程环境下是否安全
  • 八、增强遍历时添加或删除元素会发生什么事情
  • 九、为什么数组被transient修饰
  • 十、通过`subList()`获得的集合能否转为`ArrayList`
  • 十一、使用`SubList`时有哪些注意事项
  • 十二、如何将集合转为数组
  • 十三、使用`Arrays.asList`有什么注意事项

推荐往期文章: ArrayList源码解读

一、底层存储结构是什么

答:数组

transient Object[] elementData;

二、初始容量

答:默认初始容量为10,也可以通过构造方法指定初始容量

  • 默认初始容量为10

    private static final int DEFAULT_CAPACITY = 10;
    
  • 通过构造方法指定初始容量

    public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}
    }
    

三、构造方法

答:三个

  • 无参构造方法

    public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
  • 指定初始容量的构造方法

    public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}
    }
    
  • 指定集合的构造方法

    public ArrayList(Collection<? extends E> c) {Object[] a = c.toArray();if ((size = a.length) != 0) {if (c.getClass() == ArrayList.class) {elementData = a;} else {elementData = Arrays.copyOf(a, size, Object[].class);}} else {// replace with empty array.elementData = EMPTY_ELEMENTDATA;}
    }
    

四、扩容原理

当需要向ArrayList集合中添加元素时,采用先扩容,后插入的方式。

ArrayList的扩容逻辑由grow()方法实现,扩容后底层数组的新长度=原长度*1.5,即容量扩展为原来的1.5倍,该计算方法是通过位运算实现的,且最大长度不得超过int的最大值,即 2 23 − 1 2^{23}-1 2231

当确定新的数组长度后,通过Arrays.copyOf获取一个具有新长度的数组,该方法底层是通过调用jvm本地方法System.arraycopy()方法实现的。

五、读写速度比较

答:读数据快,写数据慢。由于底层采用数组作为存储元素的结构,而数组支持根据下标读取元素。

根据下标操作ArrayList时,读取和修改操作快添加和删除操作慢(因为这两个操作需要移动数组中的元素)。特殊情况是在数组尾部添加元素时,操作快。

根据元素操作ArrayList时,读取、修改、添加、删除四个操作都慢,因为数组本身只支持根据下标操作元素,因此当根据元素操作时,需要从头遍历数组。

六、克隆为深克隆还是浅克隆

答:浅克隆

ArrayList实现了Cloneable接口并实现了clone()方法,因此具有克隆的功能。但是其clone()方法的实现中仅克隆了ArrayList对象,却没有克隆其内部数组中的元素(通过Arrays.copyOf()方法),结果是克隆后的ArrayList对象与克隆前的ArrayList对象为两个对象,内部数组中的元素却是相同的对象,指向同一个内存地址。

public Object clone() {try {ArrayList<?> v = (ArrayList<?>) super.clone();v.elementData = Arrays.copyOf(elementData, size);v.modCount = 0;return v;} catch (CloneNotSupportedException e) {// this shouldn't happen, since we are Cloneablethrow new InternalError(e);}
}

代码演示如下:

public static void cloneDemo() {ArrayList<Person> personArrayList = new ArrayList<>();personArrayList.add(new Person("张三"));personArrayList.add(new Person("李四"));personArrayList.add(new Person("王五"));System.out.println("克隆前person集合,内存地址:" + System.identityHashCode(personArrayList) + ",元素:" + personArrayList);Object personListClone = personArrayList.clone();ArrayList<Person> newPersonList = (ArrayList<Person>) personListClone;System.out.println("克隆后person集合,内存地址:" + System.identityHashCode(newPersonList) + ",元素:" + newPersonList);newPersonList.get(0).setName("我修改了名字");System.out.println("修改元素==============");System.out.println("克隆前person集合,内存地址:" + System.identityHashCode(personArrayList) + ",元素:" + personArrayList);System.out.println("克隆后person集合,内存地址:" + System.identityHashCode(newPersonList) + ",元素:" + newPersonList);
}

输出:

在这里插入图片描述

七、多线程环境下是否安全

答:多线程不安全

因为在ArrayList中没有使用synchronized或其他加锁操作,因此线程不安全。

在多线程环境下,可以通过以下方法避免线程不安全的问题:

  • 在操作ArrayList的方法或代码块上加锁,无论是通过synchronized还是Lock
  • 使用Vector
  • 使用CopyOnWriteArrayList

八、增强遍历时添加或删除元素会发生什么事情

答:会抛出ConcurrentModificationException异常,但仅限于增强型遍历forEach()方法。

如下代码所示

private ArrayList<Integer> list = new ArrayList<>();for(Integer i : list) {list.remove(i);
}

在遍历时通过添加或删除元素会导致其底层数组结构发生变化,ArrayList通过使用expectedModCountmodCount两个变量判断结构是否发生变化,如果有变化,则将抛出ConcurrentModificationException异常。

解决办法:

  • 使用ArrayList内部类迭代器ItrListItr提供的add()remove()方法对集合进行添加和删除操作。在迭代器的方法中会控制expectedModCountmodCount两个变量的值,使其避免抛出ConcurrentModificationException
  • 使用CopyOnWriteArrayList

九、为什么数组被transient修饰

答:使用关键字transient来修饰数组并不表示不将其序列化,ArrayList在序列化时,最主要的是将其内部元素进行序列化而不是数组,再加上数组中可能存在大量空元素,若将数组进行序列化,对时间和空间无疑都是一种消耗。

另外我们可以通过源码看一下他的序列化和反序列化过程。

  • 序列化

    在序列化时,通过遍历数组中的元素,将元素进行序列化,而非数组。

    private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{// Write out element count, and any hidden stuffint expectedModCount = modCount;s.defaultWriteObject();// Write out size as capacity for behavioural compatibility with clone()s.writeInt(size);// Write out all elements in the proper order.for (int i=0; i<size; i++) {s.writeObject(elementData[i]);}if (modCount != expectedModCount) {throw new ConcurrentModificationException();}
    }
    
  • 反序列化

    private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {elementData = EMPTY_ELEMENTDATA;// Read in size, and any hidden stuffs.defaultReadObject();// Read in capacitys.readInt(); // ignoredif (size > 0) {// be like clone(), allocate array based upon size not capacityint capacity = calculateCapacity(elementData, size);SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);ensureCapacityInternal(size);Object[] a = elementData;// Read in all elements in the proper order.for (int i=0; i<size; i++) {a[i] = s.readObject();}}
    }
    

十、通过subList()获得的集合能否转为ArrayList

答:不能

subList()方法返回的是ArrayList的内部类SubList的实例,并不是 ArrayList 本身,而是 ArrayList 的一个视图,对于 SubList 的所有操作最终会反映到原列表上。因此无法转为ArrayList

public List<E> subList(int fromIndex, int toIndex) {subListRangeCheck(fromIndex, toIndex, size);return new SubList(this, 0, fromIndex, toIndex);
}

在《阿里巴巴Java开发手册》嵩山版中是这样描述的:

在这里插入图片描述

十一、使用SubList时有哪些注意事项

SubListArrayList的一个内部类,表示为ArrayList集合的一个视图,对子集合的操作会影响父集合,对父集合的操作也会影响子集合。

  • 修改父集合元素的值,会影响子集合
  • 修改父集合的结构,会引起子集合在遍历、增加、删除操作中出现ConcurrentModificationException异常
  • 修改子集合元素的值,会影响父集合
  • 修改子集合的结构,会影响父集合

在《阿里巴巴Java开发手册》嵩山版中是这样描述的:

在这里插入图片描述

十二、如何将集合转为数组

答:使用toArray()方法或toArray(T[] a)方法。

但是一般来说,我们都使用toArray(T[] a)方法实现,且传入的是类型完全一致、长度为0的空数组。至于为什么,在《阿里巴巴Java开发手册》嵩山版中是这样描述的:

在这里插入图片描述

十三、使用Arrays.asList有什么注意事项

答:使用Arrays.asList()方法得到的List实例为ArrayList 实例,但需要注意的是,此处返回的ArrayList 实例为Arrays的内部类,其全限定类路径为java.util.Arrays.ArrayList,而我们常用的ArrayList 的全限定类路径为java.util.ArrayList,这是两个不同的类。

当我们通过Arrays.asList()方法得到一个集合时,只能对其进行读取、遍历、修改操作,而不能使用修改集合结构相关的方法如增加、删除等,否则会抛出异常UnsupportedOperationException

且该内部类体现的是适配器的设计模式,其内部依然是一个数组,只是通过asList()方法改变我们操作数组的方式而已。

在《阿里巴巴Java开发手册》嵩山版中是这样描述的:

在这里插入图片描述



纸上得来终觉浅,绝知此事要躬行。

————————————————我是万万岁,我们下期再见————————————————

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

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

相关文章

如何在 .NET Core WebApi 中处理 MultipartFormDataContent 中的文件

问题描述# 上图示例展示了用户通过 IOS 客户端发送请求时&#xff0c;对应后端接口接收到的 Request 内容。从请求内容的整体结果&#xff0c;我们可以看出这是一个 multipart/form-data 的数据格式&#xff0c;由于这种数据是由多个 multipart section 组成&#xff0c;所以我…

在next中使用antd表格,表格使用render函数报错

Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". {title: "姓名", dataIndex: "name", key: ..., render: function} 错误描述&#xff1a;使用antd的tabl…

【FAQ】安防监控视频EasyCVR平台分发的FLV视频流在VLC中无法播放

众所周知&#xff0c;TSINGSEE青犀视频汇聚平台EasyCVR可支持多协议方式接入&#xff0c;包括主流标准协议国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。在视频流的处理与分发上&#xff0c;视频监控…

资深媒体人宋繁银加入《数据猿》任总编辑,全面负责公司整体内容工作

大数据产业创新服务媒体 ——聚焦数据 改变商业 2023年7月北京&#xff0c;《数据猿》宣布正式任命宋繁银为总编辑&#xff0c;全面负责公司整体内容工作。此次重要的人事任命标志着《数据猿》的发展迈上了一个新的台阶&#xff0c;对于《数据猿》团队而言&#xff0c;不仅是一…

LISA:通过大语言模型进行推理分割

论文&#xff1a;https://arxiv.org/pdf/2308.00692 代码&#xff1a;GitHub - dvlab-research/LISA 摘要 尽管感知系统近年来取得了显著的进步&#xff0c;但在执行视觉识别任务之前&#xff0c;它们仍然依赖于明确的人类指令来识别目标物体或类别。这样的系统缺乏主动推理…

谱包络之pysptk和pyworld

谱包络之pysptk和pyworld 谱包络可以直接用于语音的合成&#xff0c;常用的两个计算谱包络的库pysptk和pyword。 先看看代码&#xff1a; 一段语音x&#xff0c;采样率16000Hz pysptk import pysptkframe_length 1024 hop_length 80 order 25 alpha 0.41 frames libro…

个保新标 | 《信息安全技术 敏感个人信息处理安全要求》(征求意见稿)发布

8 月 9 日&#xff0c;全国信息安全标准化技术委员会公开发布关于国家标准《信息安全技术 敏感个人信息处理安全要求》&#xff08;征求意见稿&#xff09;&#xff08;以下简称《标准》&#xff09;的通知&#xff0c;面向社会广泛征求意见。 《标准》的制定背景是为支撑《个人…

k8s pod启动报错: no route to host

k8s pod kuboard启动报错 查看pod命令 kubectl get pods -A kubectl get pods --all-namespaces查看报错pod日志 命令&#xff1a; kubectl logs -f -n namespace nametime"2023-08-09T13:40:3608:00" levelerror msg"不能获取 AgentEndpointsGet \"http:/…

【论文阅读】基于深度学习的时序预测——FEDformer

系列文章链接 论文一&#xff1a;2020 Informer&#xff1a;长时序数据预测 论文二&#xff1a;2021 Autoformer&#xff1a;长序列数据预测 论文三&#xff1a;2022 FEDformer&#xff1a;长序列数据预测 论文四&#xff1a;2022 Non-Stationary Transformers&#xff1a;非平…

如何实现Excel中多级数据联动

摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 在类Excel表格应用中&#xff0c;常用的需求场景是根据单元格之间的数据联动&…

计算机视觉的应用10-图片中的表格结构识别与提取实战

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用10-图片中的表格结构识别与提取实战&#xff0c;表格结构识别在信息处理领域中具有广泛应用&#xff0c;但由于表格的多样性和复杂性&#xff0c;以及难以准确解析的布局和格式&#xff0c;传统的方…

读《Flask Web开发实战》(狼书)笔记 | 第1、2章

前言 2023-8-11 以前对网站开发萌生了想法&#xff0c;又有些急于求成&#xff0c;在B站照着视频敲了一个基于flask的博客系统。但对于程序的代码难免有些囫囵吞枣&#xff0c;存在许多模糊或不太理解的地方&#xff0c;只会照葫芦画瓢。 而当自己想开发一个什么网站的时&…

ad+硬件每日学习十个知识点(26)23.8.6 (DCDC的降压电路、升压电路、降压-升压电路,同步整流,选型考虑同步、隔离)

文章目录 1.DCDC的降压原理2.DCDC的升压原理3.DCDC的升压和降压原理4.什么是肖特基二极管造成的死区电压&#xff1f;5.MOS管有死区电压么&#xff1f;6.DCDC的同步整流&#xff08;用MOS管取代整流二极管&#xff0c;避免死区电压的影响&#xff09;7.DCDC选型——同步与非同步…

分清性能测试,负载测试,压力测试这三个的区别

做测试一年多来&#xff0c;虽然平时的工作都能很好的完成&#xff0c;但最近突然发现自己在关于测试的整体知识体系上面的了解很是欠缺&#xff0c;所以&#xff0c;在工作之余也做了一些测试方面的知识的补充。不足之处&#xff0c;还请大家多多交流&#xff0c;互相学习。 …

AI:02-基于深度学习的动物图像检索算法的研究

文章目录 一、算法原理二、代码实现三、实验结果四、总结深度学习在计算机视觉领域中的应用越来越广泛,其中动物图像检索算法是一个重要的应用场景。本文将介绍一种基于深度学习的动物图像检索算法,并提供相应的代码实现。 一、算法原理 本算法采用卷积神经网络(Convolutio…

Selenium 根据元素文本内容定位

使用xpath定位元素时&#xff0c;有时候担心元素位置会变&#xff0c;可以考虑使用文本内容来定位的方式。 例如图中的【股市】按钮&#xff0c;只有按钮文本没变&#xff0c;即使位置变化也可以定位到该元素。 xpath内容样例&#xff1a; # 文本内容完全匹配 //button[text(…

勘探开发人工智能技术:机器学习(6)

0 提纲 7.1 循环神经网络RNN 7.2 LSTM 7.3 Transformer 7.4 U-Net 1 循环神经网络RNN 把上一时刻的输出作为下一时刻的输入之一. 1.1 全连接神经网络的缺点 现在的任务是要利用如下语料来给apple打标签&#xff1a; 第一句话&#xff1a;I like eating apple!(我喜欢吃苹…

Mac M1 安装Oracle Java 与 IEDA

文章目录 1 官网下载2 安装IDEA参考 1 官网下载 https://www.oracle.com/ 使用finder中的拖拽进行安装即可 2 安装IDEA https://www.jetbrains.com/zh-cn/idea/download/?sectionmac 同样的&#xff0c;下载完后拖拽安装即可 参考 Mac M1 安装Java 开发环境 https://blog.…

倒数纪念日-生日提醒事项时间管理倒计时软件

倒数纪念日​​​​​​​是一款功能强大的时间管理、事项提醒软件。帮你更好的管理倒数日、纪念日、生日、节假日、还款日等各种重要日子&#xff0c;通知提醒&#xff0c;让你不再错过生命中的每一个重要日子。 【功能简介】 分类管理&#xff1a;倒数日、纪念日、自定义分类…

【VB6|第22期】用SQL的方式读取Excel数据

日期&#xff1a;2023年8月7日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xff…