对于集合的源码分析,一般我会采用这几种方式

  1. 怎么添加元素?
  2. 怎么获取元素?
  3. 怎么删除元素?
  4. 内部数据结构实现?

话不多说,直接走起。

一.怎么添加元素?

一般我们通过ArrayList添加元素。一般会调用其构造方法,然后调用其对象的add方法

查看空参构造函数

//Constructs an empty list with an initial capacity of ten.public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
复制代码

通过构造函数可以发现。ArrayList在调用无参的构造函数时,会构造一个长度为10的缓存数组

查看add方法

public boolean add(E e) {ensureCapacityInternal(size + 1); elementData[size++] = e;return true;}
复制代码

通过该方法发现 ArralyList内部的数据结构其实是一个数组(elementData[size++] = e;)并且在添加时会先判断当前容器在添加了一个对象之后该对象的容纳能力(主要为了,在下一次添加元素的时候,缓存数组能够有足够的空间添加元素)。之后将元素添加到数组末尾。

继续查看ensureCapacityInternal()方法

    private void ensureCapacityInternal(int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);}
复制代码

这里我们发现,如果当前elementData为空的话,minCapacity=DEFAULT_CAPACITY,同时DEFAULT_CAPACITY的默认值是10,从这我们可以看出,在第一次初始化的时候,ArrayList内部会默认创建一个内部长度为10的数组。

继续点击ensureExplicitCapacity()方法

    private void ensureExplicitCapacity(int minCapacity) {modCount++;//判断添加元素后,缓存数组时候需要扩展if (minCapacity - elementData.length > 0)grow(minCapacity);}
复制代码

该方法会记录当前数组的更改次数,并且判断当前数组添加后,是否需要进行增长,

继续走grow方法(重点的来了!!!)

    private void grow(int minCapacity) {// overflow-conscious codeint 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);}
复制代码

该方法会扩展缓存为当前数组的长度为 原数组长度+原数组长度的二分之一,也就是按照原数组的50%进行增长,同时该数组最大的扩展长度是Integer.MAX_VALUE - 8。也就是ArrayList最多能存储的数据长度,通过扩展数组长度以后,在下一次添加数据的时候,ArrayList就有足够的空间去添加新的元素了。

二.怎么获取元素

其实ArrayList获取其中的元素很简单,根据角标获取对应数组中的元素,具体代码如下:

 public E get(int index) {if (index >= size)//判断当前角标长度是否超过数组长度,如果是抛出异常,反之返回数据throw new IndexOutOfBoundsException(outOfBoundsMsg(index));return (E) elementData[index];}复制代码

##三.怎么删除元素 在ArrayList中,有两个关于删除元素的方法,一个是remove(int),另一个是remove(Object)

1.remove(int)方法

public E remove(int index) {if (index >= size)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));modCount++;E oldValue = (E) elementData[index];int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // 将数组最后一位置nullreturn oldValue;}
复制代码

这里先判断删除角标是否超过数组长度,然后通过System.arrayCopty()方法将角标对应的元素删除。

这里对System.arrayCopty()方法解释一下。该方法的第一个参数是源数组,第二个参数是复制的开始角标,第二个参数是目标数组。第三个参数是目标数组源数组的复制数据开始角标。最后一个参数是复制的长度。(注意:!!!复制的长度不能大于目标数组减去开始角标的长度源数组减去开始角标的长度)

eg:

  int[] a = {0, 1, 2, 3, 4};int[] b = {5, 6, 7, 8, 9};System.arraycopy(a, 0, b, 1, 3);// 则进行操作后 b = {5,0,1,2,9}
复制代码

2.remove(Object)方法

 public boolean remove(Object o) {if (o == null) {//判断当前元素是否为空,遍历数组,获取其角标for (int index = 0; index < size; index++)if (elementData[index] == null) {fastRemove(index);return true;}} else {for (int index = 0; index < size; index++)if (o.equals(elementData[index])) {fastRemove(index);return true;}}return false;}private void fastRemove(int index) {//根据角标,删除相应元素modCount++;int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its work}
复制代码

remove(Object)根据object在数组的角标,执行fastRemove(index)方法。删除方法与remoIndex(int)一样。这里就不在分析了。

总结

  • ArrayList内部实现是数组,且当数组长度不够时,数组的会进行原数组长度的1.5倍扩容
  • ArrayList内部元素是可以重复的。且有序的,因为是按照数组一个一个进行添加的。
  • ArrayList是线程不安全的,因为其内部添加、删除、等操作,没有进行同步操作。
  • ArrayList增删元素速度较慢,因为内部实现是数组,每次操作都会对数组进行复制操作,复制操作是比较耗时的

最后,附上我写的一个基于Kotlin 仿开眼的项目SimpleEyes(ps: 其实在我之前,已经有很多小朋友开始仿这款应用了,但是我觉得要做就做好。所以我的项目和其他的人应该不同,不仅仅是简单的一个应用。但是,但是。但是。重要的话说三遍。还在开发阶段,不要打我),欢迎大家follow和start

ArrayList分析相关推荐

  1. Java 集合 —— ArrayList 分析

    List 集合的特征: 有序 可以重复 可以随机访问(使用下标 添加,删除,访问) ArrayList 是 List 的实现类,所以 ArrayList 具有 List 的特征 ArrayList 是 ...

  2. 【Java源码分析】LinkedList源码分析

    类的定义如下 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E ...

  3. java ArrayList 概述 与源码简析

    ArrayList 概述 与源码简析 1 ArrayList 创建 ArrayList<String> list = new ArrayList<>(); //构造一个初始容量 ...

  4. LL(1)文法构造FIRST、FOLLOW、分析表并分析

    一.实验目的 学生运用编译原理的知识在实验技能和方法自行设计实验方案并加以实现. 二.使用仪器.器材 计算机一台 操作系统:Windows10 编程软件:Intellij IDEA 三.实验内容及原理 ...

  5. java arraylist 方法返回值_返回arraylist方法

    ArrayList 什么是ArrayList 可以简单的认为是一个动态数组:实际上ArrayList就是用数组实现的,长度不够时,调用Arrays.copyOf方法,拷贝当前数组到一个新的长度更大的数 ...

  6. JAVA语言基础-面向对象(集合框架02List、泛型)

    2019独角兽企业重金招聘Python工程师标准>>> 16.01_集合框架(去除ArrayList中重复字符串元素方式)(掌握) A:案例演示 需求:ArrayList去除集合中字 ...

  7. List 的add()与addAll()的区别

    add 是将传入的参数作为当前List中的一个Item存储,即使你传入一个List也只会另当前的List增加1个元素 addAll 是传入一个List,将此List中的所有元素加入到当前List中,也 ...

  8. 记录一次app崩溃信息调试

    收到了崩溃信息,如下 *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 2022-01-28 18:33:21.183 1 ...

  9. 迪杰斯特拉(dijkstra)-两个地铁站最短距离

    文章目录 前言 Github 算法原理 类职责划分 Code Station&Result&DataBuilder 算法 应用场景 总结 作者 前言 最新更新了github.欢迎多评论 ...

最新文章

  1. ICCV 2017 《Chained Cascade Network for Object Detection》论文笔记
  2. 玩家为何沉迷于游戏?《密教模拟器》中的“上瘾体验”设计
  3. 机器学习日常练习——红楼梦作者分析(聚类)
  4. Mysql索引数据结构有多个选择,为什么一定要是B+树呢?_面试 (MySQL 索引为啥要选择 B+ 树)
  5. sublime c 语言 编译,默认情况下,将程序编译为Sublime Text 3中的c 14
  6. pycharm的terminal无法识别到命令 pytest 不是内部或外部命令,也不是可运行的程序 或批处理文件。
  7. idea2020新建一个jsp页面_有关idea2019版的jsp配置小教程
  8. 单机部署RabbltMQ环境的操作记录
  9. Excel如何批量插入删除复选框
  10. 2020年CSP-J2 CSP-S2 复赛题解
  11. 解这道考研题要用克莱默法则的公式吗?
  12. Aandroid最火的十大开源项目
  13. 安装webpack及使用
  14. Horizon安装和配置
  15. Xshell的快捷键(非常实用)
  16. FreeSwitch调试小技巧
  17. 为什么TCP套接字用四元组标识而UDP是二元组?
  18. OpenCV图像修复函数inpaint()
  19. PDF转Word提示页数太多转换失败怎么办?
  20. 计算机室规章制度英语作文,书面表达 英语作文 80字你的学校新建了一个阅览室,学校要制定一些阅览室的规章制度,根据下列提示写一篇英语作文 告诉同学...

热门文章

  1. [概统]本科二年级 概率论与数理统计 第三讲 离散型随机变量
  2. UA MATH564 概率论 QE练习题 信封问题
  3. UA MATH571A 多元线性回归II 变量选择
  4. Win32 GetWindowLong函数实例Demo
  5. 动态CSS - LESS学习总结
  6. dNet项目数据访问层代码总结
  7. jQuery基础 (一)—样式篇
  8. 快学Scala习题解答—第十章 特质
  9. 【转】InstantClient安装使用
  10. 制作iPhone App demo video