zoukankan      html  css  js  c++  java
  • ArrayList 源码分析

    ArrayList

    ArrayList 能解决什么问题?什么时候使用 ArrayList?

    1)ArrayList 底层存储结构是一个对象数组,因此只能存储 Java 对象和 null 值。
    2)每个 ArrayList 都有一个容量,容量表示该 ArrayList 当前能容纳的元素个数,
    随着元素的增加,ArrayList 会自动扩容,扩容操作通过 System.arraycopy 完成旧元素的拷贝,
    因此 ArrayList 适用于元素个数不确定的对象集合。
    3)ArrayList 不是线程安全的,多线程并发读写 ArrayList 并且至少有一个线程修改了它的结构【增加、删除元素、扩容等】,
    则 ArrayList 将抛出 ConcurrentModificationException 异常。
    4)ArrayList 的 size、isEmpty、get、set、iterator 和 listIterator 方法以常量时间运行,其他的操作基本以线性时间运行。
    5)ArrayList 实现了 RandomAccess 接口,随机读写以常量时间运行,效率高。
    6)ArrayList 的快速失败机制【fast-fail】:iterator 和 listIterator 返回的迭代器是快速失败的,
    如果不是通过 ListIterator#remove() 或 ListIterator#add(Object) 方法修改其结构,
    则 ArrayList 将尽最大努力抛出 ConcurrentModificationException 异常。
    7)ArrayList 的缩容机制:通过 trimToSize 方法将 ArrayList 的容量缩小为当前元素的个数,以减少 ArrayList 的内存占用。
    8)ArrayList 的扩容机制:默认为 1.5 倍向下取整扩容,如果批量添加元素,则以 size+newNum 进行扩容。
    

    如何使用 ArrayList?

    1)在创建 ArrayList 时可以指定一个合适的初始化容量,以减少频繁扩容带来的性能损耗,使用默认容量值 10 或指定容量值。
    2)对于 ArrayList 类型的静态只读属性,通过 trimToSize 方法将 ArrayList 的容量缩小为当前元素的个数,以减少 ArrayList 的内存占用。
    3)ArrayList 的随机删除操作会导致部分元素往左 shift,随机删除操作越多,内存拷贝越频繁,性能越差。
    

    使用 ArrayList 有什么风险?

    1)ArrayList 的最大容量为 Integer.MAX_VALUE,使用不当可能会导致内存溢出。
    2)ArrayList 不是线程安全的,ArrayList 作为共享资源在多线程下执行写操作时,会出现元素丢失的问题。
    

    ArrayList 核心操作的实现原理?

    • 属性说明
        /**
         * 通过无参构造函数创建 ArrayList 实例时,第一次扩容的默认容量值。
         */
        private static final int DEFAULT_CAPACITY = 10;
    
        /**
         * 通过带容量构造函数创建 ArrayList 实例时,用于共享的空数组对象
         */
        private static final Object[] EMPTY_ELEMENTDATA = {};
    
        /**
         * 通过无参构造函数创建 ArrayList 实例时,用于共享的空数组对象
         */
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
        /**
         * ArrayList 底层存储元素的对象数组,数组的长度就是 ArrayList 的容量
         */
        transient Object[] elementData; // non-private to simplify nested class access
    
        /**
         * ArrayList 包含元素的个数
         */
        private int size;
    
    • 创建实例
        /**
         * 创建一个初始化容量为 10 的空 ArrayList 实例
         */
        public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    
        /**
         * 创建一个指定初始容量的空 ArrayList 实例
         */
        public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                // 指定容量为负数时抛出 IllegalArgumentException 异常
                throw new IllegalArgumentException("Illegal Capacity: "+
                        initialCapacity);
            }
        }
    
        /**
         * 创建一个包含指定集合中所有元素的 ArrayList 实例,集合中的元素按照迭代器顺序返回。
         */
        public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            // 形参集合非空
            if ((size = elementData.length) != 0) {
                if (elementData.getClass() != Object[].class) {
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
                }
            } else {
                // replace with empty array.
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }
    
    • 在尾部添加元素
        /**
         * 将指定的元素添加到列表的尾部
         */
        @Override
        public boolean add(E e) {
            modCount++;
            add(e, elementData, size);
            return true;
        }
    
        /**
         * This helper method split out from add(E) to keep method
         * bytecode size under 35 (the -XX:MaxInlineSize default value),
         * which helps when add(E) is called in a C1-compiled loop.
         */
        private void add(E e, Object[] elementData, int s) {
            // 当前元素的个数已经达到底层数组的最大容量,需要进行扩容
            if (s == elementData.length) {
                elementData = grow();
            }
            // 存储元素
            elementData[s] = e;
            // 递增元素个数
            size = s + 1;
        }
    
        private Object[] grow() {
            return grow(size + 1);
        }
    
        /**
         * 增加 ArrayList 的容量,以保证其至少能够容纳 minCapacity 个元素
         */
        private Object[] grow(int minCapacity) {
            return elementData = Arrays.copyOf(elementData,
                    newCapacity(minCapacity));
        }
    
        private int newCapacity(int minCapacity) {
            // 获取旧容量
            final int oldCapacity = elementData.length;
            // 计算新容量(1.5 倍向下取整)
            final int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity <= 0) {
                // 如果是通过无参构造函数创建的实例,且是第一次添加元素
                if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                    // 单个添加则返回默认初始容量 10,批量添加并且元素个数大于 10,则返回目标元素个数 minCapacity
                    return Math.max(DEFAULT_CAPACITY, minCapacity);
                }
                if (minCapacity < 0) {
                    throw new OutOfMemoryError();
                }
                // 通过 addAll 批量添加元素,并且个数超出(剩余容量+原始容量*0.5),则返回目标容量
                return minCapacity;
            }
            // 新容量小于 Integer.MAX_VALUE - 8,则返回 1.5 倍向下取整的值
            return newCapacity - MAX_ARRAY_SIZE <= 0
                    ? newCapacity
                            : ArrayList.hugeCapacity(minCapacity);
        }
    
        private static int hugeCapacity(int minCapacity) {
            // 目标容量溢出
            if (minCapacity < 0) {
                throw new OutOfMemoryError();
            }
            // 新容量等于 Integer.MAX_VALUE - 8,则返回该值,否则返回 Integer.MAX_VALUE
            return minCapacity > MAX_ARRAY_SIZE
                    ? Integer.MAX_VALUE
                            : MAX_ARRAY_SIZE;
        }
    
    • 在尾部批量添加元素
        /**
         * 将形参集合中的所有元素顺序添加到 ArrayList 的尾部
         */
        @Override
        public boolean addAll(Collection<? extends E> c) {
            final Object[] a = c.toArray();
            // 增加结构化修改计数值,在并发修改时可抛出 CME
            modCount++;
            // 形参集合为空时直接返回
            final int numNew = a.length;
            if (numNew == 0) {
                return false;
            }
            Object[] elementData;
            final int s;
            // 新增元素个数大于 ArrayList 剩余可用容量时执行扩容操作
            if (numNew > (elementData = this.elementData).length - (s = size)) {
                elementData = grow(s + numNew);
            }
            // 拷贝目标元素到底层数组中
            System.arraycopy(a, 0, elementData, s, numNew);
            // 增加元素个数
            size = s + numNew;
            return true;
        }
    
    • 读取元素
        /**
         * 获取 ArrayList 指定索引处的元素
         */
        @Override
        public E get(int index) {
            // 索引合法性校验
            Objects.checkIndex(index, size);
            return elementData(index);
        }
    
        @SuppressWarnings("unchecked")
        E elementData(int index) {
            // 获取底层数组指定索引的元素
            return (E) elementData[index];
        }
    
    • 替换元素
        /**
         * 替换指定索引处的元素,并返回旧值
         */
        @Override
        public E set(int index, E element) {
            Objects.checkIndex(index, size);
            // 读取旧值
            final E oldValue = elementData(index);
            // 设置新值
            elementData[index] = element;
            // 返回旧值
            return oldValue;
        }
    
    • 移除指定索引处的元素
        /**
         * 移除指定索引处的元素
         */
        @Override
        public E remove(int index) {
            Objects.checkIndex(index, size);
            final Object[] es = elementData;
    
            @SuppressWarnings("unchecked")
            final E oldValue = (E) es[index];
            fastRemove(es, index);
    
            return oldValue;
        }
    
        /**
         * 忽略下标校验,并且无返回值的快速元素移除
         */
        private void fastRemove(Object[] es, int i) {
            modCount++;
            final int newSize;
            // 被移除元素不是最后一个元素
            if ((newSize = size - 1) > i) {
                // 目标索引之后的元素集体左移
                System.arraycopy(es, i + 1, es, i, newSize - i);
            }
            // 将最后一个元素置为 null,并修改总元素个数
            es[size = newSize] = null;
        }
    
    • 移除第一个匹配的元素
        /**
         * 从 ArrayList 中移除第一个匹配形参的元素,通过  Objects.equals(o, get(i)) 进行相等性比较
         */
        @Override
        public boolean remove(Object o) {
            final Object[] es = elementData;
            final int size = this.size;
            int i = 0;
            // 查找目标元素的下标
            found: {
                if (o == null) {
                    for (; i < size; i++) {
                        if (es[i] == null) {
                            break found;
                        }
                    }
                } else {
                    for (; i < size; i++) {
                        if (o.equals(es[i])) {
                            break found;
                        }
                    }
                }
                return false;
            }
            // 快速移除
            fastRemove(es, i);
            return true;
        }
    
    • 批量移除元素
        /**
         * 从 ArrayList 中移除包含在形参集合中的所有元素
         */
        @Override
        public boolean removeAll(Collection<?> c) {
            return batchRemove(c, false, 0, size);
        }
    
        /**
         * created by ZXD at 19 Nov 2018 T 21:24:42
         * @param c 目标集合
         * @param complement 是否取补集
         * @param from 起始索引,包含
         * @param end 结束索引,不包含
         * @return
         */
        boolean batchRemove(Collection<?> c, boolean complement,
                final int from, final int end) {
            Objects.requireNonNull(c);
            final Object[] es = elementData;
            int r;
            // Optimize for initial run of survivors
            // 查找到需要移除的第一个元素的下标
            for (r = from;; r++) {
                // 如果未找到则直接返回 false
                if (r == end) {
                    return false;
                }
                if (c.contains(es[r]) != complement) {
                    break;
                }
            }
            // 需要填充的第一个元素的下标【原来的元素被移除】
            int w = r++;
            try {
                for (Object e; r < end; r++) {
                    if (c.contains(e = es[r]) == complement) {
                        // 需要保留的元素按顺序进行填充
                        es[w++] = e;
                    }
                }
            } catch (final Throwable ex) {
                // 将结束索引后的元素集体左移进行填充
                System.arraycopy(es, r, es, w, end - r);
                w += end - r;
                throw ex;
            } finally {
                modCount += end - w;
                // 整体移动元素填充空隙,并将索引为 size-1 之后的元素置为 null
                shiftTailOverGap(es, w, end);
            }
            return true;
        }
    
    • 按条件移除
        /**
         * 从 ArrayList 中移除满足函数式断言的所有元素
         */
        @Override
        public boolean removeIf(Predicate<? super E> filter) {
            return removeIf(filter, 0, size);
        }
    
        /**
         * Removes all elements satisfying the given predicate, from index
         * i (inclusive) to index end (exclusive).
         */
        boolean removeIf(Predicate<? super E> filter, int i, final int end) {
            Objects.requireNonNull(filter);
            int expectedModCount = modCount;
            final Object[] es = elementData;
            // Optimize for initial run of survivors
            for (; i < end && !filter.test(ArrayList.elementAt(es, i)); i++) {
                ;
            }
            // 首先查找所有需要移除的元素索引,之后进行物理删除
            if (i < end) {
                final int beg = i;
                final long[] deathRow = ArrayList.nBits(end - beg);
                deathRow[0] = 1L;   // set bit 0
                for (i = beg + 1; i < end; i++) {
                    // 如果满足函数式断言
                    if (filter.test(ArrayList.elementAt(es, i))) {
                        // 记录需要删除元素的下标
                        ArrayList.setBit(deathRow, i - beg);
                    }
                }
                // 标记过程中出现多线程并发修改,则抛出 ConcurrentModificationException
                if (modCount != expectedModCount) {
                    throw new ConcurrentModificationException();
                }
                expectedModCount++;
                modCount++;
                int w = beg;
                for (i = beg; i < end; i++) {
                    // 从第一个被删除的位置开始,将需要保留的元素顺序进行填充
                    if (ArrayList.isClear(deathRow, i - beg)) {
                        es[w++] = es[i];
                    }
                }
                shiftTailOverGap(es, w, end);
                return true;
            } else {
                if (modCount != expectedModCount) {
                    throw new ConcurrentModificationException();
                }
                return false;
            }
        }
    
    • 读取目标元素第一次出现的索引
        /**
         * 形参对象在 ArrayList 中第一次出现的索引,如果不存在相等的元素,则返回 -1
         */
        @Override
        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;
        }
    
    • 读取目标元素最后一次出现的索引
        /**
         * 形参对象在 ArrayList 中最后一次出现的索引,如果不存在相等的元素,则返回 -1
         */
        @Override
        public int lastIndexOf(Object o) {
            if (o == null) {
                for (int i = size-1; i >= 0; i--) {
                    if (elementData[i]==null) {
                        return i;
                    }
                }
            } else {
                for (int i = size-1; i >= 0; i--) {
                    if (o.equals(elementData[i])) {
                        return i;
                    }
                }
            }
            return -1;
        }
    
    • 目标元素是否包含在列表中
        @Override
        public boolean contains(Object o) {
            return indexOf(o) >= 0;
        }
    
    • 交集
        /**
         * 移除 ArrayList 中不包含在形参集合中的所有元素
         */
        @Override
        public boolean retainAll(Collection<?> c) {
            return batchRemove(c, true, 0, size);
        }
    
    • 逐个替换
        /**
         * 通过函数式接口将 ArrayList 中的元素进行逐个替换
         * created by ZXD at 19 Nov 2018 T 21:51:23
         * @param operator
         */
        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            Objects.requireNonNull(operator);
            final int expectedModCount = modCount;
            final Object[] es = elementData;
            final int size = this.size;
            for (int i = 0; modCount == expectedModCount && i < size; i++) {
                // 将当前元素进行替换
                es[i] = operator.apply(ArrayList.elementAt(es, i));
            }
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }
    
    • 通过指定的比较器对 ArrayList 中的元素进行排序
        @Override
        @SuppressWarnings("unchecked")
        public void sort(Comparator<? super E> c) {
            final int expectedModCount = modCount;
            Arrays.sort((E[]) elementData, 0, size, c);
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }
    
    • 迭代遍历
        /**
         * 顺序迭代 ArrayList 中所有元素的简单迭代器
         */
        @Override
        public Iterator<E> iterator() {
            return new Itr();
        }
    
        /** 
         * 顺序迭代 ArrayList 中所有元素的列表迭代器,支持的操作更丰富
         */
        @Override
        public ListIterator<E> listIterator() {
            return new ListItr(0);
        }
    
        /**
         * 通过函数式接口顺序消费 ArrayList 中的每个元素
         */
        @Override
        public void forEach(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            final int expectedModCount = modCount;
            final Object[] es = elementData;
            final int size = this.size;
            for (int i = 0; modCount == expectedModCount && i < size; i++) {
                action.accept(ArrayList.elementAt(es, i));
            }
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
        }
    
    • 返回包含 ArrayList 所有元素的对象数组
        /**
         * 返回包含 ArrayList 所有元素的对象数组
         */
        @Override
        public Object[] toArray() {
            return Arrays.copyOf(elementData, size);
        }
    
        /**
         * 返回包含 ArrayList 所有元素的对象数组,可指定返回类型
         */
        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            // 形参数组的长度小于元素个数
            if (a.length < size) {
                // 拷贝 ArrayList 中的所有元素
                return (T[]) Arrays.copyOf(elementData, size, a.getClass());
            }
            // 拷贝 ArrayList 中的所有元素
            System.arraycopy(elementData, 0, a, 0, size);
            if (a.length > size) {
                a[size] = null;
            }
            return a;
        }
    
    • 元素总数
        /**
         * 返回 ArrayList 中的元素个数
         */
        @Override
        public int size() {
            return size;
        }
    
    • 是否为空
        /**
         * ArrayList为空时返回true
         */
        @Override
        public boolean isEmpty() {
            return size == 0;
        }
    
    • 扩容过程
        /**
         * 增加 ArrayList 的容量以至少能够容纳 minCapacity 个元素
         */
        public void ensureCapacity(int minCapacity) {
            // 通过无参构造函数创建,并且 minCapacity<=10 时不会执行扩容操作
            if (minCapacity > elementData.length
                    && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
                    && minCapacity <= DEFAULT_CAPACITY)) {
                modCount++;
                grow(minCapacity);
            }
        }
    
    • 缩容
        /**
         * 将容量缩小为 ArrayList 中元素的个数,以节约内存使用
         */
        public void trimToSize() {
            modCount++;
            if (size < elementData.length) {
                /**
                 * ArrayList 为空时,底层数组修改为 EMPTY_ELEMENTDATA
                 * ArrayList 非空时,通过数组拷贝完成
                 */
                elementData = size == 0
                        ? EMPTY_ELEMENTDATA
                                : Arrays.copyOf(elementData, size);
            }
        }
    
    • 清空 ArrayList
        /**
         * 移除 ArrayList 中的所有元素,个数置为0,容量保持不变
         */
        @Override
        public void clear() {
            modCount++;
            final Object[] es = elementData;
            for (int to = size, i = size = 0; i < to; i++) {
                es[i] = null;
            }
        }
    
  • 相关阅读:
    mybatis-config.xml
    log4j.properties
    applicationContext.xml
    对象mapper
    面向接口,定义接口
    Java实现Excel导入数据库,数据库中的数据导入到Excel。。转载
    判断浏览器类型
    大小写字母,数字,下划线,中横线和中文 正则表达式
    Androidpn的使用[找不到org.androidpn.client.PersistentConnectionListener]
    沙扬娜拉---徐志摩
  • 原文地址:https://www.cnblogs.com/zhuxudong/p/9581072.html
Copyright © 2011-2022 走看看