每天都用ArrayList,你读过它的源码么?
作者:陌北有棵树,玩Java,架构师社区合伙人!
【一】关于扩容
如果没有指定初始容量,则设置为10
/** * Default initial capacity. */private static final int DEFAULT_CAPACITY = 10;ArrayList的扩容比较简单,容量扩为之前的1.5倍/** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity */private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity);}
【二】关于拷贝
源码中用到的数组复制的两个方法分别是:System.arraycopy()和Arrays.copyOf()
一句话总结二者区别:Arrays.copyOf()可以看做是受限制的System.arraycopy()
Arrays.copyOf()是系统自己创建一个数组,再调用System.arraycopy()复制
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy;}
System.arraycopy()需要传入一个目标数组作为参数,同时可以指定拷贝的起点和拷贝的长度
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
各个参数的含义:
src - 源数组。
srcPos - 源数组中的起始位置。
dest - 目标数组。
destPos - 目标数据中的起始位置。
length - 要复制的数组元素的数量。
同时要注意的是,上述两个拷贝方法都是浅拷贝,关于深拷贝和浅拷贝,后续会做详细说明。
【三】关于Fail-Fast
Fail-Fast是非线程安全的集合,实现的一种错误机制。但不能百分百得到保证,只是尽最大努力抛出ConcurrentModificationException。
什么时候产生Fail-Fast
ArrayList中如何实现Fail-Fast
两个变量:modCount和expectedModCount
只要涉及到数组个数改变的方法,都会导致modCount的改变(add、remove、clear)
当发现expectedModCount和modCount不一致,就会抛出ConcurrentModificationException
所以,Iterator在遍历时,是不允许被迭代的对象被改变的
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException();}
如何避免Fail-Fast:用CopyOnWriteArrayList代替ArrayList
【四】关于ArrayList中删除元素
错误的删除方式一:for循环遍历删除
public void testRemove() { List<Integer> integers = new ArrayList<>(5); integers.add(1); integers.add(2); integers.add(2); integers.add(4); integers.add(5); for (int i = 0; i < integers.size(); i++) { if (integers.get(i) % 2 == 0) { integers.remove(i); } } System.out.println(integers);}
这段代码的输出是 [1,2,5]
因为在remove方法执行的时候,删除第一个“2”,会更新后面的索引值,数组变为[1,2,4,5],这样会导致第二个“2”不会被删除
错误的删除方式二:使用Iterator遍历,但仍用ArrayList的remove方法
public void testRemove(){ List<String> strings = new ArrayList<>(); strings.add("a"); strings.add("b"); strings.add("c"); strings.add("d"); Iterator<String> iterator = strings.iterator(); while (iterator.hasNext()){ String next = iterator.next(); strings.remove(next); } System.out.println(strings);}
会抛出ConcurrentModificationException,参见上述的Fail-Fast机制
正确的删除方法:使用Iterator的remove方法
public static void main(String[] args) { List<Integer> intList = new ArrayList<Integer>(); Collections.addAll(intList, 1, 2, 3, 5, 6); Iterator<Integer> it = intList.iterator(); while(it.hasNext()) { Integer value = it.next(); if(value == 3 || value == 5) { it.remove(); } } System.out.println(intList);}
长按订阅更多精彩▼
如有收获,点个在看,诚挚感谢
每天都用ArrayList,你读过它的源码么?相关推荐
- 4月,诚邀你参加源码共读,学会看源码,打开新世界!开阔视野
大家好,我是若川.很多关注我的新朋友可能不知道我组织了源码共读活动~ 也有很多人不知道我是谁.有人以为我是80后.有人以为我是全职自媒体等等.若川的 2021 年度总结,弹指之间 这篇文章写了我是16 ...
- 人人都能读懂的react源码解析(大厂高薪必备)
人人都能读懂的react源码解析(大厂高薪必备) 1.开篇(听说你还在艰难的啃react源码) 本教程目标是打造一门严谨(严格遵循react17核心思想).通俗易懂(提供大量流程图解,结合demo ...
- 【Spring源码这样读】-怎么阅读源码
做开发要不要读源码?如果你天天996,真心的不建议你去读源码(我是不介意做一个劝退师的).读源码确确实实是一个费时费力的活,如果你每天都很忙,偶尔看一眼,想了解其中的奥秘,这很难办到.那我们需不需要读 ...
- arraylist 的扩容机制_每天都用ArrayList,你读过它的源码么?
作者:陌北有棵树,玩Java,架构师社区合伙人! [一]关于扩容 如果没有指定初始容量,则设置为10 /** * Default initial capacity. */private static ...
- 跟着小哈一起读AHT20温湿度传感器驱动源码
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 人工智能编程入门博客 AHT20简介 2020年上市,奥松生产: 3mmx3mmx1mm 超小体积: ...
- java面试——集合(ArrayList、lterator、LinkedList)源码理解
文章目录 ArrayList扩容机制 lterator迭代器 ArrayList与LinkedList的区别 ArrayList扩容机制 初始化:(无参时)数组大小是0,添加第一个元素时是10.有参数 ...
- 分分钟带你读懂 ButterKnife 的源码
为什么要写这一系列的博客呢? 因为在 Android 开发的过程中, 泛型,反射,注解这些知识进场会用到,几乎所有的框架至少都会用到上面的一两种知识,如 Gson 就用到泛型,反射,注解,Retrof ...
- 悦读FM客户端应用源码
<ignore_js_op> <ignore_js_op><ignore_js_op> 正如悦读FM所表达的[当好的文字遇上好的声音],悦读FM提供了一个很好的文章 ...
- mysql 一致性读_MySQL半一致性读原理解析-从源码角度解析
1.什么是半一致性读 A type of read operation used for UPDATE statements, that is a combination of read commit ...
最新文章
- 利用最小二乘法求解仿射变换参数
- python turtle画彩虹-Python基础实例——绘制彩虹(turtle库的应用)
- 最大熵学习笔记(六)优缺点分析
- Redis整合Spring结合使用缓存实例
- hystrix服务降级
- SAP 电商云 Spartacus UI added-to-cart 的端到端测试源代码解析
- Windows应用程序开发
- 程序如何在两个gpu卡上并行运行_深度学习分布式训练相关介绍 - Part 1 多GPU训练...
- leetcode1177. 构建回文串检测(前缀和)
- 关于webservice(CXF)的一些理解
- python词汇网络分析_8个Python高效数据分析的技巧!
- Spring Boot文档阅读笔记-对Securing a Web Application解析
- Google 是如何成为巨头的?
- 汇川IS620F PN博途使用FB284<111报文>进行基本定位,及GSD/使用说明下载<替换V90>
- 最大流(Max Flow)
- 爬PHP网站文件,蜘蛛来访爬取链接详情导出TXT文件(php脚本)
- 分布式对象存储服务器minio
- ps教程:教你如何制作一种牛仔布料
- Python 机器学习 | 超参数优化 黑盒(Black-Box)非凸优化技术实践
- js判断网络链接的四种方法
热门文章
- 习题8-9 分类统计各类字符个数 (15 分)
- babylonjs 分部加载模型_使用 Babylon.js 在 HTML 页面加载 3D 对象
- android获取指针空间大小_腾讯笔试题:浅谈计算机中cpu位数和指针
- 安卓 linux init.rc,[原创]Android init.rc文件解析过程详解(二)
- es获取最大时间的记录_ES查询一段时间内某一循环时间段的数据
- AcWing 734. 能量石 (01背包)+(贪心 - 领项交换)
- 【题解】P1508 Likecloud-吃、吃、吃(简单DP)
- mysql 多数据库文件_今天突然发现我的Linux下MySQL数据库目录多了好多文件
- J - Invitation Cards POJ - 1511
- android任务管理,安卓下载任务管理