ArrayList源码解析
1、属性
//默认初始容量为10 private static final int DEFAULT_CAPACITY = 10; //空对象数组,当用户指定的数组长度为0时,返回该数组 private static final Object[] EMPTY_ELEMENTDATA = {}; //空对象数组,使用默认的构造方法是,返回该数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //对象数组 transient Object[] elementData; //对象数组当前的容量 private int size; //分配给对象数组的最大容量 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
2、构造方法
//无参构造方法 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
public ArrayList(int initialCapacity) { if (initialCapacity > 0) { //创建指定长度的数组 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { //空数组 this.elementData = EMPTY_ELEMENTDATA; } else { //如果指定的长度小于0时,抛出异常 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
//不常用 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // 判断是不是Object类型的数组,如果不是的话,则构造一个Object类型的数组 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }
3、添加
//在数组尾部添加元素 public boolean add(E e) { //检查是否需要扩容 ensureCapacityInternal(size + 1); elementData[size++] = e; return true; }
//检查数组是否需要扩容,其中参数minCapacity表示当前数组需要存储元素的个数 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
//计算数组的最小容量 private static int calculateCapacity(Object[] elementData, int minCapacity) { //如果数组为空数组,则返回默认数组大小10和minCapacity中较大的那个 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
//判断数组是否需要扩容 private void ensureExplicitCapacity(int minCapacity) { //操作次数加一 modCount++; //数组需要存储的最小容量和数组当前的容量进行比较 if (minCapacity - elementData.length > 0) grow(minCapacity); }
//数组扩容的方法 private void grow(int minCapacity) { //获取当前数组的大小 int oldCapacity = elementData.length; //原数组大小扩大1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //如果新的数组的长度比MAX_ARRAY_SIZE还大的话,就越界了,则进行判断 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //数组扩容 elementData = Arrays.copyOf(elementData, newCapacity); }
//数组长度越界判断 private static int hugeCapacity(int minCapacity) { //如果数组当前需要存储的长度小于0的话,抛出异常 if (minCapacity < 0) throw new OutOfMemoryError(); //如果数组当前需要存储的长度要大于MAX_ARRAY_SIZE,就返回int型的最大值 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
//在指定位置添加元素 public void add(int index, E element) { //判断index是否越界 rangeCheckForAdd(index); //检查是否需要扩容 ensureCapacityInternal(size + 1); //将index之后的所有元素,后移一位 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
//检查是否越界 private void rangeCheckForAdd(int index) { //如果index越界,则抛出异常 if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
注意:一开始数组是一个空数组,只有在第一次添加元素的时候,容量才会扩充为10。如果不够的话,就扩容1.5倍。
疑问:为什么要初始化为空数组呢?
因为开发中,很多时候创建了ArrayList的对象,但是没有装元素,这个时候的话,如果初始化为10的数组,就浪费空间了。
4、查找
//获取下标为index的元素 public E get(int index) { //检查下标index是否越界 rangeCheck(index); //获取下标为index的元素,并返回 return elementData(index); }
//检查下标是否越界 private void rangeCheck(int index) { //如果越界,抛出异常 if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
//返回index下标的元素 E elementData(int index) { return (E) elementData[index]; }
5、修改
//将index下标的元素修改成element,并返回之前未修改时的元素 public E set(int index, E element) { //检查下标index是否越界 rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; }
6、删除
//指定位置删除,并返回删除的元素 public E remove(int index) { //检查下标index是否越界 rangeCheck(index); //操作次数加一 modCount++; E oldValue = elementData(index); //将index+1及后面的元素向前移一位,覆盖被删除的值,当前值表示需要移动的元素的长度 int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; return oldValue; }
//指定元素删除,如果有,返回true,否则返回false public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { //删除下标为index的元素 fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { //删除下标为index的元素 fastRemove(index); return true; } } return false; }
//删除下标为index的元素 private void fastRemove(int index) { //操作次数加一 modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; }
7、其他方法
//返回数组的大小 public int size() { return size; }
//判断数组是否为空 public boolean isEmpty() { return size == 0; }
//判断数组是否存在元素o public boolean contains(Object o) { return indexOf(o) >= 0; }
//检查数组是否存在元素o,如果存在,返回其第一次出现下标,否则返回-1 public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
//将数组后面多余的空间删掉,长度为存储元素的个数 public void trimToSize() { //操作次数加一 modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }