jdk1.8----ArrayList源码解析

                                                     jdk1.8----ArrayList源码解析

1.ArrayList类的结构

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 Object[] EMPTY_ELEMENTDATA = {};

    //空数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 存放元素的数组
     * 任何空数组(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
     * 在新增第一个元素的时候将会把容量扩充到DEFAULT_CAPACITY即10
     */
    transient Object[] elementData; // non-private to simplify nested class access
    
    //大小(实际上是包含的元素个数)
    private int size;
      其中,用transient关键字来修饰elementData这个数组变量,实际上表明这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。

    总之,java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

2.ArrayList构造函数

 ArrayList构造函数分别有三个构造函数,分别是:构造一个指定初始容量的空列表、构造一个空列表和构造一个包含指定collection的元素的列表

    // 构造一个指定初始容量的空列表
    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的元素的列表,这些元素按照该collection的迭代器返回的顺序排列的
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

3.添加元素

  1).add(E e):在列表的末尾添加指定的元素

 //在列表的末尾添加指定的元素
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

    //用于添加元素时,确保数组容量
    private void ensureCapacityInternal(int minCapacity) {
        //如果是空列表,那么取默认值DEFAULT_CAPACITY即10与参数minCapacity两者的最大值作为数组容量的预设值
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    //如果参数大于当前数组的容量,就增加数组容量
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//list的结构变化的次数加1,最初值为0

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * 分配给数组的最大容量值
     * 有些虚拟机在数组中预留一些头信息,所以尝试分配给数组更大容量时,可能导致内存溢出(数组的容量超出了虚拟机的限制)
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    //增加容量以确保新容量值至少是参数要求的
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//旧容量的1.5倍
        //取旧容量的1.5倍和参数两者的最大值作为预设值
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //若预设值大于默认的最大值,则检查是否溢出,并确认最终的预设值
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    //检查是否溢出,若没有溢出,返回最大整数值(java中的int为4字节,所以最大为0x7fffffff)或默认最大值
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }
  其中变量modCount是在其父类AbstractList中定义的,具体如下:   

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {

    //list结构变化的次数,其中结构变化指list的大小即list包含元素的个数的变化
    protected transient int modCount = 0;

}

具体,一个空的ArrayList新增一个元素即调用add(E e)方法,具体的实现逻辑如下:

     i)首先执行ensureCapacityInternal(size + 1),此时size值为0,所以执行ensureCapacityInternal(1)

     ii)执行ensureCapacityInternal(1),由于当前的ArrayList是空列表,所以执行 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);取默认值DEFAULT_CAPACITY即10与参数minCapacity也就是1两者的最大值作为数组容量的预设值即10,然后执行ensureExplicitCapacity(10);

     iii)执行ensureExplicitCapacity(10),modCount自增,此时modCount值为1;由于参数大于当前数组的容量即为0,所以增加数组容量即执行grow(10);

     iv)执行grow(10),取旧容量的1.5倍即0和参数即10两者的最大值作为预设值即10,然后执行elementData = Arrays.copyOf(elementData, newCapacity);即把长度为10的空数组赋值给elementData,即空的ArrayList在新增第一个元素的时候将会把容量扩充到DEFAULT_CAPACITY即10

     v)然后执行elementData[size++] = e;此时size为0,elementData数组index为0赋值e,然后size自增  


2)add(int index, E element):将指定的元素即E element插入此列表中的指定位置即index

 //将指定的元素即E element插入此列表中的指定位置即index
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        //判断是否需要扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);//将数组中从index位置开始后的size-index个元素统一后移一位
        elementData[index] = element;//给指定的位置即index赋值
        size++;//列表的大小加1,即列表包含的元素个数加1
    }

    //判断index是否合法
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

3)addAll(Collection<? extends E> c) :按照特定的迭代顺序把指定集合的所有元素添加到列表的末尾

    //按照特定的迭代顺序把指定集合的所有元素添加到列表的末尾
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        //判断当前list的容量是否满足添加指定集合所有元素,如果不满足则进行扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //把集合的所有元素添加到数组的末尾(实际上将集合转化为数组),共numNew个,即将数组a[0,...,numNew-1]复制到数组elementData[size,...,size+numNew-1]
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;//列表的大小+numNew
        return numNew != 0;
    }

   4)addAll(int index, Collection<? extends E> c):从指定的位置开始,将指定collection中的所有元素插入到此列表中,新元素的顺序为指定collection的迭代器所返回的元素顺序     

    //从指定的位置开始,将指定collection中的所有元素插入到此列表中,新元素的顺序为指定collection的迭代器所返回的元素顺序
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);//校验index是否合法

        Object[] a = c.toArray();
        int numNew = a.length;
        //判断当前list的容量是否满足添加指定集合所有元素,如果不满足则进行扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;//需要移动的元素个数
        if (numMoved > 0)
            //先将数组elementData[index,...,index+numMoved-1]复制到elementData[index+numMoved,...,index+2*numMoved-1]
            //即,将原数组中从index位置开始的后numMoved个元素统一后移numNew位
            System.arraycopy(elementData, index, elementData, index + numNew,
                    numMoved);
        //再将由集合转化来的数组a[0,...,numNew-1]复制到数组elementData[index,...,index+numNew-1]
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;//列表的大小+numNew
        return numNew != 0;
    }

    5)set(int index, E element):用指定的元素即E element取代在指定位置即index上的元素,并返回在指定位置即index上的旧元素

   //用指定的元素即E element取代在指定位置即index上的元素,并返回在指定位置即index上的旧元素
    public E set(int index, E element) {
        rangeCheck(index);//校验index是否合法

        E oldValue = elementData(index);
        elementData[index] = element;//赋值新元素
        return oldValue;
    }

    //校验index是否合法
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    //得到指定位置即index上的元素
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

4.查找元素

   1)get(int index):得到列表中指定位置即index上的元素   

 //得到列表中指定位置即index上的元素
    public E get(int index) {
        rangeCheck(index);//校验index是否合法

        return elementData(index);
    }
   2)indexOf(Object o) :返回指定元素第一次出现在列表中的位置即index,如果不存在指定元素,则返回-1

    //返回指定元素第一次出现在列表中的位置即index,如果不存在指定元素,则返回-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;
    }

     3) lastIndexOf(Object o) :返回指定元素最后一次出现在列表中的位置即index,如果不存在指定元素,则返回-1

  //返回指定元素最后一次出现在列表中的位置即index,如果不存在指定元素,则返回-1
    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;
    }

    4.contains(Object o):返回列表是否包含指定元素

  //返回列表是否包含指定元素
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

     5.删除元素

       1)remove(int index):删除列表中指定位置即index上的元素     

 //删除列表中指定位置即index上的元素
    public E remove(int index) {
        rangeCheck(index);//校验index

        modCount++;//列表结构变化次数加1
        E oldValue = elementData(index);//将要删除的元素值

        int numMoved = size - index - 1;//需要往前移动的元素个数
        if (numMoved > 0)
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);//将数组elementData中index位置之后的所有元素向前移一位
        //将原数组最后一个位置置为null,由GC清理
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
       2)remove(Object o):删除列表中第一次出现的指定元素,如果列表中包含指定元素则返回true,反之返回false
 //删除列表中第一次出现的指定元素,如果列表中包含指定元素则返回true,反之返回false
    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;
    }

    //删除列表中指定位置即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; // clear to let GC do its work
    }
       3)clear():清空列表,将全部的元素设为null

 //清空列表,将全部的元素设为null
    public void clear() {
        modCount++;//列表结构变化次数加1

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;//将全部的元素设为null

        size = 0;//列表的大小置为0,即列表包含的元素个数为0
    }
      4)removeRange(int fromIndex, int toIndex):删除list中从fromIndex(包含)到toIndex(不包含)之间所有的元素     

  //删除list中从fromIndex(包含)到toIndex(不包含)之间所有的元素
    protected void removeRange(int fromIndex, int toIndex) {
        modCount++;//列表结构变化次数加1
        int numMoved = size - toIndex;//需要往前移动的元素个数
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                numMoved);//将原数组中从toIndex位置开始之后的所有元素统一往前移动toIndex - fromIndex位

        // clear to let GC do its work
        int newSize = size - (toIndex - fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;//把元素赋值为null
        }
        size = newSize;//重新赋值list的大小
    }
     5)removeAll(Collection<?> c):删除列表中存在于指定集合中的所有元素
  //删除列表中存在于指定集合中的所有元素
    public boolean removeAll(Collection<?> c) {
        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 {
            //遍历数组,遍历时根据参数complement决定是否保留该元素,如果complement为false代表保留不在指定集合中的元素,反之保留存在指定集合中的元素
            //并把保留的元素放在数组的前面,实际上是保留的元素依次存放于elementData[0,....,w-1]
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            //如果r!=size,则说明出现异常了。此时把还没遍历的数组元素添加到到数组elementData的末尾,共size-r个
            if (r != size) {
                System.arraycopy(elementData, r,
                        elementData, w,
                        size - r);
                w += size - r;
            }
            //如果w!=size,说明需要删除数组中的元素,反之不需要删除
            if (w != size) {
                // clear to let GC do its work
                //把需要删除的存储空间删除,实际上是elementData[w,...,size-1]
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;//list的结果变化次数加(size-w)
                size = w;//list的大小为w
                modified = true;
            }
        }
        return modified;
    }
       6)retainAll(Collection<?> c):删除列表中不存在于指定集合中的所有元素      
//删除列表中不存在于指定集合中的所有元素
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);//校验集合是否为空
        return batchRemove(c, true);
    }

   5.其他public方法

    1)trimToSize():将list容量调整为当前list的大小即实际包含元素的个数   

    //将list容量调整为当前list的大小即实际包含元素的个数
    public void trimToSize() {
        modCount++;//list结构变化次数加1
        if (size < elementData.length) {//如果list的容量elementData.length大于list的大小即size
            elementData = (size == 0)//如果list的大小为0则,数组为空数组;反之数组赋值为一个包含list中所有元素的数组,即原数组elementData[0,...size-1](实际上Arrays.copyOf返回一个新数组,是浅拷贝)
                    ? EMPTY_ELEMENTDATA
                    : Arrays.copyOf(elementData, size);
        }
    }
    2)size():返回list包含元素的个数    

 //返回list包含元素的个数
    public int size() {
        return size;
    }
    3)isEmpty():如果list不包含元素即为空,则返回true,反之返回false

 //如果list不包含元素即为空,则返回true,反之返回false
    public boolean isEmpty() {
        return size == 0;
    }

     4) toArray():返回一个包含list所有元素的数组

//返回一个包含list所有元素的数组
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    5)iterator():返回一个按照特定顺序遍历list所有元素的迭代器  

 //返回一个按照特定顺序遍历list所有元素的迭代器
    public Iterator<E> iterator() {
        return new Itr();
    }

   private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such返回上一个元素的位置即index,如果没有则返回-1
        int expectedModCount = modCount;//迭代器期待的expectedModCount初始值为list的结构变化次数modCount

        //判断是否有下一个元素
        public boolean hasNext() {
            return cursor != size;
        }

        //返回当前位置的元素
        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;//遍历指针往后移一位
            return (E) elementData[lastRet = i];
        }

        //删除当前位置的元素
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);//删除当前位置的元素,此时list结构变化次数modCount+1
                cursor = lastRet;//遍历指针指向当前位置
                lastRet = -1;
                expectedModCount = modCount;//迭代器期待的expectedModCount重新赋值为list结构变化次数modCount,这句话很重要
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        //判断list结构变化次数modCount是否和迭代器期待的expectedModCount相等
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
    注意:如果遍历list,然后删除满足条件的元素,一定要用Iterator的remove()方法,不能用list的remove()方法,否则会引起Fail-fase事件的产生(在遍历list的时候,不允许更改list的结构,如果要更改,需要调用迭代器的remove()方法,详情请看:http://blog.csdn.net/lululove19870526/article/details/70808903


 

 

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值