1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 奥莉嘎!!!ArrayList源码中remove removeAll clear方法我又肝了一遍 收获良多

奥莉嘎!!!ArrayList源码中remove removeAll clear方法我又肝了一遍 收获良多

时间:2021-09-04 16:55:27

相关推荐

奥莉嘎!!!ArrayList源码中remove removeAll clear方法我又肝了一遍 收获良多

前言

点赞在看,养成习惯。

点赞收藏,人生辉煌。

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

看源码血泪史

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

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

其实看了ArrayList的源码以后,你会发现能说的点还是有很多的。

比如ArrayList的构造方法的底层数组真的是构造了一个长度为10的数组吗?

Arrays.copy方法,grow扩容方法是怎么扩容的?等等都可以细说。

ArrayList的源码从工作到现在大概看了不下10遍,这其中包括看了半道放弃的。

刚开始看源码是在一些博客网站上看,看的稀里糊涂不是很明白,越看越想放弃。

后面看了一些公开课,跟着老师讲的视频看源码,看完之后感觉有点意思。但是看完之后,自己单独看还是有点吃力。

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) 根据索引删除元素

案例演示

@Testpublic 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) 根据元素删除元素

案例演示

@Testpublic 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()将集合清空

案例演示

@Testpublic 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)删除与给定集合中相同的元素

案例演示

@Testpublic 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;}

创作不易, 非常欢迎大家的点赞、评论和关注(^_−)☆

你的点赞、评论以及关注是对我最大的支持和鼓励,而你的支持和鼓励

我继续创作高质量博客的动力 !!!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。