ArrayList的扩容机制(源码解读)

(1)ArrayList所继承的接口

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable 

ArrayList继承了 AbstractList 实现了List接口,RandomAccess接口,Cloneable接口

(2)ArrayList类所包含的属性

【1】serialVersionUID

serialVersionUID适用于Java的序列化机制,这个我们今天先不用过多考虑

private static final long serialVersionUID = 8683452581122892189L;

【2】DEFAULT_CAPACITY

初始的默认初始容量10

private static final int DEFAULT_CAPACITY = 10;

【3】EMPTY_ELEMENTDATA

空数组

private static final Object[] EMPTY_ELEMENTDATA = {};

【4】DEFAULTCAPACITY_EMPTY_ELEMENTDATA

这个也是一个空数组,但是区别是什么呢???
当第一个元素被加进来的时候DEFAULTCAPACITY_EMPTY_ELEMENTDATA 知道如何扩张,在之后的源码解析会再次解释。

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

【5】elementData

elementData数组用来存储ArrayList中的数据(ArrayList的底层数据结构是数组

transient Object[] elementData; 

【6】size

记录集合中所存储元素的个数

private int size;

(3)ArrayList集合中的方法

1> 构造方法

【1】ArrayList(int initialCapacity)

  • 给定初始容量的ArrayList
  • 初始容量不为空的时候创建初始容量大小的Object[],也就是说ArrayList底层用的是Object数组
  • 初始容量为0的时候,直接返回 第一个空数组
            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);
                }
            }

【2】ArrayList()

  • 默认ArrayList无参构造返回DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组
  • 第一次加入元素的时候,调用下面add()方法里确定了(扩容为)初始大小为10
            public ArrayList() {
                this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
            }

【3】ArrayList(Collection<? extends E> c)

  • 构造函数的参数是集合
  • 原集合转化成数组
  • 数组长度为0,就返回一个空集合
  • 数组长度不为0,将原集合中的数据复制到新数组copyOf(要复制的数组,新数组的长度)
           public ArrayList(Collection<? extends E> c) {
               elementData = c.toArray();
               if ((size = elementData.length) != 0) {
                   // c.toArray might (incorrectly) not return Object[] (see 6260652)
                   if (elementData.getClass() != Object[].class)
                       elementData = Arrays.copyOf(elementData, size, Object[].class);
               } else {
                   // replace with empty array.
                   this.elementData = EMPTY_ELEMENTDATA;
               }
           }

2> add(E e)方法

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

【1】ensureCapacityInternal()函数源码

  • 如果当前数组elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA是个空数组
  • 那就在默认大小10和参数minCapacity之中选择最大值也就是说默认大小就是10
            private void ensureCapacityInternal(int minCapacity) {
                if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                    minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
                }
                ensureExplicitCapacity(minCapacity);
            }

【2】ensureExplicitCapacity(int minCapacity) 函数源码

            private void ensureExplicitCapacity(int minCapacity) {
                modCount++;
                // overflow-conscious code
                if (minCapacity - elementData.length > 0)
                    grow(minCapacity);
            }

3> add(int index, E element)方法

根据索引加入一个指定数据

  • 检查位置有效性(是否越界)
  • 添加修改次数,判断是否需要扩容
  • 完成数组自身从index开始的所有元素到index+1开始长度为size-index的位置上
  • 将新元素添加至指定位置
public void add(int index, E element) {
                //位置有效性检查
                rangeCheckForAdd(index);
                //添加修改次数,判断是否需要扩容
                ensureCapacityInternal(size + 1);  // Increments modCount!!
                //完成数组自身从index开始的所有元素拷贝到index+1开始且长度为size-index的位置上。
                System.arraycopy(elementData, index, elementData, index + 1,
                        size - index);
                //上面是完成自身的拷贝
                //下面将add的这个数据添加到index位置上
                elementData[index] = element;
                size++;
            }
            private void rangeCheckForAdd(int index) {
                if (index > size || index < 0)//是否越界鸭???
                    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            }
            private String outOfBoundsMsg(int index) {
                return "Index: "+index+", Size: "+size;
            }

4> grow(int minCapacity) 扩容数组

  • 旧容量右移一位再加上原大小即原大小的1.5倍
  • 如果扩容过小,则至少扩容至minCapacity
  • 如果扩容过大,则大小选择Integer.MAX_VALUE
  • MAX_VALUE = 0x 7fff ffff
  • 然后将旧数组中的数据复制到新数组中:copyOf()
private void grow(int minCapacity) {
       // overflow-conscious code
       int oldCapacity = elementData.length;
       int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容至原大小的1.5倍
       if (newCapacity - minCapacity < 0)//如果扩张的大小过小,则至少扩容至minCapacity
           newCapacity = minCapacity;
       if (newCapacity - MAX_ARRAY_SIZE > 0)//如果扩容的大小过大,Integer.MAX_VALUE=MAX_VALUE = 0x 7fff ffff
          newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
       elementData = Arrays.copyOf(elementData, newCapacity);//将数组中数据copyOf()到新的数组中
}

public static int[] copyOf(int[] original, int newLength) {
       int[] copy = new int[newLength]; //创建一个新长度的数组
       System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
       return copy;
}
 //public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

【1】 hugeCapacity(int minCapacity)源码

private static int hugeCapacity(int minCapacity) {
       if (minCapacity < 0) // overflow
           throw new OutOfMemoryError();
           return (minCapacity > MAX_ARRAY_SIZE) ?
           Integer.MAX_VALUE :
           MAX_ARRAY_SIZE;
}
发布了120 篇原创文章 · 获赞 59 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/lr1916417519/article/details/88130752