Arraylist翻译分析

时间:2020-8-3 作者:admin

public class ArrayList<E> extends AbstractList<E>

        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

{      //序列号UID,代表版本,私有的静态常量

    private static final long serialVersionUID = 8683452581122892189L;

 

    /**

     *定义数组初始化默认长度为10,静态常量

     */

    private static final int DEFAULT_CAPACITY = 10;

 

    /**

     *用于空实例的数组,静态私有的,空实例意味着创建时为,空,

       *类型为object(相当于泛型,即任何类型都可以)

   */

    private static final Object[] EMPTY_ELEMENTDATA = {};

 

    /**

     * 用于默认大小的空实例的共享空数组实例。我们

将其与EMPTY_ELEMENTDATA区分开来,以便知道何时膨胀多少

添加第一个元素。

静态私有数组对象常量    

 */

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

 

    /**

     * 存储ArrayList元素的数组缓冲区。

ArrayList的容量是这个数组缓冲区的长度。任何

空ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA

当添加第一个元素时是否扩展为DEFAULT_CAPACITY     */

    transient Object[] elementData; // non-private to simplify nested class access

 

    /**

     * ArrayList的大小(包含的元素数量)。

       *  私有的int类型,默认为0

     *

     * @serial

     */

    private int size;

 

    /**

     * 构造器

     *

     * @param  initialCapacity  参数initialCapacity为arraylist容量

     * @throws  如果参数容量为负数,则抛出异常IllegalArgumentException

//如果传递的参数长度>0,给数组缓冲区赋值长度,长度为传递的参数长度

//如果传递参数长度为0,将empty_elementdata这个空数组给elemendata

//如果传递参数小于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);

        }

    }

 

    /**

     *无参构造,这个arraylist的初始长度为10

     */

    public ArrayList() {

        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

    }

 

    /**

     * 构造一个包含指定集合元素的列表,按照集合的迭代器返回元素的顺序     *

     * @param 参数是个集合。集合中包括要将其元素放置到arraylist中

     * @throws如果指定传递参数的集合元素为空,则抛出空指针异常

//1.调用collection的toArray方法,但是因为collection是接口,其实就是相当于调用传递进来的参数的toArray方法,toArray方法的目的返回包含此集合中所有元素的数组。

如果此集合保证其迭代器返回元素的顺序,则此方法必须以相同的顺序返回元素。

返回的数组将是“安全的”,因为这个集合不维护对它的引用。(换句话说,这个方法必须分配一个新的数组,即使这个集合由一个数组支持)。因此,调用者可以自由地修改返回的数组。

此方法充当基于数组和基于集合之间的桥梁

2.然后集合容器转换为数组之后,再赋值给elementData

3.将elemendata的长度赋值给size,再把size属性进行判断

4. c.toArray 被重写可能返回的有可能不返回一个 Object 数组,所以需要进行类型匹配判断

例如:

String.class 是能对类名的引用取得在内存中该类型class对象的引用,而new String().getClass() 是通过实例对象取得在内存中该实际类型class对象的引用

5.如果类型不一致,调用Arrays.copyof进行复制操作,底层调用本地方法system.copyof

,然后返回一个泛型数组,再将这个泛型数组赋值给elementData,即地址赋值,注意这里的elementdata属性不是私有的,也不是常量

6.如果类型一致,直接将elemendata赋值给EMPTY_ELEMENTDATA;

 

     */

public ArrayList(Collection<? extends E> c) {

        elementData = c.toArray();

        if ((size = elementData.length) != 0) {

         

            if (elementData.getClass() != Object[].class)

                elementData = Arrays.copyOf(elementData, size, Object[].class);

        } else {

            // replace with empty array.

            this.elementData = EMPTY_ELEMENTDATA;

        }

    }

 

    /**

     * 1.将这个<tt>ArrayList</tt>实例的容量调整为列表的当前大小。应用程序可以使用这个操作来最小化<tt>ArrayList</tt>实例的存储。

Mount是AbstractList中的,由迭代器和列表迭代器使用,目的是为了防止属性意外的改变. 如果这个字段的值意外变化,迭代器(或列表迭代器)将抛出一个{@code ConcurrentModificationException}来响应{@code next}, {@code remove}, {@code previous},提供了快速的故障行为,而不是在迭代期间面对并发修改时的非确定性行为。

2.判断size和缓冲长度的大小,如果size小于缓冲数组的长度,再判断size是否等于0,如果size等于0,则返回EMPTY_ELEMENTDATA,否则就用Arrays.copyof对elementada进行自我复制,新的elementdata的长度为实际有效个数size

     */

    public void trimToSize() {

        modCount++;

        if (size < elementData.length) {

            elementData = (size == 0)

              ? EMPTY_ELEMENTDATA

              : Arrays.copyOf(elementData, size);

        }

    }

 

    /**

     *如果需要,增加这个<tt>ArrayList</tt>实例的容量,以确保它至少可以容纳最小容量参数指定的元素数量。     *

     * @param   minCapacity   描绘期望的最小容量

       1.先定义一个最小期望

2.判断elementdata是否等于默认大小的空实例的共享空数组实例

       3.如果等于,则返回0给最小期望,如果不等于,则返回10给最小期望

       4.再判断传递进来的形参和最小期望的关系

       5.如果形参大于最小期望,调用ensureExplicitCapacity方法,此时把接收的minCapacity继续当作形参传给ensureExplicitCapacity

     */

    public void ensureCapacity(int minCapacity) {

        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)

            // any size if not default element table

            ? 0

            // larger than default for default empty table. It’s already

            // supposed to be at default size.

            : DEFAULT_CAPACITY;

 

        if (minCapacity > minExpand) {

            ensureExplicitCapacity(minCapacity);

        }

    }

       //定义私有的静态方法calculateCapacity,计算出实际长度,该方法形参为elementData和传入的最小长度,如果传递的elementData地址等于默认共享数组的地址,返回传入最小长度和10之中的最大值,如果地址不等,返回传入的最小长度

    private static int calculateCapacity(Object[] elementData, int minCapacity) {

        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

            return Math.max(DEFAULT_CAPACITY, minCapacity);

        }

        return minCapacity;

    }

//定义私有ensureCapacityInternal方法,方法里面调用的是ensureExplicitcapacity,传递的长度为调用计算长度方法算出的实际长度

    private void ensureCapacityInternal(int minCapacity) {

        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));

    }

//定义私有的ensureExplicitCapacity,传入实际长度,然后如果传入的实际长度减去elementData的长度大于0,调用grow方法进行扩容

    private void ensureExplicitCapacity(int minCapacity) {

        modCount++;

 

        // overflow-conscious code

        if (minCapacity – elementData.length > 0)

            grow(minCapacity);

    }

 

    /**

     *要分配的数组的最大大小。一些虚拟机在数组中保留一些头字。

尝试分配更大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制,定义最大长度为intgeter的最大值减去8

     */

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

 

    /**

     *增加容量,以确保它至少可以容纳最小容量参数指定的元素数量。

1.定义老的长度=elementData的长度,

2.定义新的长度等于数组长度的1.5倍

3.如果新的长度减去传进来的实际长度小于0,把传进来的实际长度赋值给新的长度

4.如果新的数组长度减去上面定于的最大数组长度大于0,即为即将超过integer范围,调用hugeCapacity方法扩充数组长度

5.否则,调用Arrays.copyof进行自我赋值,长度为原来1.5倍,其实即数组实际长度没达到之前的1.5倍

     * @param minCapacity the desired minimum capacity

     */

    private void grow(int minCapacity) {

        // overflow-conscious code

        int oldCapacity = elementData.length;

        int newCapacity = oldCapacity + (oldCapacity >> 1);

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

    }

       //定义hugecapacity这个方法,

  1. 如果传进来的mincapacity小于0,抛出OutofMemory异常,因为数组达到最大长度,溢出了。就是负数,OutofMemory代表堆空间用尽,也可以理解jvm耗尽
  2. 否则返会,返回前先判断
  3. 如果传入长度大于最大长度。返回integer最大长度,如果没大于。返回定于的最大长度

    private static int hugeCapacity(int minCapacity) {

        if (minCapacity < 0) // overflow

            throw new OutOfMemoryError();

        return (minCapacity > MAX_ARRAY_SIZE) ?

            Integer.MAX_VALUE :

            MAX_ARRAY_SIZE;

    }

 

    /**

     * 定义size方法返回这个list的长度

     *

     * @return the number of elements in this list

     */

    public int size() {

        return size;

    }

 

    /**

     * 定义isempty,调用size方法判断是否为空

     *

     * @return <tt>true</tt> if this list contains no elements

     */

    public boolean isEmpty() {

        return size == 0;

    }

 

    /**

     *1.定义contains方法,传递一个任意对象,方法体内调用indexof方法,通过判断indexof是否大于等于0来判断是否含有含有这个传入对象,如果大于等于0,则含有,小于0则没有

2为什么是大于等于0呢?因为indexof他判断如果存在则返回下标值,而数组下标值第一个元素为0.

     *

     * @param o element whose presence in this list is to be tested

     * @return <tt>true</tt> if this list contains the specified element

     */

    public boolean contains(Object o) {

        return indexOf(o) >= 0;

    }

 

    /**

     * 1.定义indexof方法来判断是否含有

          2先判断是否为空,一次for循环,for循环判断是否数组中有元素等于空,如果数组中元素也有为空的,则返回数组元素所在位置  

3.  如果传入对象不为空。一次for循环,用对象.equals(数组元素)的方法来判断,如果找到,则返回下标

4.为什么用对象.Equals(数组元素),而不是用数组元素.equals(对象)???

因为这样能有效避免出现空指针异常的情况,比如如果数组元素为空,那直接会报空指针,并不能进行后续的判断

5.如果没有找到,返回-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;

    }

 

    /**

     * 1.定义lastindexof方法来判断是否含有

          2先判断是否为空,一次for循环,for循环中i起始长度为有效元素个数减一

              为什么这样做??

              目的是为了避免数组下标越界

3.判断是否数组中有元素等于空,如果数组中元素也有为空的,则返回数组元素所在位置      

3.  如果传入对象不为空。一次for循环,用对象.equals(数组元素)的方法来判断,如果找到,则返回下标

4.为什么用对象.Equals(数组元素),而不是用数组元素.equals(对象)???

因为这样能有效避免出现空指针异常的情况,比如如果数组元素为空,那直接会报空指针,并不能进行后续的判断

     * or -1 if there is no such index.

     */

    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;

    }

 

    /**

     * 返回这个<tt>ArrayList</tt>实例的浅拷贝。(元素本身不会被复制。)

1.定义一个ArrayList集合V,

  1. 将原数组的值和长度赋值给这个V的数组
  2. 用try-catch包裹,处理可能出现的不支持克隆异常
  1. 返回这个新的数组,这个新的数组和原数组是两码事,地址不同,只是值相同

 

     * @return a clone of this <tt>ArrayList</tt> instance

     */

    public Object clone() {

        try {

            ArrayList<?> v = (ArrayList<?>) super.clone();

            v.elementData = Arrays.copyOf(elementData, size);

            v.modCount = 0;

            return v;

        } catch (CloneNotSupportedException e) {

            // this shouldn’t happen, since we are Cloneable

            throw new InternalError(e);

        }

    }

 

    /**

 * 返回一个新的数组,其中包含listin正确顺序中的所有元素(从第一个元素到最后一个元素)。

返回的数组将是“安全的”,因为这个列表不维护对它的引用。(换句话说,这个方法必须分配一个新的数组)。因此,调用者可以自由地修改返回的数组。

此方法充当基于数组和基于集合之间的桥梁

Arrays.copyO底层调用System.arraycopy

 

     *

     * @return an array containing all of the elements in this list in

     *         proper sequence

     */

    public Object[] toArray() {

        return Arrays.copyOf(elementData, size);

    }

 

    /**

    泛型 返回包含此列表中所有元素的数组(从第一个元素到最后一个元素);返回数组的运行时类型是指定数组的类型。如果列表与指定数组匹配,则返回该列表。否则,将为新数组分配指定数组的运行时类型和该列表的大小。

如果列表在指定的数组中有多余的空间(例如。,则数组中紧接在集合末尾的元素被设置为null。(只有当调用者知道列表不包含任何空元素时,这在确定列表的长度时才有用。)

目的:返回一个新的数组

@param a:存储列表元素的数组,如果它足够大的话;否则,将为此分配一个运行时类型相同的新数组。

返回一个包含列表元素的数组

* @抛出ArrayStoreException,如果指定数组的运行时类型不是列表中每个元素的运行时类型的超类型

* @抛出NullPointerException,如果指定的数组为null

     */

    @SuppressWarnings(“unchecked”)

    public <T> T[] toArray(T[] a) {

        if (a.length < size)

            // Make a new array of a’s runtime type, but my contents:

            return (T[]) Arrays.copyOf(elementData, size, a.getClass());

        System.arraycopy(elementData, 0, a, 0, size);

        if (a.length > size)

            a[size] = null;

        return a;

    }

 

    // Positional Access Operations

 

    @SuppressWarnings(“unchecked”)

    E elementData(int index) {

        return (E) elementData[index];

    }

 

    /**

     *

     *定义get方法,返回指定位置上的元素

      1.调用rangeCheck方法,检查是否越界

2.定义一个泛型数据oldValue,把数组的对应下标的元素赋值给这个泛型数据

为什么这样做???

因为集合的数组中可能元素不是统一个类型,他的数组定义的时候就定义成了object,可接收任意的,其实和泛型本质是一样的

 

     * @param  index index of the element to return

     * @return the element at the specified position in this list

     * @throws IndexOutOfBoundsException {@inheritDoc}

     */

    public E get(int index) {

        rangeCheck(index);

 

        return elementData(index);

    }

 

    /**

     * 定义set方法,返回指定位置上的元素,

1.调用rangeCheck方法,检查是否越界

2.定义一个泛型数据oldValue,把数组的对应下标的元素赋值给这个泛型数据

3.再把要更改的数据传入赋值给这个数组对应下标

4.最后返回原来的那个数据??

这步有点秀,可以知道改动前的数据

     *

     * @param index index of the element to replace

     * @param element element to be stored at the specified position

     * @return the element previously at the specified position

     * @throws IndexOutOfBoundsException {@inheritDoc}

     */

    public E set(int index, E element) {

        rangeCheck(index);

 

        E oldValue = elementData(index);

        elementData[index] = element;

        return oldValue;

    }

 

    /**

     *定义add方法,将指定元素追加到末尾

         1.调用ensureCapacityInternal,,,此方法内部先调用计算方法,返回长度最大值,再调用ensureExplicitCapacity,将mount++,再判断是否要扩容,注意,执行完虽然长度加了,但是数据并没有添加进去

         2 所以.执行完,将数据插入到数组最后一位

        3.放回true,代表数据插入成功

     4.因为是尾插法,所以不需要判断下标是否越界,并且无需遍历,比linkedlist速度快

     *

     * @param e element to be appended to this list

     * @return <tt>true</tt> (as specified by {@link Collection#add})

     */

    public boolean add(E e) {

        ensureCapacityInternal(size + 1);  // Increments modCount!!

        elementData[size++] = e;

        return true;

    }

 

    /**

     *1.定义add()方法,再任意位置插入在列表的指定位置插入指定的元素。将元素当前的位置(如果有的话)和后续的元素向右移动(在它们的索引中添加一个)。

       2.先判断是否越界,如果越界直接抛异常,中断方法向下一步执行

       3. 调用ensureCapacityInternal,,,此方法内部先调用计算方法,返回长度最大值,再调用ensureExplicitCapacity,将mount++,再判断是否要扩容,注意,执行完虽然长度加了,但是数据并没有添加进去

4.直接调用system.arraycopy,进行后移

???怎么后移???为什么是后移

首先,调用system.arraycopy前先进行扩容,然后数组长度已经增加了,注意如果没有这一步,亲手试验过,会直接报角标越界,,再其次如果前移,也必定会角标越界,这只是其一,其二,通过system.arraycopy,源数组给的是数组elemendata,其实位置给的是index处,然后目标数组给的也是elemendata,赋值的起使位置是index+1,然后长度是length-size就能求出后移的位数,因此肯定是后移,并且后移length-size位

public static void arraycopy(Object src,

                             int srcPos,

                             Object dest,

                             int destPos,

                             int length)

其中:src表示源数组,srcPos表示源数组要复制的起始位置,desc表示目标数组, destPos 目标数组的起始位置length表示要复制的长度

5.  将数组index赋值为要插入数据

6.Size++

*

* @param索引指定元素要插入的索引

* @param元素要插入的元素

* @throws IndexOutOfBoundsException {@inheritDoc}

     */

    public void add(int index, E element) {

        rangeCheckForAdd(index);

 

        ensureCapacityInternal(size + 1);  // Increments modCount!!

        System.arraycopy(elementData, index, elementData, index + 1,

                         size – index);

        elementData[index] = element;

        size++;

    }

 

    /**

     * *1.定义remove()方法,在数组任意位置进行删除,返回删除数据。

       2.先判断是否越界,如果越界直接抛异常,中断方法向下一步执行

       3. 因为没有ensureCapacityInternal,,也不需要,只能通过手写mount++

4.定义移除元素个数nummoved等于实际元素个数-索引-1

????为什么nummoved=实际元素个数-索引-1???、

首先,判断过角标是否越界,因此nummoved必定是大于等于0的数

其次,numoved如果等于0,那么就代表要删除的是最后一个元素,直接置空

最后,因为左移,所以复制元素的起始下标就是index+1,因此size-index-1才能代表移动的长度

4.先判断nummoved>0,如果是调用system.arraycopy,进行左移,如果nummoved=0,直接把最后位置置空,剩下的交给gc垃圾回收器

???怎么左移???为什么是左移

首先,,求出需要左移的位数,然后直接将删除位置的后一个进行左移,这样最后一个就会为空,然后没有引用,垃圾回收器就会进行回收

public static void arraycopy(Object src,

                             int srcPos,

                             Object dest,

                             int destPos,

                             int length)

其中:src表示源数组,srcPos表示源数组要复制的起始位置,desc表示目标数组, destPos 目标数组的起始位置length表示要复制的长度

5.  返回删除的数据

     *

     * @param index the index of the element to be removed

     * @return the element that was removed from the list

     * @throws IndexOutOfBoundsException {@inheritDoc}

     */

    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;

    }

 

    /**

     *1.重写remove,返回布尔类型来判断是否删除完,如果指定元素出现,则从列表中删除第一个出现的元素。如果列表中不包含该元素,则不会对其进行更改

      2.判断对象是否为空,如果为空,则for循环遍历是否存在为空的原数,存在的话调用快速删除,删除第一个为空的,返回true,结束

      3.如果传入对象不为空,for循环进行比较,找到所匹配的位置,调用快速删除方法,删除,返回true,结束

.

     *

     * @param o element to be removed from this list, if present

     * @return <tt>true</tt> if this list contained the specified element

     */

    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;

    }

 

    /*

     * 定义fastremove方法()跳过边界检查且不返回已删除值的私有移除方法

       1.mount++

       2.定义移动长度

       3.如果移动长度大于0,调用Syste,.arraycopy

       4.如果移动长度等于0,直接最后位置置空,再把长度减一,交给垃圾处理器处理

     */

    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

    }

 

    /**

     * 定义清空方法clear(),快速情况所有

       1.mount++

       2.for循环,把所有元素置空

       3.数组长度清0

     */

    public void clear() {

        modCount++;

 

        // clear to let GC do its work

        for (int i = 0; i < size; i++)

            elementData[i] = null;

 

        size = 0;

    }

 

    /**

     * 从指定位置开始,将指定集合中的所有元素插入到此列表中。将当前位置的elemen(如果有的话)和随后的元素移到右边(增加它们的索引)。新元素将按照指定集合的迭代器返回的顺序出现在列表中

1.定义返回值为boolean的方法addAll,传递的参数是一个集合

2.collection调用toarray方法生成数组然后复制给object数组a

3.定义numNew等于数组a的长度

4.调用ensureCapacityInternal,传递的长度为原来arraylist内元素个数加上a的长度,

然后计算出传递长度和默认长度10的最大值,再调用ensureExplicitCapacity方法,然后再ensureExplicitcapacity中进行mount++,再判断是否需要扩容,如果需要,则扩容,关键在于mount++,和扩容1.5倍

  1. 调用System.arraycopy(a, 0, elementData, size, numNew);从直接在最后面添加
  2. 再把size长度加上a的长度
  3. 判断numNew是否等于0并返回,如果等于0,就代表形参的集合为空,因此添加失败

     * @param c collection containing elements to be added to this list

     * @return <tt>true</tt> if this list changed as a result of the call

     * @throws NullPointerException if the specified collection is null

     */

    public boolean addAll(Collection<? extends E> 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;

    }

 

    /**

     * 从指定位置开始,将指定集合中的所有元素插入到此列表中。将元素当前的位置(如果有的话)和后续的元素向右移动(增加它们的索引)。新元素将按照指定集合的迭代器返回的顺序出现在列表中。

 1.定义返回值为boolean的方法addAll,传递的参数是一个集合

2.collection调用toarray方法生成数组然后复制给object数组a

3.定义numNew等于数组a的长度

4.调用ensureCapacityInternal,传递的长度为原来arraylist内元素个数加上a的长度,

然后计算出传递长度和默认长度10的最大值,再调用ensureExplicitCapacity方法,然后再ensureExplicitcapacity中进行mount++,再判断是否需要扩容,如果需要,则扩容,关键在于mount++,和扩容1.5倍

5.定义移动个数=size-index

6.如果移动个数大于0,则从index位置上的元素起。移动到index+numNew位置

7.如果移动个数小于0,则5. 调用System.arraycopy(a, 0, elementData, size, numNew);从直接在最后面添加

8.再把size长度加上a的长度

9.判断numNew是否等于0并返回,如果等于0,就代表形参的集合为空,因此添加失败

 

 *

     * @param index index at which to insert the first element from the

     *              specified collection

     * @param c collection containing elements to be added to this list

     * @return <tt>true</tt> if this list changed as a result of the call

     * @throws IndexOutOfBoundsException {@inheritDoc}

     * @throws NullPointerException if the specified collection is null

     */

    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;

    }

 

    /**

从这个列表中删除索引位于{@code fromIndex}(包含)和{@code toIndex}(排除)之间的所有元素。将后面的元素向左移动(减少它们的索引)。这个调用使用{@code (toIndex – fromIndex)}元素来缩短列表。(如果{@code toIndex==fromIndex},则此操作无效。)

1.定义一个removeRange()方法来移除指定区间的元素,传递参数为起使索引位置,结束索引位置

2.首先mount++

3.定义移动长度为总元素个数-结束索引位置

4.调用system.arraycopy,将结束索引位置的起到最后的元素复制给起使位置元素,共移动(总元素个数-结束索引位置)个位置

5.定义一个长度newsize等于总元素个数-(起使索引位置-开始索引位置长度)

6.利用for循环,把newsize到size的元素全部置空

7.在让size等于之前定义的newsize,这一步目的是为了让垃圾回收器工作   *

     * @throws IndexOutOfBoundsException if {@code fromIndex} or

     *         {@code toIndex} is out of range

     *         ({@code fromIndex < 0 ||

     *          fromIndex >= size() ||

     *          toIndex > size() ||

     *          toIndex < fromIndex})

     */

    protected void removeRange(int fromIndex, int toIndex) {

        modCount++;

        int numMoved = size – toIndex;

        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;

    }

 

    /**

     * 检查输入索引是否大于元素总长度,如果大于,抛出异常

     */

    private void rangeCheck(int index) {

        if (index >= size)

            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

    }

 

    /**

     * 检查关于add和addall的所用索引是否大于元素个数

     */

    private void rangeCheckForAdd(int index) {

        if (index > size || index < 0)

            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

    }

 

    /**

     构造一个IndexOutOfBoundsException详细信息消息。在错误处理代码的许多可能重构中,这种“概述”在服务器和客户端虚拟机中都执行得最好。

     */

    private String outOfBoundsMsg(int index) {

        return “Index: “+index+”, Size: “+size;

    }

 

    /**

     * removeall()从此列表中移除指定集合中包含的所有元素,调用batchRemove(false)实现     *

     * @param c collection containing elements to be removed from this list

     * @return {@code true} if this list changed as a result of the call

     * @throws ClassCastException if the class of an element of this list

     *         is incompatible with the specified collection

     * (<a href=”Collection.html#optional-restrictions”>optional</a>)

     * @throws NullPointerException if this list contains a null element and the

     *         specified collection does not permit null elements

     * (<a href=”Collection.html#optional-restrictions”>optional</a>),

     *         or if the specified collection is null

     * @see Collection#contains(Object)

     */

    public boolean removeAll(Collection<?> c) {

        Objects.requireNonNull(c);

        return batchRemove(c, false);

    }

 

    /**

     * 仅保留此列表中包含在指定集合中的元素换句话说,从该列表中删除指定集合中不包含的所有元素。通过Batchremove(true)实现*

     * @param c collection containing elements to be retained in this list

     * @return {@code true} if this list changed as a result of the call

     * @throws ClassCastException if the class of an element of this list

     *         is incompatible with the specified collection

     * (<a href=”Collection.html#optional-restrictions”>optional</a>)

     * @throws NullPointerException if this list contains a null element and the

     *         specified collection does not permit null elements

     * (<a href=”Collection.html#optional-restrictions”>optional</a>),

     *         or if the specified collection is null

     * @see Collection#contains(Object)

     */

    public boolean retainAll(Collection<?> c) {

        Objects.requireNonNull(c);

        return batchRemove(c, true);

    }

//1.定义私有的布尔类型方法batchRemove

2.定义一个常量object类型elementdata等于原arraylist中的数组

3.定义r和w

4. if (c.contains(elementData[r]) == complement)

                    elementData[w++] = elementData[r];这个来控制条件

 

    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;

    }

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。