ArrayList关键代码解析

以下代码是ArrayList中关键扩容代码解释:

  1. ArrayList底层使用数组存储数据;
  2. ArrayList默认容量是10;
  3. ArrayList默认扩容策略是原容量的1.5倍;
  4. ArrayList最大容量是Integer-8;
public class ArrayList{ /** * 默认初始化数组容量:10 */ private static final int DEFAULT_CAPACITY = 10; /** * 空数组(用于空实例),在实例化时如果传入的list长度为0,当调用new ArrayList(0)时,即传入的数组长度为0时,会默认 elementData=https://www.it610.com/article/EMPTY_ELEMENTDATA */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 用于默认大小实例的共享空数组实例,在调用new ArrayList()时会默认elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA * 之所以与EMPTY_ELEMENTDATA区分开,以知道在添加第一个元素时容量需要增加多少。 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * 保存ArrayList数据的数组 */ transient Object[] elementData; /** * ArrayList中元素的个数 */ private int size; /** * 带初始容量参数的构造函数(用户可以在创建ArrayList对象时自己指定集合的初始大小) */ public MyArrayList(int initialCapacity) { if (initialCapacity> 0) { //如果传入的参数大于0,创建initialCapacity大小的数组 this.elementData = https://www.it610.com/article/new Object[initialCapacity]; } else if (initialCapacity == 0) { //如果传入的参数等于0,创建空数组 this.elementData = EMPTY_ELEMENTDATA; } else { //其他情况,抛出异常 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }/** * 默认的无参构造函数 * 初始化的时候默认容量是10,elementData是空数组,只有在添加第一个元素的时候才会真正的将elementData初始化成为一个容量为10的数组(相当于是延迟初始化) */ public MyArrayList() { this.elementData = https://www.it610.com/article/DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }/** * 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。 * @param c */ public MyArrayList(Collection c) { //将传入的集合转成数组 elementData = https://www.it610.com/article/c.toArray(); if ((size = elementData.length) != 0) { //如果数组中元素长度不是0,判断数组类型是不是Object数组类型,如果不是则转成Object数组类型 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { //如果是一个空集合,则使用EMPTY_ELEMENTDATA this.elementData = EMPTY_ELEMENTDATA; } }/** * 裁剪ArrayList,主要是给程序员调用的,如果当前数组中元素个数小于整个数组的长度,则将数组缩减成与元素个数相同的数组,能够最小化该ArrayList占用的存储空间 */ public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }/** * 如有必要,增加此ArrayList实例的容量,以确保它至少能容纳元素的数量 * ArrayList的扩容机制 * @param minCapacity */ public void ensureCapacity(int minCapacity) { //默认最小的扩容数量,如果elementData不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,那么默认最小扩容数量是10 int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY; //如果最小容量大于已有的最大容量 if (minCapacity> minExpand) { ensureExplicitCapacity(minCapacity); } }/** * 计算需要扩展的容量大小,如果elementData是空数组,则返回默认容量大小,即10,否则返回minCapacity * @param elementData * @param minCapacity * @return */ private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData =https://www.it610.com/article/= DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }/** * 判断当前数组element能否保存minCapacity数量的元素,如果不能则进行扩容 * @param minCapacity */ private void ensureCapacityInternal(int minCapacity) { //为了方便解析,将该行代码解析成为两行 //ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); //获取容量大小,即当elementData是默认的空数组时,则返回默认大小,即10 //如果elementData默认不是空数组时,则返回minCapacity int capacity = calculateCapacity(elementData, minCapacity); //判断elementData能否满足所需最小的容量,如果不能满足则扩容 ensureExplicitCapacity(capacity); }/** * 判断elementData能否满足所需最小的容量,如果不能满足则扩容 * @param minCapacity */ private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code //如果所需最小容量(minCapacity)大于当前elementData数组的长度,则扩容 if (minCapacity - elementData.length> 0) //扩容 grow(minCapacity); }/** * 为了防止OOM异常,限制数组分配的最大长度 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 进行扩容操作 * @param minCapacity */ private void grow(int minCapacity) { // overflow-conscious code //获取当前elementData数组的长度 int oldCapacity = elementData.length; //默认新的数组长度是现在数组长度的1.5倍 (oldCapacity+0.5*oldCapacity=1.5oldCapacity) //位运算比直接newCapacity=1.5*oldCapacity要快很多 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) { //如果扩容1.5倍仍然小于指定要扩容(minCapacity)的数量 //则扩容至指定容量(minCapacity)的大小 newCapacity = minCapacity; }//代码执行到这里,实际上最终要扩容的数量要么是现在elementData长度的1.5倍,要么是指定要扩容的长度(minCapacity) if (newCapacity - MAX_ARRAY_SIZE > 0) //如果最终要扩容的数量大于内置的最大值,即MAX_ARRAY_SIZE=Integer.MAX_VALUE - 8 //则默认将最终要扩大的容量改为Integer.MAX_VALUE newCapacity = hugeCapacity(minCapacity); //将elementData扩容至newCapacity大小的数组,并且将现在elementData中的元素拷贝到新的数组中 elementData = https://www.it610.com/article/Arrays.copyOf(elementData, newCapacity); }/** *大容量 * 如果需要扩展的容量大于MAX_ARRAY_SIZE=Integer.MAX_VALUE-8,则返回MAX_ARRAY_SIZE,否则返回MAX_VALUE * @param minCapacity * @return */ private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity> MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }/** * 新增一个元素 * @param e * @return */ public boolean add(E e) { //判断当前数组容量是否够用,如果不够,则进行扩容 ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } }

【ArrayList关键代码解析】

    推荐阅读