zoukankan      html  css  js  c++  java
  • ArrayList 详解

    基本介绍

    ArrayList:
    
        支持null元素、有顺序、元素可以重复。
    
        可以动态增长和缩减的索引序列,基于数组实现的List类(查询效率高,而在插入删除性能下降很多(需要移动数组元素))。
    
        底层的数据结构是数组,数组元素类型为Object类型,即可以存放所有类型数据。
    
        removeAll(collection c)和clear()的区别就是removeAll可以删除批量指定的元素,而clear是全是删除集合中的元素。
    
        ArrayList实现了RandomAccess,所以在遍历它的时候推荐使用for循环。
    
    
    ArrayList和Vector(已废弃)的区别是:
        ArrayList是线程不安全的,当多条线程访问同一个ArrayList集合时,程序需要手动保证该集合的同步性。
        Vector是线程安全的。
    

    RandomAccess

    public interface RandomAccess {
    }
    
    RandomAccess接口:
        一个标记性接口,它的作用就是用来快速随机存取。
    
        在实现了该接口的话,那么使用普通的for循环来遍历,性能更高,例如arrayList。
        而没有实现该接口的话,使用Iterator来迭代,这样性能更高,例如linkedList。
    
        所以这个标记性只是为了让我们知道我们用什么样的方式去获取数据性能更好。
    

    源码分析

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
        private static final long serialVersionUID = 8683452581122892189L;
    
        //缺省容量
        private static final int DEFAULT_CAPACITY = 10;
    
        //最大容量
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
        //空对象数组
        private static final Object[] EMPTY_ELEMENTDATA = {};
    
        //缺省空对象数组
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
        //储存元素的数组
        transient Object[] elementData; // non-private to simplify nested class access
    
        //实际元素大小,默认为0
        private int size;
    
        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);
            }
        }
    
        //无参构造方法,初始化为空数组,在第一次添加元素时才分配数组容量
        public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    
        public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            if ((size = elementData.length) != 0) {
                // defend against c.toArray (incorrectly) not returning Object[]
                // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
                if (elementData.getClass() != Object[].class)
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
            } else {
                // replace with empty array.
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }
    
        public boolean add(E e) {
            modCount++;
            add(e, elementData, size);
            return true;
        }
    
        private void add(E e, Object[] elementData, int s) {
            if (s == elementData.length)
                elementData = grow();
            elementData[s] = e;
            size = s + 1;
        }
    
        public boolean addAll(Collection<? extends E> c) {
            Object[] a = c.toArray();
            modCount++;
            int numNew = a.length;
            if (numNew == 0)
                return false;
            Object[] elementData;
            final int s;
            if (numNew > (elementData = this.elementData).length - (s = size))
                elementData = grow(s + numNew);
            System.arraycopy(a, 0, elementData, s, numNew);
            size = s + numNew;
            return true;
        }
    
        //扩容1.5倍
        private Object[] grow() {
            return grow(size + 1);
        }
    
        private Object[] grow(int minCapacity) {
            //新的容量大小已经确定好了,就copy数组,改变容量大小
            return elementData = Arrays.copyOf(elementData,
                                               newCapacity(minCapacity));
        }
    
        private int newCapacity(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            //扩容1.5倍
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            //elementData是空数组的时候,length=0,那么oldCapacity=0,newCapacity=0,则初始化elementData的大小(10或者minCapacity:所需最小容量size+1)
            if (newCapacity - minCapacity <= 0) {
                if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                    return Math.max(DEFAULT_CAPACITY, minCapacity);
                if (minCapacity < 0) // overflow
                    throw new OutOfMemoryError();
                return minCapacity;
            }
            //如果newCapacity超过了最大的容量限制,就调用hugeCapacity,也就是将能给的最大值给newCapacity
            return (newCapacity - MAX_ARRAY_SIZE <= 0)
                ? newCapacity
                : hugeCapacity(minCapacity);
        }
    
        public E get(int index) {
            Objects.checkIndex(index, size);
            return elementData(index);
        }
    
        public E remove(int index) {
            //检查index的合理性
            Objects.checkIndex(index, size);
            final Object[] es = elementData;
    
            @SuppressWarnings("unchecked") E oldValue = (E) es[index];
            fastRemove(es, index);
    
            return oldValue;
        }
    
        /**
         * public static void arraycopy(Object src,
         *                              int srcPos,
         *                              Object dest,
         *                              int destPos,
         *                              int length)
         * src:源对象
         * srcPos:源对象对象的起始位置
         * dest:目标对象
         * destPost:目标对象的起始位置
         * length:从起始位置往后复制的长度
         */
        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,让gc(垃圾回收机制)更快的回收它
            es[size = newSize] = null;
        }
    }
    
  • 相关阅读:
    Delphi与C++的语法区别(六点区别) good
    Delphi检测用户是否具有administrator权限(OpenThreadToken,OpenProcessToken,GetTokenInformation,AllocateAndInitializeSid和EqualSid)
    QSqlDatabase::addDatabase第一次运行的时候,生成SQLite文件的同时会产生一个默认连接
    所有CN_消息的说明
    hdu 1671 Phone List(字典树)
    所有CM_消息的说明
    感悟:新事物的生命力是惊人的,存在无限的机会
    Delphi访问活动目录(使用COM,活动目录Active Directory是用于Windows Server的目录服务)
    Delphi中获取某类的祖先类及其所在单元名称(使用GetTypeData(PClass.ClassInfo)函数,并且该类是从TPersistent类的派生类才可以这么使用)
    消息函数一般是私有的,因为不需要程序员显示的调用,但子类如果需要改写这个方法,则改成保护方法Protected
  • 原文地址:https://www.cnblogs.com/loveer/p/11532803.html
Copyright © 2011-2022 走看看