ArrayList继承了AbstractList,实现了List接口,底层实现基于数组,因此可以认为是一个可变长度的数组。

ArrayList扩容的本质就是计算出新的扩容数组的size后实例化,并将原有数组内容复制到新数组中去

ArrayList 部分源码

 /*** 默认初始容量*/private static final int DEFAULT_CAPACITY = 10;/*** 定义一个空数组以供使用*/private static final Object[] EMPTY_ELEMENTDATA = {};/*** 也是一个空数组,构造无参构造方法时用到*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** 存放数组中的元素,transient修饰,不被序列化*/transient Object[] elementData; // non-private to simplify nested class access/*** 表示数组中所包含实际元素的个数,和elementData.length不同*/private int size;/*** 记录list被修改的次数*/protected transient int modCount = 0;/*** 分配数组的最大大小,(有些虚拟机在数组中保留一些头词,如果 分配更大的数组可能导致 OutOfMemoryError:请求的数组大小超过虚拟机限制 )*/private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;/*** 无参构造函数,返回空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA*/public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}/*** 有参构造函数,构造一个具有指定初始容量的空list,initialCapacity = 0 时 ,返回空数组EMPTY_ELEMENTDATA,与无参构造返回的 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 不同* @param initialCapacity*/public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}/*** 有参构造函数,构造包含指定元素的list* @param c*/public ArrayList(Collection<? extends E> c) {//将传入的集合转为数组elementData = c.toArray();if ((size = elementData.length) != 0) {// c.toArray可能(不正确地)不返回Object[]   (see 6260652)if (elementData.getClass() != Object[].class)//通过Arrays.copyOf方法把集合中的元素拷贝到elementData中elementData = Arrays.copyOf(elementData, size, Object[].class);} else {// replace with empty array.this.elementData = EMPTY_ELEMENTDATA;}}/*** 将指定元素追加到列表末尾* @param e* @return*/public boolean add(E e) {int i =0;//size + 1  把数组实际长度加1,以确保能保持下下一个数据ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;}/*** 将指定元素插入到指定的位置* 将当前元素移动到该位置(如果有的话),并 移动右边的后续元素(在它们的下标上加1)* @param index* @param element*/public void add(int index, E element) {rangeCheckForAdd(index);ensureCapacityInternal(size + 1);  // Increments modCount!!System.arraycopy(elementData, index, elementData, index + 1,size - index);elementData[index] = element;size++;}/*** minCapacity = size + 1* @param minCapacity*/private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}/*** 计算容器大小* 如果是调用了无参构造返回的空数组(DEFAULTCAPACITY_EMPTY_ELEMENTDATA),* 则返回 默认初始容量(DEFAULT_CAPACITY=10) 和 minCapacity = size+1  中的最大值 ,由于第一次调用 size=0,故此时返回 10;* 否则返回 minCapacity = size+1,注意只有第一次调用add时,才返回 1,此后的调用需要根据实际的数组长度size+1* @return*/private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;}/*** 判断是否需要调用扩容方法* 1. 如果 new ArrayList 时 给定了长度(长度 > 0),即调用有参构造 ,那elementData.length 就是 传入的长度,*    而第一次调用add 时,由于size=0, 所以 minCapacity = size +1 = 1, 故 不需要调用 扩容函数* 2. 如果 new ArrayList 时 没有给定了长度,即调用无参构造,返回的空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA ,*    那 elementData.length = 0 , 则满足条件,需要调用扩容方法* @param minCapacity*/private void ensureExplicitCapacity(int minCapacity) {modCount++;//如果minCapacity > elementData.length ,即 当前数组实际长度 大于 数组容量时 ,调用扩容方法 grow()if (minCapacity - elementData.length > 0)grow(minCapacity);}/*** 扩容方法* @param minCapacity*/private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length; //原来的容量// 新容量 = 原容量右移一位+原容量 = 原容量*1.5int newCapacity = oldCapacity + (oldCapacity >> 1);//若新容量 < 数组实际长度+1 , 则 直接让 数据实际长度+1 为新容量if (newCapacity - minCapacity < 0)newCapacity = minCapacity;//如果新容量 大于 分配数组的最大大小if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// 通过Arrays.copyOf方法把原数组的内容放到更大容量的数组里面elementData = Arrays.copyOf(elementData, newCapacity);}//如果数据实际长度+1 大于 分配数组的最大大小, 则返回 最大整数,否则 返回  分配数组的最大大小private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;}

假如我们放入11个值,那ArrayList的扩容过程是怎样?

ArrayList 初始化 elementData 数组长度为0,放入第一个值的时候,elementData 是 DEFAULTCAPACITY_EMPTY_ELEMENTDATA,所以第一次扩容是DEFAULT_CAPACITY,也就是10,所以当前elementData数组长度是10, 然后放入11个值,所需数组长度是12, 大于elementData 数组长度10,需要扩容,第二次扩容是按当前数组长度的一半,也就是5,所以扩容长度是15,15比所需长度12大,满足条件进行扩容,所以elementData 数组长度是15

总结:
调用add()方法 时 扩容步骤:

  1. 如果 放入的值个数小于10个,那 数组容量就是10;
  2. 如果 放入的值个数 大于10个 ,小于 15 个 ,则 容量为 10*1.5 = 15 ;
  3. 如果 放入的值 个数大于15 个,小于 22 个,则容量为 15*1.5 = 22
  4. ·····以此类推,每次递增到 原数组容量的1.5倍

ArrayList扩容机制相关推荐

  1. 【面试必备】透过源码角度一步一步带你分析 ArrayList 扩容机制

    该文已加入开源文档:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识).地址:https://github.com/Snailclimb/JavaGuide. 一 先从 Array ...

  2. Java集合框架:ArrayList扩容机制解释

    1.java中ArrayList该类的定义 public class ArrayList<E> extends AbstractList<E>implements List&l ...

  3. 在JDK1.8中,ArrayList扩容机制Increments modCount与起始化讲解

    在ArrayList中,起始化方式有两种: 1.调用无参的构造方法: public ArrayList() { //无参构造方法this.elementData = DEFAULTCAPACITY_E ...

  4. ArrayList扩容机制解析

    1.ArrayList的成员变量 首先我们先了解一下ArrayList的成员变量. // 默认初始化大小 private static final int DEFAULT_CAPACITY = 10; ...

  5. ArrayList扩容机制源码分析

    1.先看一下ArrayList的构造方法 1-1:空参构造方法: private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = { ...

  6. arraylist扩容是创建新数组吗 java_arraylist扩容机制要怎么实现?arraylist怎么扩容...

    ArrayList大家都知道了吧,这是一个动态数组.以java语言来说,数组是定长的,在被创建之后就不能被加长或缩短了,因此,了解它的扩容机制对使用它尤为重要.下面,我们就一起来看看它的扩容机制是怎么 ...

  7. 说一说 ArrayList 的扩容机制

    ArrayList有三种方式来初始化,构造方法源码如下: /*** 默认初始容量大小*/private static final int DEFAULT_CAPACITY = 10;private s ...

  8. ArrayList源码扩容机制分析

    ArrayList源码&扩容机制分析 发上等愿,结中等缘,享下等福 文章目录 ArrayList源码&扩容机制分析 1. ArrayList 简介 1.1. Arraylist 和 V ...

  9. Java之List系列--ArrayList扩容的原理

    原文网址:Java之List系列--ArrayList扩容的原理_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Java的ArrayList是如何进行扩容的.即:扩容的机制. 重要大小 类 初 ...

  10. android动态扩容数组,ArrayList 扩容 Android Java 真的不一样

    以前学java基础的时候 看过ArrayList的扩容机制 实现原理是下面这样 当时做的笔记 ArrayList扩容机制 在jdk1.7前是 *3/2+1 在jdk1.7开始就是 old+(old&g ...

最新文章

  1. 决策树——CART和模型树
  2. 自学电脑编程_81岁老太自学编程开发APP,她的日常酷过95%年轻人
  3. VS-watch窗口
  4. TinkPad E40 CentOS 6.5 无线网卡驱动 RTL8191SEvB 安装
  5. python os.access_Python用access判断文件是否被占用的实例方法
  6. 怎么修改HTML中样式的项目序号,给Ol的序号设置样式,怎么做?
  7. Linux关机、开机、重启、定时重启、定时关机详细命令(shutdown命令)
  8. java commons math_Apache Commons Math
  9. html的取消和选中,checkbox 选中和取消切换问题
  10. 微信公众平台开发(2)--微信认证流程图文详解
  11. python语言的实验心得体会范文_实验报告心得体会范文3篇_心得体会
  12. 感谢网友,让我实现了Zbrush笔刷自由
  13. C进阶(2)指针的进阶(1)
  14. mysql数据存储过程添加数据_Mysql 存储过程 自动插入数据
  15. 天邑ty1208z海思3798刷版本_天邑TY1208Z海思3798芯片强刷安卓系统固件rom刷机包下载...
  16. 改善监控过程中逆光的方法
  17. IP化构建新型“路网系统” 工业互联网驶上快车道
  18. 阿里巴巴CEO张勇内部讲话:好的企业文化,要视人为人
  19. 2022中国济南国际养老服务业博览会
  20. 一款基于SpringBoot2.x, springcloud G版本的后台管理系统java源码—RuoYi-plus管理平台系统模板(商城、OA、CRM等二次开发)

热门文章

  1. jsp技术被淘汰了?那还要不要学它?
  2. springboot发送垃圾邮件
  3. STM32F407VET6+cubemx+FSMC+ST7789
  4. origin导出矢量图再编辑
  5. Cisco CCNP 帧中继网络教程
  6. STM32 HAL库 时钟芯片RX8025T IIC的读写操作,入过的坑
  7. 常见开发工具下载链接
  8. 华为vrrp默认优先级_华为vrrp配置实例
  9. 网站建设中做到需求分析细致,网站优化也就顺理成章了
  10. zoj1479 dweep soj1106 搜索