• 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);
            }
        }
  • 相关阅读:
    字符串、组合练习
    national flag
    常用的Linux操作
    大数据概述
    LL(1)文法
    简单有穷自动机
    简单C语言文法
    词法分析
    编译原理 141
    综合练习
  • 原文地址:https://www.cnblogs.com/buhuiflydepig/p/12505684.html
Copyright © 2020-2023  润新知