【Java】ArrayList用法详解

一、ArrayList类的使用方式

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @BelongsProject: learn1
 * @BelongsPackage: PACKAGE_NAME
 * @Author: ZhShy
 * @CreateTime: 2022-02-06 11:16
 * @Description: arrayList
 */
public class ArrayListDemo {
    public static void main(String[] args) {
        /**
         * 创建一个ArrayList对象,
         * 定义元素个数,
         * 初始化ArrayList中的元素
         */
        ArrayList<Integer> arrayList = new ArrayList<>();
        int size = 10;
        for (int i = 0; i < size; i++) {
            arrayList.add(i);
        }
//        调用有参构造传入ArrayList作为参数
        ArrayList<Integer> otherList = new ArrayList<>(arrayList);
        System.out.println("arrayList的第0个位置元素:" + arrayList.get(0));
        System.out.println("arrayList元素5所在位置:" + arrayList.get(5));
        System.out.println("arrayList是否包含元素10:" + arrayList.contains(10));
        System.out.println("arrayList删除第0个位置元素:" + arrayList.remove(0));

        /**
         * 获取ArrayList的迭代器
         */
        Iterator<Integer> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            Integer element = iterator.next();
            System.out.println("iterator()迭代器输出ArrayList元素:" + element);
            if (element == 5) {
                iterator.remove();
                System.out.println("iterator()迭代器删除ArrayList元素:" + element);
                break;
            }
        }
        iterator.forEachRemaining(integer -> System.out.println("forEachRemaining()输出元素" + integer));
//        删除与ArrayList交集部分
        otherList.removeAll(arrayList);
        otherList.forEach(integer -> System.out.println("forEach()输出otherList元素:" + integer));
    }
}

执行结果:

arrayList的第0个位置元素:0
arrayList元素5所在位置:5
arrayList是否包含元素10false
arrayList删除第0个位置元素:0
iterator()迭代器输出ArrayList元素:1
iterator()迭代器输出ArrayList元素:2
iterator()迭代器输出ArrayList元素:3
iterator()迭代器输出ArrayList元素:4
iterator()迭代器输出ArrayList元素:5
iterator()迭代器删除ArrayList元素:5
forEachRemaining()输出元素6
forEachRemaining()输出元素7
forEachRemaining()输出元素8
forEachRemaining()输出元素9
forEach()输出otherList元素:0
forEach()输出otherList元素:5

二、ArrayList类的声明

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

ArrayList是顺序表的一种实现,在顺序表的基础上提供了更加丰富的功能。ArrayList继承了AbstractList类,实现了List、RandomAccess、Cloneable、Serializable接口。
在这里插入图片描述

三、ArrayList类的属性


    /**
     * 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.
     * 空数组,用于控制当ArrayList加入新元素时,计算扩充的容量
     */
    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存放元素的数组
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     * ArrayList包含的元素个数
     */
    private int size;

ArrayList类是基于数组实现的线性表,并且用size属性记录ArrayList对象中包含的元素的个数,因此获取ArrayList对象的大小的时间复杂度为O(1),因为不需要对ArrayList对象中的每个元素进行遍历。

四、ArrayList类的构造器

1. 构造指定初始容量空列表


    /**
     * 构造一个具有指定初始容量的空列表
     * 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) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

带初始容量的构造器中会对指定的初始容量进行校验。如果初始容量参数非法,就会抛出IllegalArgumentException异常。初始容量不宜设置过大,否则可能会造成存储空间浪费,甚至会影响JVM(Java Virtual Machine,Java虚拟机)的性能。


2. 无参构造器


    /**
     * Constructs an empty list with an initial capacity of ten.
     * 无参构造器
     */
    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.
     *
     * @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) {
            // defend against c.toArray (incorrectly) not returning Object[]
            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

五、ArrayList类添加元素的方法

ArrayList添加元素的方法有两个重载的方法,分别是add(E e)add(int index,E element)


    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }

    /**
     * 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);
        modCount++;
        final int s;
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }

1. add(E e)

add(E e)为例,

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }

这段代码使用到了一个modCount变量和add()函数
其中的add()函数:

    /**
     * This helper method split out from add(E) to keep method
     * bytecode size under 35 (the -XX:MaxInlineSize default value),
     * which helps when add(E) is called in a C1-compiled loop.
     */
    private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }

这段代码可以看出,先判断当前容量是否足够再插入一个元素,如果不够则调用grow()函数,然后再将相应位置插入元素,同时size增加1.
grow()函数:


    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero
     */
    private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));
    }

    private Object[] grow() {
        return grow(size + 1);
    }

grow()方法的大致意思是将数组复制到另一个更大的数组里,其中调用了newCapacity()方法:


    /**
     * Returns a capacity at least as large as the given minimum capacity.
     * Returns the current capacity increased by 50% if that suffices.
     * Will not return a capacity greater than MAX_ARRAY_SIZE unless
     * the given minimum capacity is greater than MAX_ARRAY_SIZE.
     *
     * @param minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero
     */
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 新数组为旧数组容积的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 如果仍然不够则给它一个足够大的容积
        if (newCapacity - minCapacity <= 0) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }

代码末尾调用了一个hugeCapacity()函数:

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

如果最小容量minCapacity小于0,就说明int类型的minCapacity发生了溢出,抛出OutOfMemoryError错误。如果最小容量minCapacity大于MAX_ARRAY_SIZE,就返回Integer.MAX_VALUE。由此可知,ArrayList的最大容量是Integer.MAX_VALUE


2. add(int index, E element)

add(int index, E element)只是比add(E e)方法多了两个方法调用,其余的处理逻辑与add(E e)方法类似。


    /**
     * 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);
        modCount++;
        final int s;
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }

add(int index, E element)首先需要通过rangeCheckForAdd()方法校验插入新元素的位置是否合法:


    /**
     * 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(int index, E element)还调用System.arraycopy()方法进行数组拷贝,将数组的第index位置空出,用于存储新元素。

六、ArrayList类查询元素方法

ArrayList查询元素的方法主要分为两类:一类是已知位置信息,查询ArrayList中的元素;另一类是已知元素信息,查询ArrayList中的位置信息或者ArrayList是否包含指定元素。

1. get()方法——查询指定位置的元素

get()方法是通过指定位置信息查询ArrayList指定位置的元素


    /**
     * Returns the element at the specified position in this list.
     *
     * @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) {
        Objects.checkIndex(index, size);
        return elementData(index);
    }

get()函数首先用Objects.checkIndex()对index判断位置是否合法,然后调用elementData()方法。

    E elementData(int index) {
        return (E) elementData[index];
    }

2. indexOf()方法——查询元素第一次出现位置

indexOf()方法是通过指定的元素查询元素在ArrayList第1次出现的位置。

    /**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index {@code i} such that
     * {@code Objects.equals(o, get(i))},
     * or -1 if there is no such index.
     */
    public int indexOf(Object o) {
        return indexOfRange(o, 0, size);
    }

    int indexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {
            for (int i = start; i < end; i++) {
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = start; i < end; i++) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

从indexOf()方法的源码可知,此方法只能找到ArrayList中第1次出现指定元素的位置,找到后立即返回。indexOf()方法比较元素相等用的是equals()方法,因此两个equals()相等的元素被ArrayList认为是同一个元素。

3. lastIndexOf()——查询元素最后一次出现位置

lastIndexOf()方法是通过指定的元素查询元素在ArrayList最后一次出现的位置。lastIndexOf()方法代码如下:

   /**
     * Returns the index of the last occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the highest index {@code i} such that
     * {@code Objects.equals(o, get(i))},
     * or -1 if there is no such index.
     */
    public int lastIndexOf(Object o) {
        return lastIndexOfRange(o, 0, size);
    }

    int lastIndexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {
            for (int i = end - 1; i >= start; i--) {
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = end - 1; i >= start; i--) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

lastIndexOf()方法与indexOf()方法的不同之处仅仅在于,lastIndexOf()方法从ArrayList最后一个元素的位置向前搜索,返回指定元素最后一次出现的位置。

4. contains() —— 元素是否存在

contains()方法返回boolean值,用于检查指定的元素是否存在于ArrayList中。contains()方法代码如下:


    /**
     * Returns {@code true} if this list contains the specified element.
     * More formally, returns {@code true} if and only if this list contains
     * at least one element {@code e} such that
     * {@code Objects.equals(o, e)}.
     *
     * @param o element whose presence in this list is to be tested
     * @return {@code true} if this list contains the specified element
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

从contains()方法的代码可知,contains()借助indexOf()方法实现功能。如果指定的元素存在于ArrayList中,indexOf()就会返回元素的位置信息,其位置信息一定是大于等于0的一个数,此时contains()方法返回true;否则indexOf()方法将返回-1,此时contains()方法返回false。

七、ArrayList类更新元素——set

set()方法用指定的元素替换此ArrayList中指定位置的元素


    /**
     * Replaces the element at the specified position in this list with
     * the specified element.
     *
     * @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) {
        Objects.checkIndex(index, size);
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

八、ArrayList类删除元素方法

1. remove(int index)

remove(int index)方法是删除指定位置index上的元素。如果删除的位置不合法,就会抛出IndexOutOfBoundsException异常。如果删除的并非是最后一个位置的元素,就会通过System.arraycopy()方法将index以后的元素依次向前移动。最后返回删除的元素。


    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @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) {
        Objects.checkIndex(index, size);
        final Object[] es = elementData;

        @SuppressWarnings("unchecked") E oldValue = (E) es[index];
        fastRemove(es, index);

        return oldValue;
    }


    /**
     * Private remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(Object[] es, int i) {
        modCount++;
        final int newSize;
        if ((newSize = size - 1) > i)
            System.arraycopy(es, i + 1, es, i, newSize - i);
        es[size = newSize] = null;
    }

2. remove(Object o)

与remove(int index)方法不同的是,remove(Object o)方法不是删除指定位置的元素,而是删除ArrayList中与指定元素相等的元素。与indexOf()方法和lastIndexOf()方法类似,remove(int index)方法判断元素是否相等也是通过equals()方法。remove(Object o)方法删除元素通过fastRemove()方法实现。


    /**
     * 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
     * {@code i} such that
     * {@code Objects.equals(o, get(i))}
     * (if such an element exists).  Returns {@code true} 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 {@code true} if this list contained the specified element
     */
    public boolean remove(Object o) {
        final Object[] es = elementData;
        final int size = this.size;
        int i = 0;
        found: {
            if (o == null) {
                for (; i < size; i++)
                    if (es[i] == null)
                        break found;
            } else {
                for (; i < size; i++)
                    if (o.equals(es[i]))
                        break found;
            }
            return false;
        }
        fastRemove(es, i);
        return true;
    }

九、ArrayList类批量方法

  1. addAll(Collection<? extends E> c)——批量将另一个集合中的元素加入ArrayList的末尾
  2. addAll(int index, Collection<? extends E> c)——指定将另一个集合中的元素插入ArrayList指定的位置后
  3. removeAll(Collection<?> c)——删除ArrayList与另一个集合c的交集部分
  4. retainAll(Collection<?> c)——和removeAll(Collection<?> c)互为相反操作

十、ArrayList类导出数组方法

  1. toArray()方法用于返回一个包含ArrayList中所有元素的数组
  2. toArray(T[] a)方法用于返回一个包含ArrayList中所有元素的指定类型的数组

十一、ArrayList类排序方法——sort()

sort():

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

sort()方法根据传入的比较器Comparator调用Arrays.sort()方法进行排序。这里也是策略设计模式的一种运用场景。Comparator是一个函数式接口,JDK1.8对Comparator接口做了修改,在其中加入了很多默认方法,此处只节选了compare()方法,因为compare()方法是Arrays.sort()方法中用到的。Arrays.sort()方法代码如下:

    public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                Comparator<? super T> c) {
        if (c == null) {
            sort(a, fromIndex, toIndex);
        } else {
            rangeCheck(a.length, fromIndex, toIndex);
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, fromIndex, toIndex, c);
            else
                TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
        }
    }

Arrays.sort()方法会使用ComparableTimSort.sort()方法或者TimSort.sort()方法进行排序。这两种排序方法的实现方式类似,不同之处在于,TimSort.sort()使用自定义比较器进行排序,ComparableTimSort.sort()使用元素的自然顺序进行排序。所谓的自然顺序,即实现了Comparable接口的类,如Integer类或者String类等,这些类的对象可以直接进行大小比较,因为没有自定义的比较器也可以对其进行排序。此处使用的TimSort排序算法是一种混合、稳定高效的排序算法。TimSort排序算法是由Tim Peters于2002年实施使用在Python编程语言中的。从2.3版本开始,TimSort一直是Python的标准排序算法。Java中也实现了TimSort算法。

十二、ArrayList类的迭代器

1. iterator()方法


    /**
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();
    }

从iterator()方法的代码可知,iterator()方法将返回一个内部类Itr对象。

2. Iterator接口


/**
 * An iterator over a collection.  {@code Iterator} takes the place of
 * {@link Enumeration} in the Java Collections Framework.  Iterators
 * differ from enumerations in two ways:
 *
 * <ul>
 *      <li> Iterators allow the caller to remove elements from the
 *           underlying collection during the iteration with well-defined
 *           semantics.
 *      <li> Method names have been improved.
 * </ul>
 *
 * <p>This interface is a member of the
 * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
 * Java Collections Framework</a>.
 *
 * @apiNote
 * An {@link Enumeration} can be converted into an {@code Iterator} by
 * using the {@link Enumeration#asIterator} method.
 *
 * @param <E> the type of elements returned by this iterator
 *
 * @author  Josh Bloch
 * @see Collection
 * @see ListIterator
 * @see Iterable
 * @since 1.2
 */
public interface Iterator<E> {
    /**
     * Returns {@code true} if the iteration has more elements.
     * (In other words, returns {@code true} if {@link #next} would
     * return an element rather than throwing an exception.)
     *
     * @return {@code true} if the iteration has more elements
     */
    boolean hasNext();

    /**
     * Returns the next element in the iteration.
     *
     * @return the next element in the iteration
     * @throws NoSuchElementException if the iteration has no more elements
     */
    E next();

    /**
     * Removes from the underlying collection the last element returned
     * by this iterator (optional operation).  This method can be called
     * only once per call to {@link #next}.
     * <p>
     * The behavior of an iterator is unspecified if the underlying collection
     * is modified while the iteration is in progress in any way other than by
     * calling this method, unless an overriding class has specified a
     * concurrent modification policy.
     * <p>
     * The behavior of an iterator is unspecified if this method is called
     * after a call to the {@link #forEachRemaining forEachRemaining} method.
     *
     * @implSpec
     * The default implementation throws an instance of
     * {@link UnsupportedOperationException} and performs no other action.
     *
     * @throws UnsupportedOperationException if the {@code remove}
     *         operation is not supported by this iterator
     *
     * @throws IllegalStateException if the {@code next} method has not
     *         yet been called, or the {@code remove} method has already
     *         been called after the last call to the {@code next}
     *         method
     */
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    /**
     * Performs the given action for each remaining element until all elements
     * have been processed or the action throws an exception.  Actions are
     * performed in the order of iteration, if that order is specified.
     * Exceptions thrown by the action are relayed to the caller.
     * <p>
     * The behavior of an iterator is unspecified if the action modifies the
     * collection in any way (even by calling the {@link #remove remove} method
     * or other mutator methods of {@code Iterator} subtypes),
     * unless an overriding class has specified a concurrent modification policy.
     * <p>
     * Subsequent behavior of an iterator is unspecified if the action throws an
     * exception.
     *
     * @implSpec
     * <p>The default implementation behaves as if:
     * <pre>{@code
     *     while (hasNext())
     *         action.accept(next());
     * }</pre>
     *
     * @param action The action to be performed for each element
     * @throws NullPointerException if the specified action is null
     * @since 1.8
     */
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

3. Itr类

        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

  1. Itr类实现hasNext()方法用于判断是否还有下一个元素可以迭代。
public boolean hasNext() {
            return cursor != size;
        }
  1. Itr类实现next()方法用于返回ArrayList中的下一个元素。
        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];
        }

next()方法调用checkForComodification()方法用于检测迭代器执行过程中是否有并发修改,如果有并发修改,就会抛出ConcurrentModificationException异常。此异常的作用通常是阻止并发修改ArrayList对象。例如,当一个线程通过迭代器修改一个ArrayList时,另一个线程修改ArrayList是不允许的。迭代器通过ConcurrentModificationException异常阻止这种情况的发生,这种迭代器也称作fast-fail迭代器。
3. Itr类实现remove()方法用于删除此迭代器返回的最后一个元素

        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();
            }
        }
  1. Itr类实现forEachRemaining()方法用于对剩余元素执行给定操作。
        @Override
        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i < size) {
                final Object[] es = elementData;
                if (i >= es.length)
                    throw new ConcurrentModificationException();
                for (; i < size && modCount == expectedModCount; i++)
                    action.accept(elementAt(es, i));
                // update once at end to reduce heap write traffic
                cursor = i;
                lastRet = i - 1;
                checkForComodification();
            }
        }

4. ListItr类


/**
 * An iterator for lists that allows the programmer
 * to traverse the list in either direction, modify
 * the list during iteration, and obtain the iterator's
 * current position in the list. A {@code ListIterator}
 * has no current element; its <I>cursor position</I> always
 * lies between the element that would be returned by a call
 * to {@code previous()} and the element that would be
 * returned by a call to {@code next()}.
 * An iterator for a list of length {@code n} has {@code n+1} possible
 * cursor positions, as illustrated by the carets ({@code ^}) below:
 * <PRE>
 *                      Element(0)   Element(1)   Element(2)   ... Element(n-1)
 * cursor positions:  ^            ^            ^            ^                  ^
 * </PRE>
 * Note that the {@link #remove} and {@link #set(Object)} methods are
 * <i>not</i> defined in terms of the cursor position;  they are defined to
 * operate on the last element returned by a call to {@link #next} or
 * {@link #previous()}.
 *
 * <p>This interface is a member of the
 * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
 * Java Collections Framework</a>.
 *
 * @author  Josh Bloch
 * @see Collection
 * @see List
 * @see Iterator
 * @see Enumeration
 * @see List#listIterator()
 * @since   1.2
 */
public interface ListIterator<E> extends Iterator<E> {
    // Query Operations

    /**
     * Returns {@code true} if this list iterator has more elements when
     * traversing the list in the forward direction. (In other words,
     * returns {@code true} if {@link #next} would return an element rather
     * than throwing an exception.)
     *
     * @return {@code true} if the list iterator has more elements when
     *         traversing the list in the forward direction
     */
    boolean hasNext();

    /**
     * Returns the next element in the list and advances the cursor position.
     * This method may be called repeatedly to iterate through the list,
     * or intermixed with calls to {@link #previous} to go back and forth.
     * (Note that alternating calls to {@code next} and {@code previous}
     * will return the same element repeatedly.)
     *
     * @return the next element in the list
     * @throws NoSuchElementException if the iteration has no next element
     */
    E next();

    /**
     * Returns {@code true} if this list iterator has more elements when
     * traversing the list in the reverse direction.  (In other words,
     * returns {@code true} if {@link #previous} would return an element
     * rather than throwing an exception.)
     *
     * @return {@code true} if the list iterator has more elements when
     *         traversing the list in the reverse direction
     */
    boolean hasPrevious();

    /**
     * Returns the previous element in the list and moves the cursor
     * position backwards.  This method may be called repeatedly to
     * iterate through the list backwards, or intermixed with calls to
     * {@link #next} to go back and forth.  (Note that alternating calls
     * to {@code next} and {@code previous} will return the same
     * element repeatedly.)
     *
     * @return the previous element in the list
     * @throws NoSuchElementException if the iteration has no previous
     *         element
     */
    E previous();

    /**
     * Returns the index of the element that would be returned by a
     * subsequent call to {@link #next}. (Returns list size if the list
     * iterator is at the end of the list.)
     *
     * @return the index of the element that would be returned by a
     *         subsequent call to {@code next}, or list size if the list
     *         iterator is at the end of the list
     */
    int nextIndex();

    /**
     * Returns the index of the element that would be returned by a
     * subsequent call to {@link #previous}. (Returns -1 if the list
     * iterator is at the beginning of the list.)
     *
     * @return the index of the element that would be returned by a
     *         subsequent call to {@code previous}, or -1 if the list
     *         iterator is at the beginning of the list
     */
    int previousIndex();


    // Modification Operations

    /**
     * Removes from the list the last element that was returned by {@link
     * #next} or {@link #previous} (optional operation).  This call can
     * only be made once per call to {@code next} or {@code previous}.
     * It can be made only if {@link #add} has not been
     * called after the last call to {@code next} or {@code previous}.
     *
     * @throws UnsupportedOperationException if the {@code remove}
     *         operation is not supported by this list iterator
     * @throws IllegalStateException if neither {@code next} nor
     *         {@code previous} have been called, or {@code remove} or
     *         {@code add} have been called after the last call to
     *         {@code next} or {@code previous}
     */
    void remove();

    /**
     * Replaces the last element returned by {@link #next} or
     * {@link #previous} with the specified element (optional operation).
     * This call can be made only if neither {@link #remove} nor {@link
     * #add} have been called after the last call to {@code next} or
     * {@code previous}.
     *
     * @param e the element with which to replace the last element returned by
     *          {@code next} or {@code previous}
     * @throws UnsupportedOperationException if the {@code set} operation
     *         is not supported by this list iterator
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this list
     * @throws IllegalArgumentException if some aspect of the specified
     *         element prevents it from being added to this list
     * @throws IllegalStateException if neither {@code next} nor
     *         {@code previous} have been called, or {@code remove} or
     *         {@code add} have been called after the last call to
     *         {@code next} or {@code previous}
     */
    void set(E e);

    /**
     * Inserts the specified element into the list (optional operation).
     * The element is inserted immediately before the element that
     * would be returned by {@link #next}, if any, and after the element
     * that would be returned by {@link #previous}, if any.  (If the
     * list contains no elements, the new element becomes the sole element
     * on the list.)  The new element is inserted before the implicit
     * cursor: a subsequent call to {@code next} would be unaffected, and a
     * subsequent call to {@code previous} would return the new element.
     * (This call increases by one the value that would be returned by a
     * call to {@code nextIndex} or {@code previousIndex}.)
     *
     * @param e the element to insert
     * @throws UnsupportedOperationException if the {@code add} method is
     *         not supported by this list iterator
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this list
     * @throws IllegalArgumentException if some aspect of this element
     *         prevents it from being added to this list
     */
    void add(E e);
}

  1. ListItr类hasPrevious()方法:由于ListItr类继承了Itr类,因此ListItr的cursor属性判断迭代器是否还有前一个元素。ArrayList中除了第一个元素以外,其余元素均有前一个元素。
                public boolean hasPrevious() {
                    return cursor != 0;
                }
  1. nextIndex()方法返回下一个将返回的元素的位置。
                public int nextIndex() {
                    return cursor;
                }
  1. previousIndex()方法用于返回前一个元素的索引位置。
                public int previousIndex() {
                    return cursor - 1;
                }
  1. previous()方法用于返回前一个元素
                public E previous() {
                    checkForComodification();
                    int i = cursor - 1;
                    if (i < 0)
                        throw new NoSuchElementException();
                    Object[] elementData = root.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i;
                    return (E) elementData[offset + (lastRet = i)];
                }
  1. ListItr类的set()方法用于更新元素值
                public void set(E e) {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

                    try {
                        root.set(offset + lastRet, e);
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }
  1. ListItr类的add()方法用于添加元素
                public void add(E e) {
                    checkForComodification();

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

十三、ArrayList重点

  1. ArrayList是基于顺序表实现的容器。
  2. ArrayList存储模型。
  3. ArrayList查找的时间复杂度。
  4. ArrayList迭代器。
  5. ArrayList线程安全问题及与之对应的并发容器。
  • 32
    点赞
  • 196
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: ArrayList的add方法是用来向列表中添加元素的。它有两种重载形式: 1. add(E e):将指定的元素添加到列表的末尾。 2. add(int index, E e):将指定的元素插入到列表的指定位置。 其中,第二种形式可以用来在列表中间插入元素,也可以用来替换列表中指定位置的元素。如果插入位置超出了列表的范围,会抛出IndexOutOfBoundsException异常。 ### 回答2: Java中的ArrayList是一个非常常用的集合类,在使用时,我们经常需要向其中添加元素。ArrayList的add()方法就是用来添加元素的。 ArrayList的add()方法有两种形式:add(E e) 和 add(int index, E e)。 add(E e)方法向ArrayList的末尾添加一个元素。比如,如果我们有一个ArrayList<Integer>,我们可以通过以下代码向其添加一个元素: ``` ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); ``` 这个代码段创建了一个ArrayList对象,并向其中添加了一个值为1的元素。 如果希望在ArrayList的指定位置插入元素,可以使用add(int index, E e)方法。例如: ``` ArrayList<Integer> list = new ArrayList<Integer>(); list.add(0, 0); // 在第0个位置插入一个值为0的元素 ``` 这个代码段创建了一个ArrayList对象,并在其第0个位置插入了一个值为0的元素。 需要注意的是,add()方法会改变ArrayList中元素的索引,例如在第一个元素前插入一个元素会将原来的第一个元素的索引变为1。此外,如果我们使用add(int index, E e)方法向一个空列表(长度为0)添加元素,则只能将索引值设置为0。如果设置的索引值大于0,会抛出IndexOutOfBoundsException异常。 在将ArrayList作为参数传递给其他方法时,我们可以使用add()方法来向其中添加元素。例如: ``` public void processArrayList(ArrayList<Integer> list) { list.add(1); list.add(2); } ``` 这个代码段定义了一个名为processArrayList的方法,其中向传入的ArrayList对象中添加了两个元素:1和2。 总之,JavaArrayList的add()方法是非常方便的,可以帮助开发人员轻松地向列表中添加元素,提高开发效率。 ### 回答3: Java中的ArrayList是一种动态数组,它是Java集合框架中的一部分。我们可以在其中添加、删除或者访问元素。add方法是ArrayList中最常用的一个方法,用于向其末尾添加元素。在Java中,我们使用ArrayList的add方法来添加元素到数组中。 ArrayList的add方法有两种构造方式: 1. add(E e),它简单地在ArrayList的末尾添加一个元素。这个方法将指定的元素添加到此列表的末尾。 2. add(int index,E element)。这个方法将指定的元素插入到此列表中的指定位置。 注意:使用add(int index,E element)方法时,一定要输入正确的插入位置参数。如果索引位置不对的话,就会抛出IndexOutOfBoundsException异常。 下面是Java ArrayList中add方法的一些例子: 1. 添加元素到ArrayList的末尾: ArrayList<String> mylist = new ArrayList<String>(); mylist.add("hello"); mylist.add("world"); 2. 在ArrayList的指定索引位置添加元素: ArrayList<String> mylist = new ArrayList<String>(); mylist.add("hello"); mylist.add("world"); mylist.add(1, "java"); 通过上面的代码我们可以看出,ArrayList的add方法很灵活,我们可以在列表中添加任意类型的元素,ArrayList会自动将它们转换为Object类型。另外,ArrayList也会自动调整其大小以适应大量元素的添加。如果我们需要在Java中动态地添加元素,那么这个add方法就是非常有用的工具。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZhShy23

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值