ArrayList

  1. 特点:按添加顺序排列、可重复、非线程安全;
  2. 底层实现:数组
  3. 扩容原理:初始化集合时,默认容量为 0,第一次添加元素时扩容为 10,容量不够时扩容为原来容量的 1.5 倍。

这里扩容指的是无参构造初始化时的场景。对于指定集合长度的构造函数初始化时,初始容量为指定长度,容量不够时再扩容为原来的 1.5 倍。

下面主要介绍无参构造初始化时的场景。

初始化-构造函数

参数定义:

transient Object[] elementData; // 实际存储数据的数组缓冲区

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 初始数组

默认初始化非常简单,调用无参构造器,初始化一个空数组。真正扩容的逻辑在每次添加元素执行。

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

添加元素-扩容

添加方法:

public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

size:ArrayList 的长度,可用 List#size() 获取

添加方法一共做了两件事:

  1. 判断数组容量是否足够,不够则给数组扩容;
  2. 向数组中添加指定的元素;

添加元素不用多说,向数组中的下一个位置插入即可。下面着重介绍容量判断的逻辑:

1. 判断容量大小

首先判断当前集合容量大小是否足够,如果不够就调用扩容方法 grow(int minCapacity)。

// 确保集合可以添加下一个元素 minCapacity:当前需要的最小容量
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
} // 计算添加元素需要的最小容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 如果当前集合为空,判断所需最小容量和默认容量大小,返回较大值
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
} // 确保集合可以满足需要的最小容量
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

2. 扩容方法

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);
}
  1. 旧容量为当前数组长度;
  2. 新容量为旧容量的 1.5 倍;(此处通过位运算计算,右移1位相当于除以 2,再加原来值即扩大1.5倍)
  3. 如果新容量小于所需最小容量,则将新容量赋值为所需最小容量;(这里主要执行场景为集合初始化时,旧容量为0,新容量扩大1.5倍后也为0,这时新容量将被赋值为默认容量 10)
  4. 如果新容量超过最大数组大小(int 最大值 - 8),这时会报内存溢出 或扩容为 int 的最大取值。
  5. 最后将原来数组数据复制到扩容到新容量大小的数组中。

添加元素-实际流程

首先初始化一个 ArrayList,向里面循环添加 11 个元素。下面针对于第一次添加和第11次添加分别查看 数组初始化 和 数组扩容的逻辑。

public static void main(String[] args) {
List<string> list = new ArrayList<>(); for (int i = 0; i < 11; i++) {
list.add("items");
}
}

数组初始化

ArrayList 初始化后,底层会初始化一个空的对象数组 (elementData),长度 (size) 为 0。当第一次添加元素时,会将其初始化为一个长度为 10 的数组。下面看第一次添加元素的流程:

1.进入添加方法 add(E e)

2.判断容量大小

3.计算所需最小容量

当前数组为空数组,所以if 条件成立,DEFAULT_CAPACITY = 10,minCapacity = 1;

当前方法返回 10;

4.判断数组是否扩容

elementData 当前为空数组,length = 0;minCapacity 为上一步返回的 10;所以此处会调用扩容方法 grow()

5.数组扩容(初始化数组)

这里会根据上面指定的默认容量 10 来给数组扩容。

  • oldCapacity = 0;
  • newCapacity = 0;
  • newCapacity = 10;
  • elementData 扩容为容量为10 的新数组

6.添加元素

  • elementData[0] = items
  • size++ = 1;

数组扩容

根据之前程序的运行,集合保存数据的数组在第一次添加元素时扩充容量为 10,所以在第 11 次添加元素时就会调用扩容的逻辑。

1、add() 方法

minCapacity = size + 1 = 11;

2、判断容量大小

3、计算所需最小容量

​ 非第一次 直接返回

4、判断是否扩容

所需最小容量大于数组长度,调用扩容方法。

5、扩容

  • oldCapatity = 10;
  • newCapatity = 15;
  • 拷贝数组内容到一个 容量为 15 的数组中,完成扩容

6、添加元素

  • elementData[10] = e;
  • size ++ = 11;

ArrayList 深入浅出的更多相关文章

  1. Java容器深入浅出之List、ListIterator和ArrayList

    List是Collection接口的子接口,表示的是一种有序的.可重复元素的集合. List接口的主要实现类ArrayList和Vector,底层都是维护了一套动态的,可扩展长度的Object[]数组 ...

  2. 深入浅出!阿里P7架构师带你分析ArrayList集合源码,建议是先收藏再看!

    ArrayList简介 ArrayList 是 Java 集合框架中比较常用的数据结构了.ArrayList是可以动态增长和缩减的索引序列,内部封装了一个动态再分配的Object[]数组 这里我们可以 ...

  3. 深入浅出Struts2+Spring+Hibernate框架

    一.深入浅出Struts2 什么是Struts2? struts2是一种基于MVC的轻量级的WEB应用框架.有了这个框架我们就可以在这个框架的基础上做起,这样就大大的提高了我们的开发效率和质量,为公司 ...

  4. 计算机程序的思维逻辑 (38) - 剖析ArrayList

    从本节开始,我们探讨Java中的容器类,所谓容器,顾名思义就是容纳其他数据的,计算机课程中有一门课叫数据结构,可以粗略对应于Java中的容器类,我们不会介绍所有数据结构的内容,但会介绍Java中的主要 ...

  5. 深入浅出Mybatis系列(四)---配置详解之typeAliases别名(mybatis源码篇)

    上篇文章<深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)> 介绍了properties与environments, ...

  6. Scala 深入浅出实战经典 第49课 Scala中Variance代码实战(协变)

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  7. Java编程的逻辑 (38) - 剖析ArrayList

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  8. ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借

    ASP.NET MVC深入浅出系列(持续更新)   一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...

  9. WPF学习之深入浅出话模板

    图形用户界面应用程序较之控制台界面应用程序最大的好处就是界面友好.数据显示直观.CUI程序中数据只能以文本的形式线性显示,GUI程序则允许数据以文本.列表.图形等多种形式立体显示. 用户体验在GUI程 ...

随机推荐

  1. 激光雷达Lidar Architecture and Lidar Design(下)

    Considerations on Lidar Design 双基地还是单基地? 双轴还是同轴? 几何重叠 向上还是向下看? 关心分散还是只关心时间? 发射器和接收器的波长 是否可调? 发射器和接收器 ...

  2. Imec推出高性能芯片的低成本冷却解决方案

    Imec推出高性能芯片的低成本冷却解决方案 Imec unveils low-cost cooling solution for high-performance chips 3D打印冷却器优于传统解 ...

  3. C#后台定义一个DataTable并手动写入静态数据(测试数据)

    //创建一个DataTable,并为之添加数据(自定义DataTable) DataTable dtz = new DataTable(); //添加Table中的列 DataColumn dc1 = ...

  4. 孟老板 BaseAdapter封装 (一) 简单封装

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  5. JUC 并发编程--04 常用的辅助类CountDownLatch , CyclicBarrier , Semaphore , 读写锁 , 阻塞队列,CompletableFuture(异步回调)

    CountDownLatch 相当于一个减法计数器, 构造方法指定一个数字,比如6, 一个线程执行一次,这个数字减1, 当变为0 的时候, await()方法,才开始往下执行,, 看这个例子 Cycl ...

  6. 尚硅谷Java——宋红康笔记【day19-day24】

    day19 测试Thread中的常用方法: start():启动当前线程:调用当前线程的run() run(): 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中 curr ...

  7. 【SQLite】教程08-SQLite可视化工具

    推荐使用"SQLiteStudio" 下载地址:http://www.downza.cn/soft/208363.html 设为中文的方法: 最后重启软件即可!

  8. Django基础之视图层

    内容概要 小白必会三板斧 request对象方法初识 form表单上传文件 Jsonresponse FBV与CBV 内容详细 1 小白必会三板斧 HttpResponse render redire ...

  9. spring + spring mvc + tomcat 面试题(史上最全)

    文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...

  10. AJAX异步原理与实现

    面试时问到了这个问题,说实话我还是不理解的,只是单单会使用.所以今天我看一下,自己了解下. 看了网上前辈们写的资料,我自己总结归纳ajax的原理和流程如下: 1.AJAX创建异步对象XMLHttpRe ...