1.ArrayList的成员变量

首先我们先了解一下ArrayList的成员变量。

// 默认初始化大小
private static final int DEFAULT_CAPACITY = 10;// 空数组(用于空实例)
// 比如List<String> ls = new ArrayList<>(0);
private static final Object[] EMPTY_ELEMENTDATA = {};// 主要用来标识该ArrayList使用无参构造方法进行了初始化
// elementData等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA意味着使用无参构造函数进行了初始化
// 使用无参构造函数的默认容量是10,但是并不是一开始就进行了初始化,而是真正在插入元素的时候才进行了初始化
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};// 实际上保存ArrayList数据的数组
transient Object[] elementData; // non-private to simplify nested class access// ArrayList包含的元素个数
private int size;

2.ArrayList的构造方法

了解了基本成员变量以后我们再来看一下构造函数

// 有参构造方法,由自己进行容量的初始化
public ArrayList(int initialCapacity) {if (initialCapacity > 0) {// 初始化值大于0,创建initialCapacity大小的数组this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {// 初始化值等于0,则创建空数组this.elementData = EMPTY_ELEMENTDATA;} else {// 初始化值小于0,抛出异常throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}
}// DEFAULTCAPACITY_EMPTY_ELEMENTDATA为0.初始化为10
// 意味着ArrayList的初始其实是空数组,当添加第一个元素的时候数组容量才变成10
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}// 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
public ArrayList(Collection<? extends E> c) {elementData = c.toArray();if ((size = elementData.length) != 0) {// 如果elementData不是Object类型数据(c.toArray可能返回的不是Object类型的数组所以加上下面的语句用于判断)if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData, size, Object[].class);} else {this.elementData = EMPTY_ELEMENTDATA;}
}

3.ArrayList的扩容机制

下面正式开始讲解ArrayList的扩容机制。

什么时候开始扩容,毫无疑问,当然是添加元素,而elementData的容量不够的时候进行扩容,所以我们从add()方法起手。

public boolean add(E e) {// 首先是将当前size+1作为参数,然后调用ensureCapacityInternal判断是否需要进行扩容ensureCapacityInternal(size + 1);  // Increments modCount!!// 最后将元素放入容量足够未扩容/容量不够扩容过的elementData数组elementData[size++] = e;return true;
}

接下来我们跟进ensureCapacityInternal方法,看看到底发生了什么…

private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}private static int calculateCapacity(Object[] elementData, int minCapacity) {// 1.计算最小扩容量// 在前面也说过,如果elementData等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA// 就意味着该ArrayList刚刚调用完无参构造方法,这个地方正是该ArrayList第一次添加元素,将容量初始化为10的地方if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}// 返回最小扩容量return minCapacity;
}private void ensureExplicitCapacity(int minCapacity) {modCount++;// 2.判断是否需要进行扩容// 如果最小需要的容量大于数组elementData的容量,就意味着要进行扩容操作// 注意!不要把size和elementData的容量弄混了,一个是ArrayList当前存放元素的个数,一个是当前容量的大小!if (minCapacity - elementData.length > 0)// 3.如果判断需要进行扩容,则调用grow方法进行扩容grow(minCapacity);
}

通过以上几个方法的执行,如果确定最小需求容量minCapacity大于该ArrayList的当前容量,就会调用grow()方法进行扩容,我们再继续看grow()方法的内部实现。

private void grow(int minCapacity) {// 先获取旧容量oldCapacity// overflow-conscious codeint oldCapacity = elementData.length;// 采用右移计算(效率更高),将新容量newCapacity赋值为旧容量oldCapacity的1.5倍int newCapacity = oldCapacity + (oldCapacity >> 1);// 检查新容量是否符合最小容量需求,如果新容量小于最小容量需求,就将新容量设计为最小容量需求if (newCapacity - minCapacity < 0)newCapacity = minCapacity;// 再检查新容量newCapacity是否超出了ArrayList类所定义的最大容量// 如果超出了那么就将新容量设置为Integer的最大值,否则设置为Arraylist定义的最大容量if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// 最后将elementData按照新容量newCapcity拷贝到一个新数组返回elementData = Arrays.copyOf(elementData, newCapacity);
}private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
}

读到这里,可能你会好奇关于为什么ArrayList的默认最大容量为Integer.MAX_VALUE - 8?我们可以详细看一下关于这个变量的注解

/*** The maximum size of array to allocate.* Some VMs reserve some header words in an array.* Attempts to allocate larger arrays may result in* OutOfMemoryError: Requested array size exceeds VM limit*/private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

大概意思是说,一些虚拟机会预留数组头部的大小,一般数组头部有8个字节,所以 这里要减掉头部的8个字节,不然的话,整个数组大小就超过int的最大值了。就会跑出OutOfMemoryError错误。

4.总结

最后我们总结一下整个扩容过程

画图不易,点赞支持一下!

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的构造方法 1-1:空参构造方法: private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = { ...

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

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

  6. 说一说 ArrayList 的扩容机制

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

  7. ArrayList源码扩容机制分析

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

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

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

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

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

最新文章

  1. 六周第四次课(5月2日)
  2. 把巧克力球送上天,玛氏用Uni Marketing 打造网红零食
  3. Installation error: INSTALL_FAILED_VERSION_DOWNGRADE Android
  4. Django 中的 cookie 和 session
  5. php 字符串的比较大小,PHP如何比较字符串的大小?
  6. Django项目知识点(二)
  7. CF-567F(President and Roads) DAG必经边
  8. NoSQL数据库:数据的一致性
  9. 不使用比较运算符如何比较两个数的大小
  10. 基于matlab的信源编码pcm,信源编码仿真实现
  11. python可以做微信小游戏吗_python可以写微信小游戏吗
  12. 文字栅格化剪切蒙版——创建文字遮罩效果的两种方法——梦幻游乐园
  13. 安装华为运动健康beta版本安装失败
  14. mysql 统计请假天数_知道请假时间段、工作日和工作时长,计算请假天数
  15. 通信中的MGF(矩生成函数)
  16. python迅雷下载任务出错_迅雷下载任务出错的原因和解决方法 来研究下吧
  17. 【计算机网络】数据链路层 : 以太网 ( 无连接、不可靠服务 | 以太网发展 | 10BASE-T 以太网 | MAC 地址 | 以太网 MAC 帧 | 高速以太网 )
  18. 5.3.1 Unique Binary Sear Trees
  19. 一步一步学Silverlight 2系列(1):创建一个基本的Silverlight应用
  20. 证券行业企业微信智慧办公解决方案

热门文章

  1. 前端页面导出excel文件功能(导出)
  2. 解决浏览器页面缩放前端页面大小自适应改变的问题
  3. .aspx.cs不存在,问题原因
  4. android升级linux 内核,Android要升级Linux 3.10内核了!
  5. android状态栏白色,Android如何实现状态栏白底黑字效果
  6. input所有属性及作用
  7. js 把烤串命名转换为驼峰命名(快手面试题)
  8. 华山全敏还是全劲_楚留香手游华山加点推荐
  9. ChatGPT:语音翻译的全新解决方案
  10. Melis系统崩溃问题分析以及解决思路