ArrayList源码学习-常用方法

 1、ArrayLis的几个申明

ArrayLis初始化容量为10

    private static final int DEFAULT_CAPACITY = 10;

空的数组实例

   private static final Object[] EMPTY_ELEMENTDATA = {};

也是一个空的数组实例,与EMPTY_ELEMENTDATA不同的是DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是用来判断何时

添加第一个元素,即何时初始化容量为默认大小

 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

存储ArrayList元素的数组缓冲区,ArrayList的容量是此数组缓冲区的长度。任何DEFAULTCAPACITY_EMPTY_ELEMENTDATA添加第一个元素时,将扩展为DEFAULT_CAPACITY

transient Object[] elementData; 

ArrayList真实的容量,即元素数量

 private int size;

ArrayLis的最大容量

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

1、ArrayLis的几个构造函数

(1)ArrayList(),这里使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA创建了一个容量为10的列表

 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

(2)ArrayList(int initialCapacity),这里传入指定大小的实例容量initialCapacity,initialCapacity大于0 时创建一个容量为initialCapacity的Object数组,initialCapacity等于0时创建一个没有默认初始容量的空数组,当小于0时抛出异常IllegalArgumentException

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

(3)ArrayList(Collection<? extends E> c),这里判断如果传入的集合元素不为空则构建一个具有特定元素的数组实例,否则返回一个空的数组实例

 public ArrayList(Collection<? extends E> c) {
        //将传入的列表转化为Object[]
        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 {
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

其中有这个注释: // c.toArray might (incorrectly) not return Object[] (see 6260652)及 if (elementData.getClass() != Object[].class)判断,这里涉及到jdk的一个bug,代号6260652。在http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652的描述为Arrays.asList(x).toArray().getClass() should be Object[].class,根据描述知道这个bug和Arrays有关,源代码如下:

 public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
  }

上面源码的ArrayList并不是java.util.ArrayList,而是Arrays的内部类。它继承自AbstractList,实现了Collection接口,代码如下

private static class ArrayList<E> extends AbstractList<E>
         implements RandomAccess, java.io.Serializable
  {
         private static final long serialVersionUID = -2764017481108945198L;
         private final E[] a;
         ......
         public int size() {
            return a.length;
         }
         ......
  }
     

可以看到这里的a不是 Object[],而是E[]这就是问题所在。

(4)trimToSize(),作用是将ArrayList的elementData数组设置为ArrayList实际的容量,删除动态增长的多余容量。

public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

(5)ensureCapacity(int minCapacity),用于ArrayList的容量扩增

public void ensureCapacity(int minCapacity) {
        //这里获取最小的扩增容量,即DEFAULTCAPACITY_EMPTY_ELEMENTDATA
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            ? 0
            : DEFAULT_CAPACITY;
        //判断当实际需要的容量小于minExpand 时确保扩容
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
private void ensureExplicitCapacity(int minCapacity) {
        //计数器+1
        modCount++;

        // 当需要的实际容量大于elementData元素长度时进入grow(),这里面是实际的扩容实现
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

grow()是扩容的具体实现

private void grow(int minCapacity) {
        // 原容量
        int oldCapacity = elementData.length;
         // 在原容量的基础上扩容1.5倍为新容量
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果newCapacity小于minCapacity(最小容量)则以minCapacity为准
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
          //newCapacity比最大长度还大,则以Integer.MAX_VALUE作为容量
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //将元素手动复制到容量大小为newCapacity的数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

hugeCapacity(minCapacity)是获取最大容量值

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

(6)size() ,返回元素数量

public int size() {
        return size;
    }

(7)isEmpty()将数组的元素数量置为0

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

(8) contains(Object o)是否包含某个元素,核心实现还是indexOf()

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

(9)indexOf(Object o),从第一个元素开始查找是否包含某个元素:

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

(10)lastIndexOf(Object o),从最后一个元素开始查找是否包含某个元素,反序遍历:

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

(11)toArray():通过复制的方式返回一个包含指定元素,指定大小的Object[]

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

(12)get(int index) 返回指定下标的元素

 public E get(int index) {
        //检查下标是否越界
        rangeCheck(index);

        return elementData(index);
    }
 private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
E elementData(int index) {
        return (E) elementData[index];
    }

(13)toArray(T[] a)   返回一个包含列表所有元素的数组,若指定数组和列表大小就在数组中返回元素,否则,重新申请数组空间,若指定数组空间有多余,则把多余空间设为null

 public <T> T[] toArray(T[] a) {
    		//如果传入数组的长度小于size,返回一个新的数组,大小为size,类型与传入数组相同
        if (a.length < size)
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        //否则,将elementData复制到传入数组并返回传入的数组
        System.arraycopy(elementData, 0, a, 0, size);
        //若传入数组长度大于size,把返回数组的第size个元素置为空
        if (a.length > size)
            a[size] = null;
        return a;
    }

(13)set(int index, E element)  将列表中指定位置的元素替换为指定元素

public E set(int index, E element) {
        //下标越界检查
        rangeCheck(index);
        //获取旧元素
        E oldValue = elementData(index);
        //用新元素替换旧元素
        elementData[index] = element;
        return oldValue;
    }

(14)add(E e) 在列表中添加一个元素

public boolean add(E e) {
    	//确保不会产生越界
        ensureCapacityInternal(size + 1);  
        //将元素放在列表尾部
        elementData[size++] = e;
        return true;
    }

(15)add(int index, E element)  在列表指定位置添加元素

 public void add(int index, E element) {
        //范围检查
        rangeCheckForAdd(index);
        //调用扩容方法确保容量足够
        ensureCapacityInternal(size + 1);  
        //调用System.arraycopy方法//调用System.arrayCop将elementData从Index开始的size至index元素复制到index+1至size+1的位置,即index开始的元素都向后移动一个位置
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //将Index位置的值指向element
        elementData[index] = element;
        size++;
    }
 private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

(16)remove(int index) 删除指定下标的元素

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
          
       //返回被删除的元素
        return oldValue;
    }

(17)remove(Object o) 返回指定元素

 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;
    }
//快速删除,不做范围检查,不反悔删除的元素
 private void fastRemove(int index) {
        modCount++;
         //重新计算大小
        int numMoved = size - index - 1;
        if (numMoved > 0)
         //复制数据并且平移剩余元素
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //将最后一个下标置空,等待GC回收
        elementData[--size] = null; 
    }

(18)clear() 清空数组列表

 public void clear() {
        modCount++;

        // 将所有元素置空,并且把数组容量置0
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

(19)addAll(Collection<? extends E> c) 将指定集合中的元素添加到集合中

    public boolean addAll(Collection<? extends E> c) {
         //将传入的集合转成Object数组
         Object[] a = c.toArray();
        //获取传入的集合数组长度
        int numNew = a.length;
        //通过数组长度和原列表容量对原列表容量进行扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //通过复制将列表元素追加到列表尾部
        System.arraycopy(a, 0, elementData, size, numNew);
        //实际容量大于0时返回true
        size += numNew;
        return numNew != 0;
    }

(20)addAll(int index, Collection<? extends E> c) 将指定集合中的所有元素从指定位置开始插入到此列表中

 public boolean addAll(int index, Collection<? extends E> c) {
        //范围检查
        rangeCheckForAdd(index);
        //将传入的集合转成数组
        Object[] a = c.toArray();
        //计算数组大小
        int numNew = a.length;
        //对列表扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //如果列表容量大于数组长度,则把数组元素追加到列表尾部,否则把列表元素插入到传入的数组中
        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;
    }

(21)removeRange(int fromIndex, int toIndex)  按照下标范围删除元素

 protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        //将elementData从toIndex位置开始的元素向前移动到fromIndex
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // 将toIndex位置之后的元素全部置空
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        //修改size 
        size = newSize;
    }

(22)removeAll(Collection<?> c)   从此列表中删除包含传入的集合中的所有元素

public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

(23)retainAll(Collection<?> c)  从列表中删除所有其未包含在指定的集合中的元素,即求两个集合的交集

 public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

retainAll(Collection<?> c) 和removeAll(Collection<?> c)的核心实现都是batchRemove(c, true);其中Objects.requireNonNull(c);是判断传入的集合是否为空,为空则抛出空指针异常。

对于batchRemove(c, true)的第二个参数,假设elementData和 集合c的交集是A: 当 complement == true 时,elementData最终只会存储A 当 complement == false 时,elementData最终删除A。

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)
                    elementData[w++] = elementData[r];
        } finally {
            //即 r != size时出现异常,所以把从r位置开始的(size-r)个元素复制到从w开始的到(w+size-r-1)位置,此时 w = size - r,这样就可以保证在出现异常之前已经遍历的c和elementData中的相同元素已经被覆盖了,同时也保证了从r位置开始的(size-r)个元素向左移动了(r-w)位,保证数组元素的完整性。然后将w~(size-1)位置的元素置空,这样即使发生了异常,也不会导致删除错误
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
           //当 w != size 时,出现elementData中有,但c中没有的元素的时候,就会存放在 elementData[w]中,也就是说0~(w-1)位置一定是elementData包含但是c中没有的元素,然后将w~(size-1)位置的元素置空,elementData中就只剩下除去和c中相同元素的数组了,它的size为w
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

(24)listIterator(int index)  返回从index下标开始的listIterator对象

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

(25)listIterator()  返回所有元素的listIterator对象

  public ListIterator<E> listIterator() {
        return new ListItr(0);
    }

(26)iterator()  返回所有元素的Iterator对象

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值