IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> ArrayList源码分析 -> 正文阅读

[Java知识库]ArrayList源码分析

ArrayList源码分析

ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。

ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。

ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。

常量以及构造方法

   /**
     * Default initial capacity.
     * 
     * 默认初始容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     * 
     * 用于空实例的共享空数组实例
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     * 
     * 用于默认大小的空实例的共享空数组实例。
     * 我们将其与空元素数据区分开来,以了解添加第一个元素时要膨胀多少
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     * 
     * 存储ArrayList元素的缓冲区。
     * ArrayList的容量是这个数组缓冲区的长度
     * 添加第一个元素时,elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的任何空ArrayList都将扩展为默认容量	
     */
    transient Object[] elementData; // non-private to simplify nested class access
    //非私有以简化嵌套类访问
    //将不需要序列化的属性添加transient关键字,序列化对象的时候,这个属性就不会被序列化。
    //回想ArrayList的自动扩容机制,elementData数组相当于容器,当容器不足时就会再扩充容量,但是容器的容量往往都是大于或者等于ArrayList所存元素的个数。
    //比如,现在实际有了8个元素,那么elementData数组的容量可能是8x1.5=12,如果直接序列化elementData数组,那么就会浪费4个元素的空间,特别是当元素个数非常多时,这种浪费是非常不合算的。
    //所以ArrayList的设计者将elementData设计为transient,然后在writeObject方法中手动将其序列化,并且只序列化了实际存储的那些元素,而不是整个数组。

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * 表示集合的长度
     * @serial
     */
    private int size;

   /**
     * Constructs an empty list with the specified initial capacity.
     *
     * 构造具有指定初始容量的空列表。
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        //判断初始容量的大小
        if (initialCapacity > 0) {
            //如果初始容量大于零 就初始化elementData数组的容量
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //如果初始容量为0 就将elementData数组的容量赋为默认值
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     * 
     * 构造一个初始容量为10的空列表。
     */
    //在无参构造函数中,将创建一个DEFAULTCAPACITY_EMPTY_ELEMENTDATA声明的数组,这里的数组容量是0,而不是很多人认为的10.当数组开始增加元素时才会扩容到10。
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     * 
     * 构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            //每个集合的toarray()的实现方法不一样,所以需要判断一下,如果不是Object[].class类型,那么就需要使用ArrayList中的方法去改造一下。
            if (elementData.getClass() != Object[].class)
                //copyOf(要复制的数组,要返回的副本的长度,要返回的副本的类)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

get()方法

    //返回索引为index的元素
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

    /**
     * Returns the element at the specified position in this list.
     *
     * 返回list中指定位置的元素
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    //返回位于list中该索引下下的指定元素
    public E get(int index) {
        //越界检查
        rangeCheck(index);
	    //返回索引为index的元素
        return elementData(index);
    }

    //检查指定索引是否在范围内。如果不在,抛出一个运行时异常。这个方法不检查索引是否为负数,它总是在数组访问之前立即优先使用,如果给出的索引index>=size,抛出一个越界异常
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

get()方法流程:判断是否角标越界(索引小于0或者大于等于实际数组长度),然后再去通过下标去获取元素

set()方法

	//返回索引为index的元素
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

    /**
     * Returns the element at the specified position in this list.
     *
     * 返回list中指定位置的元素
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    //返回位于list中该索引下下的指定元素
    public E get(int index) {
        //越界检查
        rangeCheck(index);
	    //返回索引为index的元素
        return elementData(index);
    }

    //检查指定索引是否在范围内。如果不在,抛出一个运行时异常。这个方法不检查索引是否为负数,它总是在数组访问之前立即优先使用,如果给出的索引index>=size,抛出一个越界异常
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

get()方法流程:判断是否角标越界(索引小于0或者大于等于实际数组长度),然后再去通过下标去获取元素	

add()方法

   /**
     * Appends the specified element to the end of this list.
     * 
     * 将指定元素追加到此列表的末尾
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    //带参方法
    public boolean add(E e) {
    	//确认list容量,如果不够,容量加1 注意:只加1,保证资源不被浪费
        ensureCapacityInternal(size + 1);  // Increments modCount!!
    	//将元素e放在size的位置上,并且size++
        elementData[size++] = e;
        return true;
    }
    
    //数组容量检查,不够时则进行扩容,只供类内部使用 
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        // 若elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则取minCapacity为DEFAULT_CAPACITY和参数minCapacity之间的最大值。DEFAULT_CAPACITY在此之前已经定义为默认的初始化容量是10。
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    
    //数组容量检查,不够时则进行扩容,只供类内部使用 
    // minCapacity 想要的最小容量
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     *  扩容,保证ArrayList至少能存储minCapacity个元素
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        //获取当前数组的容量
        int oldCapacity = elementData.length;
        //第一次扩容公式:新容量 = 当前容量 + 当前容量 / 2  (扩容当前容量的一点五倍)
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果扩容后的容量还是小于想要的最小容量,就再次扩容为需要的最小容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //注意:elementData就空数组的时候,length=0,那么oldCapacity=0,newCapacity=0,在这里就是真正的初始化elementData的大小了,就是为10.
        //如果扩容后的大小大于临界值,则进行大容量分配
        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);
    }

    //进行大容量分配
    private static int hugeCapacity(int minCapacity) {
        //如果minCapacity<0,抛出异常
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        //如果想要的容量大于MAX_ARRAY_SIZE,则分配Integer.MAX_VALUE,否则分配MAX_ARRAY_SIZE
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }
    
    
    /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * 将指定元素插入指定的位置
     * 将当前位于该位置的元素(如果有的话)和随后的任何元素向右移动(将一个元素添加到它们的索引中)。
     * 
     * @param index index at which the specified element is to be inserted 要插入指定元素的索引位置
     * @param element element to be inserted 即将插入的元素
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        //越界健查
        rangeCheckForAdd(index);
	    //确认list容量,如果不够,容量加1。注意:只加1,保证资源不被浪费
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //对原数组进行复制,目的是为了空出index处的位置去添加element元素,并将index后的元素位置往后移
        //arraycopy(原数组,源数组中的起始位置,目标数组,目标数据中的起始位置,要复制的数组元素的数量)
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = element;
        //实际容量++
        size++;
    }
    
    /**
     * A version of rangeCheck used by add and addAll.
     */
    //越界检查
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    
     /**
     * Appends all of the elements in the specified collection to the end of
     * this list, in the order that they are returned by the
     * specified collection's Iterator.  The behavior of this operation is
     * undefined if the specified collection is modified while the operation
     * is in progress.  (This implies that the behavior of this call is
     * undefined if the specified collection is this list, and this
     * list is nonempty.)
     * 
     * 按照指定集合的迭代器返回的顺序,将指定集合中的所有元素追加到此列表的末尾。
     * 如果在操作进行期间修改了指定的集合,则此操作的行为未定义。
     *(这意味着,如果指定的集合是This list,并且该list是非空的,则此调用的行为是未定义的。)
     * 
     * @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
        //arraycopy(原数组,源数组中的起始位置,目标数组,目标数据中的起始位置,要复制的数组元素的数量)
        System.arraycopy(a, 0, elementData, size, numNew);
        //数组长度更新
        size += numNew;
        return numNew != 0;
    }

    /**
     * Inserts all of the elements in the specified collection into this
     * list, starting at the specified position.  Shifts the element
     * currently at that position (if any) and any subsequent elements to
     * the right (increases their indices).  The new elements will appear
     * in the list in the order that they are returned by the
     * specified collection's iterator.
     *
     * 将指定集合中的所有元素插入此列表,从指定位置开始。
     * 将当前位于该位置的元素(如果有)和任何后续元素向右移动(增加其索引)。
     * 新元素将按指定集合的迭代器返回的顺序出现在列表中。
     *
     *
     * @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)
            //arraycopy(原数组,原数组中的起始位置,目标数组,目标数据中的起始位置,要复制的数组元素的数量)
            System.arraycopy(elementData, index, elementData, index + numNew, numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }
    
    /**
     * A version of rangeCheck used by add and addAll.
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    
add()添加流程:
如果原数组时空的,添加一个元素数组容量变为10,如果原数组不为空,追加元素时,容量变为原来的1.5倍
如果扩容后的容量大于分配给ArrayList的容量,判断需要的容量是否比分配的容量大,就是把是就Integer.MAX_VALUE:2147483647 赋值给 minCapacity,否就用 MAX_ARRAY_SIZE:2147483639

add -> ensureCapacityInternal -> calculateCapacity -> ensureExplicitCapacity ....> grow ....> hugeCapacity

remove()方法

    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * 删除list中位置为指定索引index的元素
     * 索引之后的元素向左移一位
     *
     * @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);
	    //结构性修改次数+1
        modCount++;
        //记录索引处的位置
        E oldValue = elementData(index);
		//需要左移的元素个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //arraycopy(原数组,源数组中的起始位置,目标数组,目标数据中的起始位置,要复制的数组元素的数量)
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
    	//size减一,然后将索引为size-1处的元素置为null。为了让GC起作用,必须显式的为最后一个位置赋null值
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
    
   /**
     * Checks if the given index is in range.  If not, throws an appropriate
     * runtime exception.  This method does *not* check if the index is
     * negative: It is always used immediately prior to an array access,
     * which throws an ArrayIndexOutOfBoundsException if index is negative.
     */
    //检查指定索引是否在范围内。如果不在,抛出一个运行时异常。这个方法不检查索引是否为负数,它总是在数组访问之前立即优先使用,如果给出的索引 index>=size,抛出一个越界异常
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

   /**
     * Constructs an IndexOutOfBoundsException detail message.
     * Of the many possible refactorings of the error handling code,
     * this "outlining" performs best with both server and client VMs.
     */
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

    /**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If the list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     * 
     * 从列表中删除指定元素的第一个出现项,如果它存在的话。
     * 如果列表不包含该元素,它将保持不变。
     * 更正式地说,删除索引最低的元素...
     * @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;
    }

    /*
     * Private remove method that skips bounds checking and does not
     *
     * 私有的remove方法,该方法跳过边界检查,并且不返回已删除的值。
     * return the value removed.
     */
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //arraycopy(原数组,源数组中的起始位置,目标数组,目标数据中的起始位置,要复制的数组元素的数量)
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
    
   /**
     * Removes from this list all of the elements whose index is between
     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
     * Shifts any succeeding elements to the left (reduces their index).
     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
     * (If {@code toIndex==fromIndex}, this operation has no effect.)
     * 
     * 从该列表中删除索引位于两者之间的所有元素,包含fromIndex,但是不包含toIndex,
     * 将任何后续元素向左移动(减少它们的索引)
     * 这个调用通过{@code (toIndex - fromIndex)}元素缩短列表。
     * 
     * @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;
        //arraycopy(原数组,源数组中的起始位置,目标数组,目标数据中的起始位置,要复制的数组元素的数量)
        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;
    }
    
   /**
     * Removes from this list all of its elements that are contained in the
     * specified collection.
     *
     * 从此列表中删除指定集合中包含的所有元素。
     *
     * @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);
    }

    /**
     * Retains only the elements in this list that are contained in the
     * specified collection.  In other words, removes from this list all
     * of its elements that are not contained in the specified collection.
     *
     * 仅保留此列表中包含在指定集合中的元素。 
     * 换句话说,从该列表中删除指定集合中不包含的所有元素。
     *
     * @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);
    }

    //complement:true时从数组保留出指定集合中元素的值,为false时从数组删除指定集合中元素的值
    private boolean batchRemove(Collection<?> c, boolean complement) {
        //原集合
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            //遍历数组,并检查这个集合是否包含对应的值,移动要保留的值到数组前面,w最后值为要保留的数量
            //若保留,就将相同元素移动到前段;不删除,就将不同元素移动到前端
            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 表示可能出错了:c.contains(elementData[r])抛出异常
            if (r != size) {
                System.arraycopy(elementData, r, elementData, w, size - r);
                w += size - r;
            }
            //如果 w == size :表示全部元素都保留了,所以也就没有删除操作发生,所以返回false;反之返回true,并更改数组
            //如果 w != size 的时候,即使try块抛出异常,也能正确处理异常抛出前的操作,因为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;
    }
    
   /**
     * Removes all of the elements from this list.  The list will
     * be empty after this call returns.
     */
    //清空集合
    public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }
    
remove(int index)流程:越界检查,修改记录次数(modCount可以用来检测快速失败的一种标志),通过索引找到要删除的元素,计算出需要左移的元素个数,将–size上的位置赋值为null,让gc(垃圾回收机制)更快的回收它。返回被删除的元素
    
remove(Object o)流程:循环遍历所有对象,得到对象所在索引位置,然后调用fastRemove方法,执行remove操作。定位到需要remove的元素索引,先将index后面的元素往前面移动一位(调用System.arraycooy实现),然后将最后一个元素置空。
这里最主要是知道arrayList可以存储null值。
    
removeRange(int fromIndex, int toIndex)流程:将 fromIndex 到 toIndex 之间的元素都删除,把 toIndex 后面的元素往左边移动( size - toIndex)位,把左移后空的元素置为null,方便垃圾回收机制回收内存,最后把新数组的大小赋值给size 

总结

1)arrayList可以存放null。
2)arrayList本质上就是一个elementData数组。
3)arrayList区别于数组的地方在于能够自动扩展大小,其中关键的方法就是gorw()方法。
4)arrayList中removeAll(collection c)clear()的区别就是removeAll可以删除批量指定的元素,而clear是全是删除集合中的元素。
5)arrayList由于本质是数组,所以它在数据的查询方面会很快,而在插入删除这些方面,性能下降很多,有移动很多数据才能达到应有的效果。
6)arrayList实现了RandomAccess,所以在遍历它的时候推荐使用for循环。
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 15:57:54  更:2022-03-03 16:00:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:53:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码