前言

点赞在看,养成习惯。

点赞收藏,人生辉煌。

点击关注【微信搜索公众号:编程背锅侠】,第一时间获得最新文章。

看源码血泪史

刚开始工作面试的时候,面试官经常问ArrayList源码相关的问题,基本上都是这部分很快结束战斗。

  • 面试官:你看过ArrayList的源码吗?
  • 我:你肯定会说看过呀。
  • 面试官:那你来讲讲你对ArrayList源码的理解吧。
  • 我:底层的数据结构是object数组;增删快、查询慢等等,没说几句就完了。

其实看了ArrayList的源码以后,你会发现能说的点还是有很多的。
比如ArrayList的构造方法的底层数组真的是构造了一个长度为10的数组吗?
Arrays.copy方法,grow扩容方法是怎么扩容的?等等都可以细说。
ArrayList的源码从工作到现在大概看了不下10遍,这其中包括看了半道放弃的。
刚开始看源码是在一些博客网站上看,看的稀里糊涂不是很明白,越看越想放弃。
后面看了一些公开课,跟着老师讲的视频看源码,看完之后感觉有点意思。但是看完之后,自己单独看还是有点吃力。
2020年4月份的时候看了一遍ArrayList源码并且每行都做了注释,整理在了有道上。
现在是七月初时隔两个月在再次看源码发现以前的笔记有部分是模糊、或者理解不正确的。
目前我发布出来的ArrayList源码是我一步一步DEBUG调试验证的源码。如果理解有问题看过之后,还请多多指教。

ArrayList系列文章

第一篇:ArrayList中的构造方法源码在面试中被问到了…抱歉没准备好!!!告辞
第二篇:面试官让我讲ArrayList中add、addAll方法的源码…我下次再来
第三篇:工作两年还没看过ArrayList中remove、removeAll、clear方法源码的都来报道吧
第四篇: 乱披风锤法锤炼ArrayList源码中的get、set、contains、isEmpty方法!!!肝起来
第五篇: 满屏飘红,操作ArrayList的Iterator方法时竟然给我报ConcurrentModificationException异常,撸ta

删除方法表格

方法名 描述
public E remove(int index) 根据索引删除元素
public boolean remove(Object o) 根据元素删除元素
public void clear() 将集合清空
public boolean removeAll(Collection<?> c) 删除与给定集合中相同的元素

public E remove(int index) 根据索引删除元素

案例演示

@Test
public void test_remove_index(){ArrayList<String> list = new ArrayList<>();list.add("洛洛01");list.add("洛洛02");list.add("洛洛03");list.forEach(System.out::println);// 索引删除list.remove(1);list.forEach(System.out::println);
}

源码分析

public E remove(int index) {// 校验这个索引是否在集合中存在rangeCheck(index);// 记录修改的次数modCount++;// 将index对应的元素赋值给 oldValueE oldValue = elementData(index);// 计算集合中需要移动元素个数int numMoved = size - index - 1;// 判断要移动的元素个数是否大于0if (numMoved > 0)// 能进到这里面要删除的元素肯定不在集合的最后面// 如果需要移动元素个数大于0,就使用arrayCopy方法进行拷贝 // 注意:数据源和目标数据都是elementDataSystem.arraycopy(elementData, index+1, elementData, index,numMoved);// 将源集合最后一个元素置为null,尽早让垃圾回收机制对其进行回收elementData[--size] = null; // clear to let GC do its work// 返回被删除的元素return oldValue;
}

elementData数组中元素的变化

  • 源数组中的元素

  • System.arraycopy执行前数组中元素

  • System.arraycopy执行后数组中元素-1

  • System.arraycopy执行后数组中元素-2

总结

根据索引删除元素,返回被删除的元素。重点关注elementData数组中元素的变化,可以帮助理解。

System.arraycopy方法不明白的参考这篇文章

public boolean remove(Object o) 根据元素删除元素

案例演示

@Test
public void test_remove_v(){ArrayList<String> list = new ArrayList<>();list.add("洛洛01");list.add("洛洛02");list.add("洛洛03");list.add("洛洛04");list.forEach(System.out::println);// 值删除list.remove("洛洛03");list.forEach(System.out::println);
}

源码分析

public boolean remove(Object o) {// 判断要删除的元素是否为nullif (o == null) {// 被删除的元素为null,遍历这个集合for (int index = 0; index < size; index++)// 判断集合的元素是否为nullif (elementData[index] == null) {// 如果相等,调用fastRemove方法快速删除fastRemove(index);return true;}} else {// 被删除的元素不为空,遍历集合for (int index = 0; index < size; index++)// 用o对象的equals方法和集合每一个元素进行比较if (o.equals(elementData[index])) {// 如果相等,调用fastRemove方法快速删除fastRemove(index);return true;}}// 如果集合没有o该元素,那么就会返回falsereturn false;
}// 根据索引快速删除方法
private void fastRemove(int index) {// 记录修改的次数modCount++;// 计算要移动元素的个数int numMoved = size - index - 1;// 如果需要移动的个数大于0,调用arrayCopy方法进行拷贝,判断是不是在尾部插入,大于0不是在尾部if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);// 将集合最后一个元素置为null,尽早被释放elementData[--size] = null; // clear to let GC do its work
}

elementData数组中元素的变化

  • 源数组中的元素

  • System.arraycopy执行前数组中元素

  • System.arraycopy执行后数组中元素

总结

根据给定的元素删除集合中与之匹配的元素。返回值为是否删除成功的布尔值。

System.arraycopy方法不明白的参考这篇文章

public void clear()将集合清空

案例演示

@Test
public void test_clear(){ArrayList<String> list = new ArrayList<>();list.add("洛洛01");list.add("洛洛02");list.forEach(System.out::println);list.clear();list.forEach(System.out::println);
}

源码分析

public void clear() {// 实际修改集合次数++modCount++;// 遍历集合,将集合每一个索引对应位置上的元素都置为null,尽早让其释放for (int i = 0; i < size; i++)elementData[i] = null;// 集合长度更改为0size = 0;
}

elementData数组中元素的变化

  • 源数组中的元素

  • 清空以后的数组

总结

将集合清空。这个方法会将集合每一个索引对应位置上的元素都置为null,为的是尽早让垃圾收集器回收。

public boolean removeAll(Collection<?> c)删除与给定集合中相同的元素

案例演示

@Test
public void test_remove_all(){ArrayList<String> list = new ArrayList<>();list.add("洛洛01");list.add("洛洛02");list.forEach(System.out::println);ArrayList<String> all = new ArrayList<>();all.add("洛洛01");all.add("洛洛05");list.removeAll(all);list.forEach(System.out::println);
}

源码分析

public boolean removeAll(Collection<?> c) {// 校验集合是否为空,为空抛出空指针异常Objects.requireNonNull(c);// 批量删除return batchRemove(c, false);
}

elementData数组中元素的变化

  • 源数组中的元素

  • 源数组变化以后的元素

总结

删除与给定集合中相同的元素。这个方法的主要实现是batchRemove方法。

private boolean batchRemove(Collection<?> c, boolean complement)批量删除方法

private boolean batchRemove(Collection<?> c, boolean complement) {// 将原始数组的地址赋值给elementDatafinal Object[] elementData = this.elementData;// r:用于遍历原始数组,原始数组中元素的索引, w:记录的是未被删除元素的个数int r = 0, w = 0;// modified:是否删除成功给个默认值falseboolean modified = false;try {// 遍历原始数组,size为原始数组的长度for (; r < size; r++)// complement的给定的值为false,判断指定的集合c是否不包含这个元素if (c.contains(elementData[r]) == complement)// 指定的集合c中不包含原始数组中的元素,将这个元素放到elementData数组中。// 这个循环执行完毕,elementData数组中存放的就是从索引0开始存放未被删除的元素,和后面可能有要被删除的和未被删除的元素,总的长度是原始数组的size。被删除的元素会留在原位置,未被删除的元素原位置有一份,还有一份复制到前面。elementData[w++] = elementData[r];} finally {// 正常情况下r == size的,这个不等于是抛出了异常if (r != size) {// 数组的拷贝,参看我的其他文章,有这个方法的源码详解System.arraycopy(elementData, r,elementData, w,size - r);// 计算修改的次数w += size - r;}// 判断w【记录未被删除的元素的个数】是否等于元素数组的长度if (w != size) {// clear to let GC do its work,方便垃圾回收,将elementData数组从索引i=w开始,置空每个元素for (int i = w; i < size; i++)// 置空元素elementData[i] = null;// size - w删除元素的个数,modCount记录的是修改的次数,每删除一个元素modCount加1modCount += size - w;// 删除执行完以后集合的长度size = w;// 删除成功modified 赋值为truemodified = true;}}// 返回是否删除成功return modified;
}

创作不易, 非常欢迎大家的点赞、评论和关注(^_−)☆
你的点赞、评论以及关注是对我最大的支持和鼓励,而你的支持和鼓励
我继续创作高质量博客的动力 !!!

奥莉嘎!!!ArrayList源码中remove、removeAll、clear方法我又肝了一遍,收获良多相关推荐

  1. Python:如何查看一个对象有哪些属性、方法以及查询源码中只有pass的方法的参数

    Python:如何查看一个对象有哪些属性.方法以及查询源码中只有pass的方法的参数 1.问题背景 2.解决思路 2.1.查看对象有哪些属性或方法 2.1.1.dir()函数 2.1.2.help命令 ...

  2. vue 拷贝 数组_vue源码中值得学习的方法

    最近在深入研究vue源码,把学习过程中,看到的一些好玩的的函数方法收集起来做分享,希望对大家对深入学习js有所帮助.如果大家都能一眼看懂这些函数,说明技术还是不错的哦. 1. 数据类型判断 Objec ...

  3. WebRTC源码中turnserver的使用方法

    WebRTC的源码中自带了一个turnserver,编译之后,会在out/Default下生成一个turnserver文件,可以充当STUN和TURN server.用法如下: ./turnserve ...

  4. android 静态工厂方法,Android 源码中的静态工厂方法

    我们知道工厂模式有三兄弟,通常我们说的工厂模式指的是工厂方法模式,它的应用频率最高.本篇博客分享的简单工厂模式是工厂方法模式的"小弟",确切的来讲它不属于设计模式,而是一种方法.此 ...

  5. Google 源码中电池百分比获取方法和格式转换

    Google 源码的电池百分比获取和转换 package com.android.settingslib;public class Utils {/** Formats a double from 0 ...

  6. android源码中常用的Rect方法

    inset dirty.inset(-1, -1); 缩小还是扩大矩形.如果为正值,则是缩,反之就是扩. dx:左边及右边 dy:上边及下边 offset dirty.offset(0, -mCurS ...

  7. vue操作dom_vue源码全面解析(四十六)源码中操作DOM的方法集合

    // 查找节点是否存在,如果不存在新建一个div元素返回function query (el) { if (typeof el === 'string') { var selected = docum ...

  8. ABP框架源码中的Linq扩展方法

    文件目录:aspnetboilerplate-dev\aspnetboilerplate-dev\src\Abp\Collections\Extensions\EnumerableExtensions ...

  9. 增加数组下标_数组以及ArrayList源码解析

    点击上方"码之初"关注,···选择"设为星标" 与精品技术文章不期而遇 前言 前一篇我们对数据结构有了个整体的概念上的了解,没看过的小伙伴们可以看我的上篇文章: ...

最新文章

  1. Redis 生产架构选型解决方案
  2. 二极管7种应用电路详解之二
  3. pta段错误怎么办_雅思50问 | 07:雅思写作时间不够怎么办?写不完会给分吗?...
  4. sleep方法和wait方法的区别
  5. 简单而又不平凡的杨辉三角形
  6. 五问唐骏:泡妞真的如你说的那么容易?
  7. 运放组成的吉他放大电路_如何通过5个步骤构建开放式硬件吉他放大器
  8. 林超贤携彭于晏带《紧急救援》再度征战2020春节档
  9. 可以分屏的软件_Screen分屏软件下载|Screen+专业分屏 免费版v1.4.25 下载
  10. datatable更新到mysql_.NET_使用DataTable更新数据库(增,删,改),1、修改数据复制代码 代码如 - phpStudy...
  11. 【CometOJ】CometOJ#8 解题报告
  12. Team Project 设想 -- 基于用户信息的学术搜索
  13. SNMP协议-SNMP TRAP
  14. 计算机二级等级考试ms office用什么软件练习好?
  15. 第二天:TypeScript的InterFace接口、类、修饰符、抽象类、implements
  16. 2020阿里云服务器免费领取与互联教程
  17. 考研词汇 用语言记忆
  18. 麦芽糖-刀豆球蛋白A,maltose-ConcanavalinA,刀豆球蛋白A-PEG-麦芽糖
  19. Activity生命周期的三种状态
  20. MAP(maximum a posteriori)

热门文章

  1. 汇编语言STD CLD的用法
  2. 【WIFI】WIFI-HT的意思
  3. 如何用html弄出抽奖的网页,用JS实现简单的网页抽奖
  4. 提供数据仓储搬迁服务 GoogleBigQuery实作的成本
  5. 小菜鸟的python学习之路(3)
  6. 彻底明白Hadoop map和reduce的个数决定因素
  7. 麻将算法(七)胡牌之对子判断
  8. 机器学习---聚类算法
  9. bigquant量化平台数据精准吗?
  10. FastDFS布式文件系统仿抖音小视频实现