20220929-ArrayList扩容机制源码分析
示例代码
public class ArrayListSource {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();  //跳转至第一步
        for (int i = 0; i < 10; i++) {
            arrayList.add(i);  //需要进行第一次扩容,跳转至第二步
        }
        for (int i = 11; i <= 15; i++) {
            arrayList.add(i);  //需要进行第二次扩容
        }
        arrayList.add(100);  //需要进行第三次扩容
        arrayList.add(200);
        arrayList.add(300);
    }
}
代码分析
第一步:
当使用new ArrayList()创建集合时,会调用ArrayList类的无参构造器,在集合内部存在一个空的elementData数组,代码如下
private static final int DEFAULT_CAPACITY = 10;  //默认容量
...
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};  //默认空数组
...
transient Object[] elementData;  //存放Object对象的数组
...
private int size;  //集合中所包含的元素,默认为0
...
protected transient int modCount = 0;
...
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;  //MAX_ARRAY_SIZE = 2147483639
...
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;  //elementData初始化为{}数组,其中size=0
}
第二步:
程序进入for循环,从i=0开始,执行arrayList.add(i)方法,进入ArrayList类中
public boolean add(E e) {  //此时:e=1
        ensureCapacityInternal(size + 1);  //跳转至第三步
        elementData[size++] = e;
        return true;
}
第三步:
执行ensureCapacityInternal(size + 1),其中size=0
private void ensureCapacityInternal(int minCapacity) {  //此时minCapacity=size+1=1,即给集合中添加1个元素,需要的最小容量是1
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));  //跳转至第四步
}
第四步:
先执行ensureExplicitCapacity()中的嵌套函数calculateCapacity(elementData, minCapacity)
// elementData = {}
// minCapacity = 1
// DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
// DEFAULT_CAPACITY = 10
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {  //此if语句成立
            return Math.max(DEFAULT_CAPACITY, minCapacity);  //返回值为10,退出函数,跳转至第五步,
        }
        return minCapacity;
}
第五步:
执行ensureExplicitCapacity()函数
// minCapacity = 10
// modCount默认为0,然后自加1
// elementData.length = 0
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)  //此时if语句成立
            grow(minCapacity);  //跳转至第六步
}
第六步:
执行grow(minCapacity)
// minCapacity = 10
// MAX_ARRAY_SIZE = 2147483639
private void grow(int minCapacity) {
        int oldCapacity = elementData.length; //oldCapacity=0
        int newCapacity = oldCapacity + (oldCapacity >> 1);  //newCapacity=0+0/2=0
        if (newCapacity - minCapacity < 0)  //此if语句成立
            newCapacity = minCapacity;  //newCapacity = 10
        if (newCapacity - MAX_ARRAY_SIZE > 0)  //此if语句不成立
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
        //此语句执行后,elementData = {null,null,null,null,null,null,null,null,null,null}
}
第七步:
当程序执行完第六步之后,根据方法调用步骤依次返回,直至第二步的第2条程序语句
public boolean add(E e) {//此时:e=1
        ensureCapacityInternal(size + 1);
        //通过以上方法,确保集合中可以存放e对象
        elementData[size++] = e;//此时size=0,之后自加1;e=1
        //执行之后 elementData = {1,null,null,null,null,null,null,null,null,null}
        return true;
}
第八步:
在for循环中,不断执行 arrayList.add(i)方法,直到for循环结束,以上步骤介绍了ArrayList第一次默认初始化之后存放元素的步骤和扩容机制,当集合中存放的对象达到容量10时,集合需要再次进行扩容。而接下来的每次扩容的容量=原来容量*1.5,即 0 --> 10 --> 15 --> 22 --> 33...
20220929-ArrayList扩容机制源码分析的更多相关文章
- JAVA ArrayList集合底层源码分析
		目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ... 
- Android事件分发机制源码分析
		Android事件分发机制源码分析 Android事件分发机制源码分析 Part1事件来源以及传递顺序 Activity分发事件源码 PhoneWindow分发事件源码 小结 Part2ViewGro ... 
- ArrayList详解-源码分析
		ArrayList详解-源码分析 1. 概述 在平时的开发中,用到最多的集合应该就是ArrayList了,本篇文章将结合源代码来学习ArrayList. ArrayList是基于数组实现的集合列表 支 ... 
- Springboot学习04-默认错误页面加载机制源码分析
		Springboot学习04-默认错误页面加载机制源码分析 前沿 希望通过本文的学习,对错误页面的加载机制有这更神的理解 正文 1-Springboot错误页面展示 2-Springboot默认错误处 ... 
- ApplicationEvent事件机制源码分析
		<spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ... 
- 2.8.2 并发下的ArrayList,以及源码分析
		package 第二章.并发下的ArrayList; import java.util.ArrayList;import java.util.List; /** * Created by zzq on ... 
- Android查缺补漏(View篇)--事件分发机制源码分析
		在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 <Android查缺补漏(View篇)-- ... 
- ArrayList 和 LinkedList 源码分析
		List 表示的就是线性表,是具有相同特性的数据元素的有限序列.它主要有两种存储结构,顺序存储和链式存储,分别对应着 ArrayList 和 LinkedList 的实现,接下来以 jdk7 代码为例 ... 
- List中的ArrayList和LinkedList源码分析
		 List是在面试中经常会问的一点,在我们面试中知道的仅仅是List是单列集合Collection下的一个实现类, List的实现接口又有几个,一个是ArrayList,还有一个是LinkedLis ... 
随机推荐
- Wpf 多指应用开发解析
			1 首先分析多指事件与单指事件,以及执行顺序 2 事件阻断 订阅多指事件后,在TouchDown时 采用e.handle = true,阻断多指事件,或在ManipulationStarting. ... 
- Linux(Centos7) 实例搭建 FTP 服务
			本文以 CentOS 7.2 64位系统为例,使用 vsftpd 作为 FTP 服务端,FileZilla 作为客户端.指导您如何在 Linux 云服务器上搭建 FTP 服务. 操作步骤 安装 vsf ... 
- SPFA算法(SLF优化)2022.7.8更新
			SPFA可能会被卡掉,能用dijkstra就别用SPFA,代码较长,但我已尽力做到解释,请耐心看下去,存储为邻接表存储. #include<bits/stdc++.h> #define i ... 
- nodejs学习总结02
			response对象常用的API #response对象 response 对象类型<http.ServerResponse> response对象常用成员:response.write ... 
- SElinux管理
			SElinux: 是Linux的一个强制访问控制的安全模块 SElinux的相关概念: 对象:文件.目录.进程.端口等 主体:进程称为主体 SElinux将所有的文件都赋予一个type类型的标签,所有 ... 
- SQL注入 基础学习
			SQL注入学习笔记 注入原理 SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有 ... 
- MySQL数据库的创建和基本的查询语句
			数据库的定义 数据库是按照数据结构来组织.存储和管理数据的建立在计算机存储设备上的仓库 分类 非结构化数据: 数据相对来说没有固定的特点 半结构化数据: 数据之间有着相同的存储结构 属性 值 每一条数 ... 
- 【docker专栏8】使用IDEA远程管理docker镜像及容器服务
			使用命令行的方式管理服务器镜像及容器是运维人员最常用的方式,但是有的时候我们不得不远程操作docker或者是面向对docker并不熟悉的技术人员提供能力(配置管理员.测试人员),这种情况下图形界面就有 ... 
- Luogu3594 [POI2015]WIL-Wilcze doły (双端队列)
			单调性显然,双端队列队列维护严格单调递减手写双端队列真的可恶. #include <iostream> #include <cstdio> #include <cstri ... 
- Digester解析xml原理
			Tomcat内部是使用Digester来解析xml文件的,将xml转化为java对象. digester底层是基于SAX+事件驱动+栈的方式来搭建实现的,SAX主要用来解析xml,事件驱动主要是在解析 ... 
