美文网首页
ArrayList的介绍和源码解析

ArrayList的介绍和源码解析

作者: high5130 | 来源:发表于2018-08-28 14:45 被阅读0次

    ArrayList的介绍

    1 ArrayList简介

    ArrayList是List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。(此类大致上等同于 Vector 类,除了此类是不同步的。),此类是线程不安全的。

    2 ArrayList的构造函数

    public ArrayList()    //默认构造函数
    public ArrayList(int initialCapacity)   //生成一个指定容量的空列表
    public ArrayList(Collection<? extends E> c)  //生成一个包含指定元素的列表
    

    3 ArrayList的Api

    void        trimToSize    //把列表的容量修剪成列表的实际容量,删除动态增长的多余容量。
    void        ensureCapacity(int minCapacity)   //根据传入的值对数组进行扩容,在数量已知的情况下
    void        ensureCapacityInternal(int minCapacity)    //私有方法,根据传入的值对数组进行扩容
    void        ensureExplicitCapacity(int minCapacity)   //传入数组进行扩容
    void        grow(int minCapacity)     //进行扩容
    int         hugeCapacity(int minCapacity)   //根据传入的值判断当前大小是否超过数组最大的大MAX_ARRAY_SIZE= Integer.MAX_VALUE - 8
    int         size()    //获取列表大小
    boolean     isEmpty()  //判断对象是否为空
    boolean     contains(Object o)   //判断是否包含某个对象
    int         indexOf(Object o)   //根据对象查询第一个索引下标
    int         lastIndexOf(Object o)    //根据对象查询最后一个索引下标
    Object      clone()   //对象进行复制
    Object[]    toArray()  //将列表对象转成Object数组
    T[]         toArray(T[] a)    //将列表对象转成某个固定对象的数组
    E           elementData(int index)    //通过下标访问对象,内部方法
    E           get(int index)    //通过下标访问对象
    E           set(int index, E element)    //替换某个下标位置上的对象
    boolean     add(E e)      //添加对象
    void        add(int index, E element)   //在某个位置上添加对象,如果当前位置有相应的对象,则位置往右递增
    E           remove(int index)     //删除某个对象通过下标
    boolean     remove(Object o)   //通过对象查找删除某个对象 通过equals判断
    void        fastRemove(int index)  //通过对象删除时的删除方法
    void        clear()       //数据清空
    boolean     addAll(Collection<? extends E> c)  //添加一个Collection队列到当前列表中
    boolean     addAll(int index, Collection<? extends E> c)  //从某个位置开始添加一个Collection队列到当前列中
    void        removeRange(int fromIndex, int toIndex)   //删除某个区间的数据
    void        rangeCheck(int index)   //验证当前下标是否在实际数据范围内
    void        rangeCheckForAdd(int index)   //添加数据到某个下标时 判断是否超过范围
    String      outOfBoundsMsg(int index)  //数组越界显示字段
    boolean     removeAll(Collection<?> c)    //删除传入的列表对象
    boolean     retainAll(Collection<?> c)      //获取两个元素的交集 并把数据存入前面的列表中 l1.retainAll(l2)
    boolean     batchRemove(Collection<?> c, boolean complement)   私有方法  //retainAll调用的内部方法    
    void        writeObject(java.io.ObjectOutputStream s)    //
    void        readObject(java.io.ObjectInputStream s)   //和WriteObject重写序列化方法
    ListIterator<E> listIterator(int index)   //返回一个ListIterator从下标位置开始
    ListIterator<E> listIterator()    //返回一个ListIterator接口的实现对象,下标从0开始
    Iterator<E> iterator()  //返回Iterator接口具体实现对象
    List<E>     subList(int fromIndex, int toIndex)  //返回开始和结束下标中的对象
    void        subListRangeCheck(int fromIndex, int toIndex, int size)   //判断取区间对象是是否
    void        forEach(Consumer<? super E> action)   //输出对象
    Spliterator<E> spliterator()    //生成一个Spliterator对象,用于遍历和分割队列 一般配合Collection的stream方法使用,1.8新增方法
    boolean     removeIf(Predicate<? super E> filter)   //移除满足条件的所有元素
    void        sort(Comparator<? super E> c)   //列表进行排序
    

    ArrayList的数据结构

    ArrayList里面的重要字段说明

    elementData:Object类型的数组,存放ArrayList添加进来的元素,是一个动态数组,大小会根据ArrayList的容量的增长而增长。
    size:ArrayList中实际数据的大小。
    modCount:实现fail-fast机制,不同线程对同一个集合进行操作是的错误机制

    ArrayList的重要方法源码解析

    //数据的添加
    public boolean add(E e) {   //添加一个数据元素
            ensureCapacityInternal(size + 1);  // Increments modCount!!    //确定ArrayList的大小
            elementData[size++] = e;   //添加e元素到ArrayList中 并ArrayList大小加1
            return true;
        }
    
    public void add(int index, E element) {  //添加一个元素到指定位置
            rangeCheckForAdd(index);   //判断当前位置是否越界(超出当前ArrayList大小和小于0)
    
            ensureCapacityInternal(size + 1);  // Increments modCount!!   //确定ArrayList的大小
            System.arraycopy(elementData, index, elementData, index + 1,
                             size - index);   //把新元素存放位置后面的元素往后移动一位
            elementData[index] = element;  //把新元素放到指定位置
            size++;  //ArrayList大小加1
        }
    
    public boolean addAll(Collection<? extends E> c) {  //往ArrayList中添加一个Collection集合
            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityInternal(size + numNew);  // Increments modCount  //把传入集合转为数组对象,通过长度确定ArrayList大小
            System.arraycopy(a, 0, elementData, size, numNew);  //把转为数组对象的Collection集合添加到ArrayList中
            size += numNew;
            return numNew != 0;
        }
    
    public boolean addAll(int index, Collection<? extends E> c) {  //添加一个Collection集合到ArrayList中的指定位置
            rangeCheckForAdd(index);
    
            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityInternal(size + numNew);  // Increments modCount  把传入集合转为数组对象,通过长度确定ArrayList大小
    
            int numMoved = size - index;
            if (numMoved > 0)
                System.arraycopy(elementData, index, elementData, index + numNew,
                                 numMoved);    //计算指定位置插入数据是原数据往后移动位置,并移动
    
            System.arraycopy(a, 0, elementData, index, numNew);  //把转为数组对象的Collection集合添加到ArrayList中
            size += numNew; //确定size
            return numNew != 0;
        }
    
    private void ensureCapacityInternal(int minCapacity) {    //确定ArrayList的大小
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {   //判断是否为默认创建的空元素
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);  //大小为默认大小和传进来大小去最大值
            }
    
            ensureExplicitCapacity(minCapacity);  
        }
    
    private void ensureExplicitCapacity(int minCapacity) {  //判断并确定ArrayList大小
            modCount++;   //证明进行了ArrayList的数据添加操作
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)   //如果传进来的大小大于现在数组大小,就对数组进行自增操作
                grow(minCapacity);
        }
    
    private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            int newCapacity = oldCapacity + (oldCapacity >> 1);  //自增的大小默认为原大小的1.5倍
            if (newCapacity - minCapacity < 0)   //如果自增大小小于添加数据后的带下,新的自增大小更改为传入数据大小
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)   //如果自增大小大于ArrayList中自定义最大大小,就把大小设置为int值得最大大小范围
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);  //数组进行自增
        }
    
    private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
        }
    
    //ArrayList数据删除
    public boolean remove(Object o) {   //通过对象删除对象 通过循环ArrayList中的元素查找到需要删除的对象进行删除
            if (o == null) {  
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
        }
    
    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; // clear to let GC do its work
        }
    
    protected void removeRange(int fromIndex, int toIndex) {  //删除一个范围内的数据
            modCount++;
            int numMoved = size - toIndex;  //通过删除最后的下标往前移动 然后把取消的数据设为null值
            System.arraycopy(elementData, toIndex, elementData, fromIndex,
                             numMoved);
    
            // clear to let GC do its work
            int newSize = size - (toIndex-fromIndex);
            for (int i = newSize; i < size; i++) {
                elementData[i] = null;
            }
            size = newSize;
        }
    
    public E remove(int index) {  //通过下标删除对象
            rangeCheck(index);  //判断指定位置是否在数据大小之中
    
            modCount++;
            E oldValue = elementData(index);  
    
            int numMoved = size - index - 1;  //是否需要移动 最后一个元素不需要移动其他位置的元素
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
            elementData[--size] = null; // clear to let GC do its work  //最后一个元素设为null值
    
            return oldValue;
        }
    
    public boolean removeAll(Collection<?> c) {  //删除ArrayList中存在的输入的集合的元素 
            Objects.requireNonNull(c);  //判断是否为空
            return batchRemove(c, false);
        }
    
    private boolean batchRemove(Collection<?> c, boolean complement) {
            final Object[] elementData = this.elementData;
            int r = 0, w = 0;
            boolean modified = false;  
            try {
                for (; r < size; r++)
                    if (c.contains(elementData[r]) == complement)   //complement:true 返回相同的元素 false 返回不同元素
                        elementData[w++] = elementData[r];
            } finally {
                if (r != size) {  //如果不等于证明前面报了异常,把后面的部分补全
                    System.arraycopy(elementData, r,
                                     elementData, w,
                                     size - r);
                    w += size - r;
                }
                if (w != size) {    //如果w!=size说明进行了删除操作,故需将删除的值赋为null
                    for (int i = w; i < size; i++)
                        elementData[i] = null;
                    modCount += size - w;
                    size = w;
                    modified = true;
                }
            }
            return modified;
        }
    
    public E get(int index) {  //通过下标返回数据 先判断下标是否正确
            rangeCheck(index);
    
            return elementData(index);
        }
    

    ArrayList的遍历方式

    1、通过迭代器的方式去实现,既Iterator的方式

    Iterator iterator = list.iterator;
    while(iterator.hasNext()){
        String value = iterator.next();
    }
    

    2、通过索引随机访问,ArrayList默认实现了RandomAccess

      for(int i = 0;i<size;i++){
        String value = list.get(i);
    }
    

    3、通过ForEach循环遍历

     for(String str:list){
        String value = str;
    }
    

    通过对比三种方式中随机访问的效率,迭代器的方式效率最低

    相关文章

      网友评论

          本文标题:ArrayList的介绍和源码解析

          本文链接:https://www.haomeiwen.com/subject/bwqmiftx.html