[java][集合]ArrayList的详解与源码分析(基于java8)

ArrayList简介

ArrayList是一个数组队列,底层是这个类的一个成员变量(Object[] elementData ),容量可以实现动态改变。 和数组一样可以实现添加(add方法)、修改(set方法)、删除(remove 方法)、遍历。ArrayList实现了Serializable接口(可以实现对象流的序列化和反序列化)、Cloneable接口、RandomAccess接口(标记接口可以实现随机访问)、List接口,继承了AbstractList。

下面介绍三种ArrayList的遍历方法

使用迭代器遍历

Iterator<Integer> it = arrayList.iterator();
while(it.hasNext()){
    System.out.print(it.next() + " ");
}

foreach循环遍历

for(Integer number : arrayList){
   System.out.print(number + " ");
}

引索值遍历

for(int i = 0; i < arrayList.size(); i++){
   System.out.print(arrayList.get(i) + " ");
}

注意:迭代器和foreach(底层还是迭代器)不能使用集合的方法修改元素,否则会抛出并发修改异常。具体请参考点击打开链接其中引索值遍历效率最高,因为底层是使用数组的遍历。

源码分析

1常量和变量

private static final long serialVersionUID = 8683452581122892189L;//版本号
private static final int DEFAULT_CAPACITY = 10;//默认数组容量
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(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;
        }

    带Collection类型参数的构造器

     public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();//将Collection转化为数组并赋值给elementData
            if ((size = elementData.length) != 0) {//如果转化后的数组长度不为0则进入for语句,否则创建一个空集合
                if (elementData.getClass() != Object[].class)//判断元素是否是是Object类型,如果不是则转化为Object类型
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
            } else {
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }

3常用方法

trimToSize将集合多余的元素(包括null)去除

 public void trimToSize() {
        modCount++;//从AbstractList继承用来表示集合修改的次数
        if (size < elementData.length) {//只有当集合元素的个数<部内数组的长度时(也就是有空元素)
            elementData = (size == 0)//三目元算
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

ensureCapacity提升集合的容量以确保可以至少可以装下minCapacity的元素

 public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY;
        //判断是否为空集合,如果不是则minExpand=0,若果是minExpend=10   
        if (minCapacity > minExpand) {//如果minCapacity小于minExpand则说明集合的容量够装下minCapacity个元素
            ensureExplicitCapacity(minCapacity);//minCapacity大于minExpaind则进行扩容,扩容的方式为10个10个的增加,参考add方法
        }
    }

grow增加集合容量,ArrayList的核心方法

 private void grow(int minCapacity) {
        int oldCapacity = elementData.length;//获取ArrayList中elementData数组的长度
        int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容到1.5倍
        if (newCapacity - minCapacity < 0)//判断新数组的容量够不够minCapacity,够了就用mincapacty创建新数组,不够就用1.5倍的那个
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)//判断有没有超过最大长度
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

size返回集合元素的个数

 public boolean isEmpty() {
        return size == 0;
    }

isEmpty判断集合是否为空

  public boolean isEmpty() {
        return size == 0;
    }

contains判断集合是否包含指定对象

  public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

indexOf返回集合中第一次出现指定对象的位置

    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;//如果没有次对象则返回-1
    }

lastIndexOf返回指定对象在集合中最后一次出现的位置

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

clone重写Object的clone方法,返回一个具有相同元素的副本

   public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }

toArray将结合转化成数组/数组转换成集合可以用asList

 public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

get获取指定下标的元素

   public E get(int index) {
        rangeCheck(index);//检查index是否超过size,超过就抛数组下标越界异常
        return elementData(index);
    }

set用指定对象替换指定下标的元素

    public E set(int index, E element) {
        rangeCheck(index);
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

add添加元素

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);//扩容
        elementData[size++] = e;
        return true;
    }

add的重载方法,在指定位置插入元素

    public void add(int index, E element) {
        rangeCheckForAdd(index);//判断是否越界
        ensureCapacityInternal(size + 1);  // 扩容
        System.arraycopy(elementData, index, elementData, index + 1,//将源数组下标为index长度为size-index的连续元素复制到新数组中,从index+1的位置开始复制。
                         size - index);
        elementData[index] = element;
        size++;
    }

addAll将指定集合添加到集合中

   public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();//将指定集合转化为数组
        int numNew = a.length;//取到a数组的长度
        ensureCapacityInternal(size + numNew);  //扩容
        System.arraycopy(a, 0, elementData, size, numNew);//将a数组从0下标开始numNew个元素复制到elementData数组从size下标开始
        size += numNew;
        return numNew != 0;
    }

addAll重载方法,在指定位置插入指定集合

    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);
        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,numMoved);
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

remove删除指定下标元素

    public E remove(int index) {
        rangeCheck(index);//判断是否越界
        modCount++;//集合修改次数加一
        E oldValue = elementData(index);//读取原来这个下标的元素
        int numMoved = size - index - 1;//index后面的元素个数
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index, numMoved);//源数组第index+1个元素开始数量为numMoved,复                                                                                    制到新数组的index下标开始
        elementData[--size] = null; //size个数减一,将最后一个元素设为null
        return oldValue;
    }

remove重载方法,删除指定元素,只删除第一次

    public boolean remove(Object o) {
        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;
    }

clear清除所有元素

   public void clear() {
        modCount++;
        for (int i = 0; i < size; i++)
            elementData[i] = null;//将所有元素都设为null
        size = 0;
    }

removeRange删除指定范围所有元素

    protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

removeAll删除指定集合里的所有元素

    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);//判断c是否为空    
        return batchRemove(c, false);
    }

batchRemove根据complement值将ArrayList中包含c中元素删除或保留

    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;//定义一个r,一个w两个指针同时右移
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)//如果c中不包括elementData[r]这个元素
                    elementData[w++] = elementData[r];//则直接将位置上的元素赋给w位置上的元素,w自增
        } finally {
            if (r != size) {//防止抛出异常导致上面r右移过程没有完成
                System.arraycopy(elementData, r,elementData, w,size - r);//
                w += size - r;
            }
            if (w != size) {//如果有悲覆盖掉的元素,则将w后面的元素都赋值为null
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;//修改size为w
                modified = true;
            }
        }
        return modified;
    }

listIterator重载方法,从指定下标创建迭代器

    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }

iterator创建一个Iterator迭代器

    public Iterator<E> iterator() {
        return new Itr();
    }

Iterator和ListIterator的区别:

https://blog.csdn.net/NGUhuang/article/details/80378804

subList创建一个子集合,并没有创建新的集合

   public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);    //fromIndex是否小于0,toIndex是否大于size,fromIndex是否大于toIndex
        return new SubList(this, 0, fromIndex, toIndex);//创建一个SubList内部类对象
    }
    原文作者:java集合源码分析
    原文地址: https://blog.csdn.net/NGUhuang/article/details/80373275
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞