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);
        }
    }

 

posted @ 2020-03-16 19:29  不会fly的pig  阅读(119)  评论(0编辑  收藏  举报