当前位置: 首页 > news >正文

ArrayList集合源码解读(二)已完结

ArrayList集合源码解读(二)

前言

这篇文章已经把 ArrayList 更完了。各位还想看什么源码可以私信我~~
上节课带大家阅读了 ArrayList 中的核心扩容代码,那么今天带大家阅读下List集合中我们常用的几个方法的底层实现逻辑!

常用方法解读

笔者为大家讲解list 集合类中常用的几种操作,咱们一起看看他们的底层源码是如何实现的。

大家要区分set()add()的区别,不要弄混了。

  • int size()返回此列表中的元素数。

  • boolean isEmpty()如果此列表为空,则返回 true 。

  • boolean contains(Object o)如果此列表包含指定的元素,则返回 true 。

  • int lastIndexOf(Object o)返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回 -1。

  • E get(int index)返回此列表中指定位置的元素。

  • E set(int index, E element)用指定的元素替换此列表中指定位置的元素。

  • boolean add(E e)将指定的元素追加到此列表的末尾。

  • void add(int index, E element) 在此列表中的指定位置插入指定的元素。

  • E remove(int index)删除该列表中指定位置的元素。 将任何后续元素向左移动一位(从其索引中减去一个元素)。

源码:

// 返回此列表中的元素个数 
public int size() {return size;}// ------------------------------------// 如果集合为空,返回 truepublic boolean isEmpty() {return size == 0;}// ------------------------------------/**
* 如果此列表包含指定元素,则返回true。更正式地说,当且仅当此列表包含至少一个元素value,使得Objects. 
* equals(o,value)时,返回true
*
* @param value 要测试其是否在此列表中的元素
* @return 如果此列表包含指定元素,返回true
*/
public boolean contains(Object value) {// contains 方法底层调用的是 indexOf(Object o) 中的 indexOfRange(Object o, int s, int e)return indexOf(value) >= 0;
}// 底层方法实现
public int indexOf(Object o) {// 向下调用 indexOfRange() 方法,传入三个参数:需要查找的元素  查找起始索引  查找结束索引return indexOfRange(o, 0, size);
}// 真正实现逻辑的方法
int indexOfRange(Object o, int start, int end) {// 1.获取当前集合中的元素  (ArrayList 底层是使用 Object[] 存储元素数据的)Object[] es = elementData;// 2.如果待查找的元素 o 为 null,则从 start 起始索引开始遍历到 end 结束索引,找到第一个等于 null 的元素后返回其索引值if (o == null) {for (int i = start; i < end; i++) {if (es[i] == null) {return i;}}} else {// 3.如果待查找的元素 o 不为 null,则则从 start 起始索引开始遍历到 end 结束索引,找到第一个等于 o 的元素后返回其索引值for (int i = start; i < end; i++) {if (o.equals(es[i])) {return i;}}}// 没找到的情况,返回 -1return -1;
}// ------------------------------------// 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回 -1。
public int lastIndexOf(Object o) {// 底层调用lastIndexOfRange() 来实现,传入三个参数:待查找的元素值 o,起始索引,结束索引return lastIndexOfRange(o, 0, size);
}// 底层真正实现逻辑的方法
// 其实和上方的 indexOfRange() 方法类似,唯一变化的就是:
// indexOfRange() 是从开始索引遍历到结束索引;而 lastIndexOfRange() 是从结束索引倒序遍历。
int lastIndexOfRange(Object o, int start, int end) {Object[] es = elementData;if (o == null) {// 倒序遍历数组元素for (int i = end - 1; i >= start; i--) {if (es[i] == null) {return i;}}} else {// 倒序遍历数组元素for (int i = end - 1; i >= start; i--) {if (o.equals(es[i])) {return i;}}}return -1;
}// ------------------------------------/**
* 返回此列表中指定位置的元素。
*
* @param  index 要返回的元素的索引
* @return 此列表中指定位置的元素
* @throws IndexOutOfBoundsException 如果索引超出范围(索引<0||索引>=size())
*/
public E get(int index) {// 检查索引是否合法  如果 index < 0 || index >= size 那么抛出异常  (size 是集合中的元素个数)Objects.checkIndex(index, size);// 底层调用 elementData(int index) 方法实现return elementData(index);
}// 底层真正实现逻辑的方法
@SuppressWarnings("unchecked")  // @SuppressWarnings() 注解的作用是让编译器忽略检查,不要飘黄线
E elementData(int index) {// 直接返回当前索引对应的元素return (E) elementData[index];
}// ------------------------------------/**
* 将此列表中指定位置的元素替换为指定元素。
*
* @param index 要替换的元素的索引
* @param element 要存储在指定位置的元素
* @return 先前位于指定位置的元素
* @throws IndexOutOfBoundsException 如果索引超出范围(索引<0||索引>=size())
*/public E set(int index, E element) {// 检查索引是否合法  如果 index < 0 || index >= size 那么抛出异常  (size 是集合中的元素个数)Objects.checkIndex(index, size);// 获取指定索引的元素,上面有调用,此次不重复讲解// 因为要返回原先处于该位置的元素,所以需要先用个变量保存E oldValue = elementData(index);// 替换掉旧元素elementData[index] = element;return oldValue;}// ------------------------------------/**
* 在此列表中的指定位置插入指定的元素。
* 先调用 rangeCheckForAdd 对index进行界限检查;然后调用 grow 方法保证 capacity  足够大;
* 再将从index开始之后的所有成员后移一个位置;将element插入index位置;最后size加1。
*/public void add(int index, E element) {// 检查索引是否合法 rangeCheckForAdd(index);// 版本号 +1// 此列表在结构上被修改的次数。结构修改是指改变列表大小的修改,或者以其他方式扰乱列表,使得正在进行的迭代可能会产生不正确的结果。modCount++;final int s;Object[] elementData;// 这句话的意思是 首先将 size 的值赋值给局部变量 s,再将数组底层存储数据的 Object[] elementData  赋值给局部变量 elementData。最好判断他们的长度是否一样if ((s = size) == (elementData = this.elementData).length) {// 扩容的核心方法 grow()  上面有讲,此处不再过多陈述elementData = grow();}// System.arraycopy() 数组拷贝方法很重要!!// 第一个参数是要复制的数组 a1// 第二个参数是从a1的哪个索引开始赋值// 第三个参数是要复制到哪个数组 a2// 第四个参数是从 a2 这个数组的哪个索引开始覆盖// 第五个参数是指复制多少个元素System.arraycopy(elementData, index,elementData, index + 1,s - index);elementData[index] = element;size = s + 1;}// 判断索引是否符合规则  
// 和上方的 Objects.checkIndex() 方法的区别在于:
// rangeCheckForAdd() 方法判断的区间是 index < 0 || index > size
// checkIndex() 方法判断的区间是 index < 0 || index >= sizeprivate void rangeCheckForAdd(int index) {if (index > size || index < 0)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}
http://www.lryc.cn/news/418906.html

相关文章:

  • 光伏逆变器、MPPT、PCS储能变流器、BMU、BCU、BDU和液冷机组
  • OpenHarmony编译
  • C语言典型例题30
  • springMVC @RestControllerAdvice注解使用方式
  • HarmonyOS鸿蒙开发岗位面试中关于组件的问题总结
  • Unity 在Editor下保存对Text组件的文本的修改
  • mysql 日志爆满,删除日志文件,定时清理日志
  • MySQL学习(19):锁
  • 【出海日记】关于 KD ,数据工具的陷阱
  • 【k8s集群部署篇】在openEuler环境下部署多master高可用kubernetes集群详细教程(V1.30版本)
  • 数据结构:链表经典算法OJ题
  • 【线性代数】【二】2.2 极大线性无关组与向量空间的基
  • OD C卷 - CPU算力分配
  • matlab实现红绿灯识别
  • base64 转 pdf
  • vue2项目微信小程序的tabs切换效果
  • WPF动画的使用
  • 跑腿代购app系统源码开发及功能分析
  • mysql数据库:字符串函数
  • C语言实现游戏2048(超详细!!!超易懂!!!)
  • MATLAB代码检查工具PolySpace
  • FPGA设计之跨时钟域(CDC)设计篇(5)----同步FIFO的两种设计方法(计数器法/高位扩展法 | 手撕代码)
  • 快速掌握Vue:基础命令详解
  • MySQL——索引(二)创建索引(1)创建表的时候创建索引
  • 源代码加密怎么做?企业常用十款源代码加密软件排行榜
  • python 文件打开、读、关闭练习
  • 迈向大规模小目标检测:综述与数据集
  • 69、zabbix自动、代理、snmp监控
  • 搜索引擎设计:如何避免大海捞针般的信息搜索
  • 设计模式- 数据源架构模式