【Java源码】基于数组实现的ArrayList(下)

 接着上篇

目录

 addAll (Collection c)   增加

 addAll (int index, Collection c)   增加

 removeAll (Collection c)  在集合中,删除与Collection中元素相等的元素

 subList (int fromIndex, int toIndex) 根据起始下标返回一个List(不包括toIndex下标元素)

 Sort 排序

 迭代器


 addAll (Collection c)   增加

    public boolean addAll(Collection c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

  这个增加是把一整个“集合”全部增加进去,同add方法一样

  主要使用ensureCapacityInternal方法,在上篇说过这个,在确定有容量可以增加的时候再使用System.arraycopy方法增加元素。

addAll (int index, Collection c)   增加

    public boolean addAll(int index, Collection 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;
    }

  相比上面的那个addAll,这个加入了一个新的参数,下标。以实现可以在指定下标处添加一个“集合”

   有下标就必然要判断下标的合法性。要增加就必须考虑是否有足够容量可以add

  第一个arraycopy将ArrayList数组指定下标及其之后元素后移,以确保这里的空间存放c  (roArray后是a)

  第二个arraycopy将a添加到上面空间中

  System.arraycopy(原数组, 原数组起始下标, 目标数组, 目标数组起始下标, 复制长度)

  removeAll (Collection c)  在集合中,删除与Collection中元素相等的元素

    public boolean removeAll(Collection c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }
    public static  T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

  首先判断参数collection是否存在,如果为null,则抛出异常

  接下来是其核心的batchRemove (Collection c, boolean complement)   批量移除

    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 {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            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;
    }

  第一个for循环将有效元素(ArrayList数组中有并且不在c中的元素)都放在前面,并记录有效元素的个数w 

  即,目前ArrayList数组前w个元素与collection不同,(这个取决于complement)  false 不同   true 相同

  然后判断了 r != size , 经过循环后r怎么能不等于size呢,别忘了contains可能抛出异常,这样就完成了对元素“排列”并计数;

  根据计数(w),将w及其之后的元素(这些元素现在都是重复元素)设为null,以便回收。

  若不执行上述操作,即没有删除任何数据,返回false

  subList (int fromIndex, int toIndex) 根据起始下标返回一个List(不包括toIndex下标元素)

    public List subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }

有下标就要对下标进行检查判断sublistRangeCheck,不多说了

SubList(AbstractList parent,int offset, int fromIndex, int toIndex)

 Sort 排序

    @Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

  这里用到了Arrays自己的sort方法 (默认字典序)

  迭代器

    public Iterator iterator() {
        return new Itr();
    }   

    private class Itr implements Iterator {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = 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);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

 迭代器采用了以内部类方式实现了Iterator接口

  cursor  是一个游标

  lastRet 末尾标志,最后一个返回元素的位置,-1表示不存在

  expectedModCount   预想模式??? = count???  现在知道前面好多方法都有count++的原因了  这应该是一个标识,用                                          来检查在使用迭代器的同时,ArrayList有没有被外面修改

  hasNext()  只需检查游标有没有到size,返回true或者false  

                    如果仍有元素可以迭代或有多个元素,则返回 true。

  next()   返回迭代的下一个元素。

  remove()  从迭代器指向的 collection 中移除迭代器返回的最后一个元素,并将游标移动到此处,证明此处是有元素的,这也就                     同时解释了没有用 == null判断了

  checkForComodification()   用来检查在使用迭代器的同时,ArrayList有没有被外面修改的方法

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

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

    private class ListItr extends Itr implements ListIterator {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

 有了对上面迭代器的理解,这个升级版就很容易理解了

 

 通过对ArrayList的源码解析,发现

  1.它是由数组来实现的

  2.它并不是无限大的

  3.频繁的用到System.arraycopy方法,说明其内部就是不断地产生新数组,复制,完成扩容的

  4.ArrayList并不是线程安全的,里面没有使用同步方法

 

 新手第一次看源码,若有错误,望各位大佬多多指点更正

你可能感兴趣的:(java)