作者:陌北有棵树,玩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,你读过它的源码么?相关推荐

  1. 4月,诚邀你参加源码共读,学会看源码,打开新世界!开阔视野

    大家好,我是若川.很多关注我的新朋友可能不知道我组织了源码共读活动~ 也有很多人不知道我是谁.有人以为我是80后.有人以为我是全职自媒体等等.若川的 2021 年度总结,弹指之间 这篇文章写了我是16 ...

  2. 人人都能读懂的react源码解析(大厂高薪必备)

    人人都能读懂的react源码解析(大厂高薪必备) 1.开篇(听说你还在艰难的啃react源码) ​ 本教程目标是打造一门严谨(严格遵循react17核心思想).通俗易懂(提供大量流程图解,结合demo ...

  3. 【Spring源码这样读】-怎么阅读源码

    做开发要不要读源码?如果你天天996,真心的不建议你去读源码(我是不介意做一个劝退师的).读源码确确实实是一个费时费力的活,如果你每天都很忙,偶尔看一眼,想了解其中的奥秘,这很难办到.那我们需不需要读 ...

  4. arraylist 的扩容机制_每天都用ArrayList,你读过它的源码么?

    作者:陌北有棵树,玩Java,架构师社区合伙人! [一]关于扩容 如果没有指定初始容量,则设置为10 /** * Default initial capacity. */private static ...

  5. 跟着小哈一起读AHT20温湿度传感器驱动源码

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 人工智能编程入门博客 AHT20简介 2020年上市,奥松生产: 3mmx3mmx1mm 超小体积: ...

  6. java面试——集合(ArrayList、lterator、LinkedList)源码理解

    文章目录 ArrayList扩容机制 lterator迭代器 ArrayList与LinkedList的区别 ArrayList扩容机制 初始化:(无参时)数组大小是0,添加第一个元素时是10.有参数 ...

  7. 分分钟带你读懂 ButterKnife 的源码

    为什么要写这一系列的博客呢? 因为在 Android 开发的过程中, 泛型,反射,注解这些知识进场会用到,几乎所有的框架至少都会用到上面的一两种知识,如 Gson 就用到泛型,反射,注解,Retrof ...

  8. 悦读FM客户端应用源码

    <ignore_js_op> <ignore_js_op><ignore_js_op> 正如悦读FM所表达的[当好的文字遇上好的声音],悦读FM提供了一个很好的文章 ...

  9. mysql 一致性读_MySQL半一致性读原理解析-从源码角度解析

    1.什么是半一致性读 A type of read operation used for UPDATE statements, that is a combination of read commit ...

最新文章

  1. 利用最小二乘法求解仿射变换参数
  2. python turtle画彩虹-Python基础实例——绘制彩虹(turtle库的应用)
  3. 最大熵学习笔记(六)优缺点分析
  4. Redis整合Spring结合使用缓存实例
  5. hystrix服务降级
  6. SAP 电商云 Spartacus UI added-to-cart 的端到端测试源代码解析
  7. Windows应用程序开发
  8. 程序如何在两个gpu卡上并行运行_深度学习分布式训练相关介绍 - Part 1 多GPU训练...
  9. leetcode1177. 构建回文串检测(前缀和)
  10. 关于webservice(CXF)的一些理解
  11. python词汇网络分析_8个Python高效数据分析的技巧!
  12. Spring Boot文档阅读笔记-对Securing a Web Application解析
  13. Google 是如何成为巨头的?
  14. 汇川IS620F PN博途使用FB284<111报文>进行基本定位,及GSD/使用说明下载<替换V90>
  15. 最大流(Max Flow)
  16. 爬PHP网站文件,蜘蛛来访爬取链接详情导出TXT文件(php脚本)
  17. 分布式对象存储服务器minio
  18. ps教程:教你如何制作一种牛仔布料
  19. Python 机器学习 | 超参数优化 黑盒(Black-Box)非凸优化技术实践
  20. js判断网络链接的四种方法

热门文章

  1. 习题8-9 分类统计各类字符个数 (15 分)
  2. babylonjs 分部加载模型_使用 Babylon.js 在 HTML 页面加载 3D 对象
  3. android获取指针空间大小_腾讯笔试题:浅谈计算机中cpu位数和指针
  4. 安卓 linux init.rc,[原创]Android init.rc文件解析过程详解(二)
  5. es获取最大时间的记录_ES查询一段时间内某一循环时间段的数据
  6. AcWing 734. 能量石 (01背包)+(贪心 - 领项交换)
  7. 【题解】P1508 Likecloud-吃、吃、吃(简单DP)
  8. mysql 多数据库文件_今天突然发现我的Linux下MySQL数据库目录多了好多文件
  9. J - Invitation Cards POJ - 1511
  10. android任务管理,安卓下载任务管理