集合框架--ArrayList

106 阅读21分钟

1. 简介

基于数组实现,增删慢,查询快,线程不安全。

ArrayList 是使用最广泛的 List 实现类,其内部数据结构基于数组实现,提供了对 List 的增加、删除和访问功能。

ArrayList 的缺点是对元素必须连续存储,当需要在 ArrayList 的中间位置插入或者删除元素时,需要将待插入或者删除的节点后的所有元素进行移动,其修改代价较高,因此,ArrayList 不适合随机插入和删除的操作,更适合随机查找和遍历的操作。

ArrayList 不需要在定义时指定数组的长度,在数组长度不能满足存储要求时,ArrayList 会创建一个新的更大的数组并将数组中已有的数据赋值到新的数组中。

ArrayList 底层是数组队列,相当于动态数组。与 Java 中的普通数组相比,它的容量能够动态的增长,没有固定大小的限制。

import java.util.ArrayList; //导入包

ArrayList objectName = new ArrayList<>(); //初始化

  • E:数据类型,设置 objectName 的数据类型,只能为引用数据类型
  • objectName :对象名
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    //////
}
  • RandomAccess:标志接口,实现这个接口即表示该集合支持快速随机访问,ArrayList中我们可以通过下标快速获取元素对象即快速随机访问。
  • Cloneable:实现 clone() 方法,能够被克隆。
  • Serializable:支持序列化,能够序列化去传输。

2. 扩容机制分析

2.1 变量

// 默认初始化容量大小:10
private static final int DEFAULT_CAPACITY = 10;
// 空数组,用于空实例
private static final Object[] EMPTY_ELEMENTDATA = {};
// 用于默认大小空实例的共享空数组实例。
// 将它从 EMPTY_ELEMENTDATA 数组中区分出来,以知道在添加第一个元素时容量需要增加多少
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 实际保存数据的数组
transient Object[] elementData;
// 元素个数
private int size;

2.2 构造函数

// 创建一个空的数组,并为其复制为空数组
public ArrayList() {
    // 在这里我们可以看到,在调用 ArrayList 的空参构造函数的时候其实并没有给数组指定初始容量,而是分配了一个空数组
    // 只有当真正调用 add 方法的时候才会分配默认容量 10;
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 构造一个初始容量为 initialCapacity 大小的数组
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);
    }
}
/**
     * 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
    按集合迭代器返回的顺序构造包含指定集合元素的列表。
    @param c要将其元素放置到此列表中的集合
    @如果指定的集合为空,则引发NullPointerException
*/
public ArrayList(Collection<? extends E> c) {
    Object[] a = c.toArray();
    if ((size = a.length) != 0) {
        if (c.getClass() == ArrayList.class) {
            elementData = a;
        } else {
            elementData = Arrays.copyOf(a, size, Object[].class);
        }
    } else {
        // replace with empty array.
        elementData = EMPTY_ELEMENTDATA;
    }
}

2.3 扩容流程

// 定义一个 ArrayList 集合
List<String> list = new ArrayList<>();
// 向集合中添加元素
list.add("data001");
  1. 第一行代码是调用 ArrayList 的无参构造方法
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; // 空数组,长度为 0
}
  1. 第二行代码添加一个元素
// 添加元素方法
// 在添加元素前会先调用 ensureCapacityInternal 方法判断是否需要进行扩容
// 然后将元素添加到数组的尾部
public boolean add(E e) {
    // 判断是否需要进行扩容,参数为 元素个数+1,1 表示新增一个元素
    ensureCapacityInternal(size + 1);
    // 追加新元素到数组尾部
    elementData[size++] = e;
    return true;
}
// 首先调用 calculateCapacity 方法判断是否为空数组
// 再调用 ensureExplicitCapacity 方法进行下一步处理
private void ensureCapacityInternal(int minCapacity) {
    // 最小需要的容量
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
// 判断是否为空数组,如果是空数组则比较默认容量 10 和元素个数+1 的大小,然后两者取最大值返回
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        // 得到默认数组大小 10 并返回
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
// 判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    // 如果原来的数组长度小于所需最小容量,则调用 grow 方法进行扩容
    if (minCapacity - elementData.length > 0)
        // 真正的扩容方法
        grow(minCapacity);
}
// 扩容方法
private void grow(int minCapacity) {
    // overflow-conscious code
    // 记录数组的长度
    int oldCapacity = elementData.length;
    // 新的容量就是原来数组长度的1.5倍
    // 右移运算效率较高,计算新数组大小,老数组大小 + (老数组容量右移动一位,即除以2)
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 判断:如果新容量小于最小容量,就直接把最小容量赋值给新的容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 如果超出临界值,就调用 hugeCapacity 方法
    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 final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
@Native public static final int   MAX_VALUE = 0x7fffffff;
// 如果 minCapacity 为负数就抛出异常
// 如果比临界值大,就直接赋值 MAX_VALUE
// 如果比临界值小,就直接赋值临界值
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}
  1. 使用无参构造函数创建 ArrayList 对象,直接赋值给 elementData 一个默认的空数组,数组长度为 0.

  2. 添加元素

    1. 进入 add 方法内,首先调用 ensureCapacityInternal 方法

    2. 在 ensureCapacityInternal 方法中首先调用 calculateCapacity 然后调用 ensureExplicitCapacity 方法

    3. 在 calculateCapacity 方法中,这个方法主要就是判断是否为空数组,如果是空数组就比较默认容量 10 和最小容量的大小,取二者的最大值;如果不是空数组,则直接返回最小容量即10。

    4. 在 ensureExplicitCapacity 方法中,这个方法主要作用是判断是否需要扩容,如果最小容量- elementData 数组长度 > 0,说明最小容量大于数组长度,此时调用 grow 方法进行扩容

    5. 在 grow 方法中,这个方法实际就是扩容方法。

      新定义一个变量 oldCapacity 存储原来数组的长度,再定义一个变量 newCapacity = oldCapacity + (oldCapacity >> 1),就是为原来数组长度的 1.5 倍,然后再判断 newCapacity - minCapacity 是否小于 0,小于 0 则说明 newCapacity 不够,直接执行 newCapacity = minCapacity,然后判断是否超过临界值,如果 newCapacity - MAX_ARRAY_SIZE 大于 0 ,调用hugeCapacity 方法,该方法中会判断 minCapacity 是否为负数,如果是则抛出 OutOfMemoryError 异常,否则如果比临界值大则直接赋值 MAX_VALUE(MAX_VALUE = 0x7fffffff),如果比临界值小则赋值 MAX_ARRAY_SIZE( MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;), 没超过就直接调用 elementData = Arrays.copyOf(elementData, newCapacity) 进行实际的扩容。

    6. 返回 add 方法,执行 elementData[size++] = e; 返回 true

3. 缩容机制分析

缩容指的是 ArrayList 中的 Object 数组 elementData 的大小缩减

使用 ArrayList 对象过程中,自动扩容一般发生在 add() 方法和 addAll() 方法中,那么在 remove() 方法中是否会自动进行缩容呢?

/**
 * 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) {
    // 校验传入的下标是否大于或等于当前 ArrayList 的长度 size
    // 如果大则抛出异常 IndexOutOfBoundsException
    rangeCheck(index);
    
    // 修改次数自增,用于快速失败机制
    modCount++;
    // 获取需要删除的元素的值
    E oldValue = elementData(index);
    // 计算数组从需要删除的元素后需要移动的元素个数
    int numMoved = size - index - 1;
    if (numMoved > 0)
        // 使用 System.arraycopy 进行数组元素左移动
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 空位标记为 null,便于 GC 回收,size 自减
    elementData[--size] = null; // clear to let GC do its work
    // 返回被删除的元素
    return oldValue;
}
// 检查索引是否越界,如果越界则抛出异常
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
    @param src源数组。
    @param srcPos在源数组中的起始位置。
    @param dest目标数组。
    @param destPos目标数据中的起始位置。
    @param length要复制的数组元素的数量。
    System.arraycopy()并不会影响源数组和目标数组的长度。
*/
public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

图示:

ArrayList 类的 elementData,size 为 0

image-20230207090456885

假设要删除下标index为 4 的元素

E oldValue = elementData(index);

标红的是待删除的元素

image-20230207090546966

int numMoved = size - index - 1; 计算数组需要从删除元素后移动的元素个数

numMoved = 10 - 4 - 1 = 5

此时需要移动的是在 4 之后的 5 个元素

image-20230207090822417

使用 System.arraycopy(); 进行数组元素左移动

System.arraycopy(elementData, 5, elementData, 4, 5);

image-20230207091139078

左移之后,最后一个数组元素需要进行移除,此处标记为灰色的元素

image-20230207091037696

elementData[--size] = null;

多余的元素标记为 null,size 自减

image-20230207091239828

从上面可以看到,ArrayList 在执行 remove() 方法的时候,内置的 object 数组实际上并没有减少长度,只是通过数组部分元素左移、最后一个元素置为 null 同时 size 自减来实现删除操作的。其他的删除方法 index remove(object)、removeAll() 和 removeRange() 也是类型的做法。

在 ArrayList 中还有一个方法用来对数组进行清空的,那就是 clear() 方法,源码如下:

/**
 * 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
    // 遍历数组,为所有元素赋值为 null,便于 GC 回收
    for (int i = 0; i < size; i++)
        elementData[i] = null;
    // 为 size 赋值 0 
    size = 0;
}

从上面分析可以得出,ArrayList 是不提供自动缩容机制的。

这样设计也是无可厚非的,因为什么时候都无法判断是否需要进行缩容操作

自此我们知道了,ArrayList 是没有自动缩容的机制的,但是它是可以进行缩容的,那就是 ArrayList 的方法 trimToSize,该方法会将 ArrayList 内置的数组缩容到当前的 size,源码如下:

/**
 * Trims the capacity of this <tt>ArrayList</tt> instance to be the
 * list's current size.  An application can use this operation to minimize
 * the storage of an <tt>ArrayList</tt> instance.
  将此<tt>ArrayList</tt>实例的容量调整为列表的当前大小。应用程序可以使用此操作来最小化<tt>ArrayList</tt>实例的存储。
 */
public void trimToSize() {
    modCount++;
    // 判断当前是否需要缩容
    if (size < elementData.length) {
        // 如果 size 为 0,直接给 elementData 赋值内置的空数组
        // 不为 0则创建一个 size 长度的新数组
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

总结:

  1. ArrayList 的 remove 只是通过数组部分元素左移、最后一个元素置为 null、同时 size 自减的方式来实现删除元素操作。实际上并没有对 elementData 进行缩容
  2. 可以使用 trimToSize() 方法对 elementData 来进行缩容

4. 其他方法源码

  1. get(int index) :根据下标获得元素对象
/**
 * 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) {
    // 检查 index 是否越界
    rangeCheck(index);
    return elementData(index);
}
// 根据下标从 elementData 数组中返回元素
@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}
  1. remove(Object o):根据对象删除元素
/**
 * 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
 	从列表中删除指定元素的第一个出现(如果存在)。如果列表中不包含该元素,则它将保持不变。
 	更正式地说,删除具有最低索引<tt>i</tt>的元素,使得<tt>(o==null?get(i)==null:&nbsp;o.equals(get(i)))</tt>(如果存在这样的元素)。
 	如果此列表包含指定的元素(或者等效地,如果此列表因调用而更改),则返回<tt>true</tt>。
	*@param o 要从此列表中删除的元素(如果存在)
	*@return<tt>true</tt> 如果此列表包含指定的元素
 */
public boolean remove(Object o) {
    // 如果要删除的元素 o 为 null(ArrayList允许元素为 null,且可以重复)
    if (o == null) {
        // 遍历数组
        for (int index = 0; index < size; index++)
            // 直接用 == 比较值是否相等
            if (elementData[index] == null) {
                // 调用删除操作,参数为下标
                fastRemove(index);
                return true;
            }
    } else {
        // 如果不为null,需要调用 equals() 方法来进行匹配比较
        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
 * return the value removed.
 	跳过边界检查且不返回移除值的私有移除方法
 */
// 根据索引快速删除,同样是复制数组元素
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
}
  1. 扩容方法,可以自己调用,避免重复扩容
/**
 * Increases the capacity of this <tt>ArrayList</tt> instance, if
 * necessary, to ensure that it can hold at least the number of elements
 * specified by the minimum capacity argument.
 *
 * @param   minCapacity   the desired minimum capacity 所需的最小容量
 	如有必要,增加这个<tt>ArrayList</tt>实例的容量,以确保它至少可以容纳最小容量参数指定的元素数
 */
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);
    }
}

5. 常用 API 方法

  1. add(),插入

    功能:将元素插入到指定位置的动态数组中

    语法:arraylist.add(int index, E lement)

    - index:可选参数,表示元素所插入处的索引值,若没有添加到末尾
    - element:要插入的元素
    

    返回值:成功插入返回 true,如果index超出范围,抛出 IndexOutOfBoundsException 异常

    public class test {
        public static void main(String[] args){
            ArrayList<Integer> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            integers.add(3);
            integers.add(0,5);
            System.out.println(integers);
        }
    }
    
    运行结果:
        [5,1, 2, 3]
    
  2. addAll()

    功能:将给定结合中的所有元素添加到 arraylist 中

    语法:arraylist.addAll(int index, Collection c)

    	- index:可选参数,表示元素所插入处的索引值,若没有添加到末尾
    	- c:要插入的集合元素
    

    返回值:插入成功返回 true,如果给定的集合为 null,则超出 NullPointerExceptoin 异常,如果 index 超出范围,方法抛出 IndexOutOfBoundsException 异常

    public class test {
        public static void main(String[] args){
            ArrayList<Integer> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            ArrayList<Integer> integers1 = new ArrayList<>();
            integers1.add(3);
            integers1.add(4);
            integers.addAll(integers1);
            System.out.println(integers);
        }
    }
    
    运行结果:
        [1, 2, 3, 4]
    
  3. clear()

    功能:方法用于删除动态数组冲的所有元素

    方法:arraylist.clear()

    public class test {
        public static void main(String[] args){
            ArrayList<Integer> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            System.out.println(integers);
            integers.clear();
            System.out.println(integers);
        }
    }
    
    运行结果:
        [1, 2]
    	[]
    
  4. clone()

    功能:拷贝一份动态数组,浅拷贝

    浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,所以如果其中一个对象改变这个地址,就会影响到另一个对象

    深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

    语法:arraylist.clone()

    public class test {
        public static void main(String[] args){
            ArrayList<Integer> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            Object clone = integers.clone();
            System.out.println(integers);
            System.out.println(clone);
        }
    }
    
    运行结果:
        [1, 2]
    	[1, 2]
    
  5. contains()

    功能:用于判断元素是否在动态数组中

    语法:arraylist.contains(Object obj)

    参数:obj:要检测的元素

    返回值:如果存在返回 true,如果不存在返回 false

    public class test {
        public static void main(String[] args){
            ArrayList<Object> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            byte[] b = new byte[10];
            integers.add(b);
            System.out.println(integers.contains(b));
        }
    }
    
    运行结果:
        true
    
  6. set(),替换

    功能:替换动态数组中的指定索引的数组

    语法:arraylist.set(int index, E element)

    	- index:索引位置
    	- element:替换的新元素
    

    返回值:返回之前在 index 位置的元素,如果 index 超出范围,抛出 IndexOutOfBoundsException 异常。

    public class test {
        public static void main(String[] args){
            ArrayList<Object> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            integers.set(0,"aaa");
            System.out.println(integers);
        }
    }
    
    运行结果:
        [aaa, 2]
    
  7. get()

    功能:通过索引值获取动态数组中的元素

    语法:arraylist.get(int index)

    	- index:索引值
    

    返回值:返回动态数组中索引处的元素,如果index超出了范围,抛出 IndexOutOfBoundsException 异常

    public class test {
        public static void main(String[] args){
            ArrayList<Object> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            System.out.println(integers.get(0));
        }
    }
    
    运行结果:
        1
    
  8. indexOf()

    功能:返回动态数组中元素的索引值

    语法:arraylist.indexOf(Object obj)

    	- obj:查找的元素
    

    返回值:从动态数组中返回指定元素的位置的索引值,如果 obj 元素在动态数组中重复出现,返回数组中最先出现 obj 的元素索引值,如果不存在返回 -1

    public class test {
        public static void main(String[] args){
            ArrayList<Object> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            System.out.println(integers.indexOf(1));
        }
    }
    
    运行结果:
        1
    
  9. removeAll()

    功能:用于删除存在于指定集合中的动态数组元素

    语法:arraylist.removeAll(Collection c)

    	- c:动态数组列表中要删除的元素集合
    

    返回值:如果从动态数组成功删除元素返回 true,如果动态数组中存在的元素类与指定 collection 的元素类不兼容抛出 ClassCastException 异常,如果动态数组中包含 null 元素,并且指定 collection 不允许 null 元素,则抛出 NullPointerException 异常

    public class test {
        public static void main(String[] args){
            ArrayList<Object> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            System.out.println(integers);
            System.out.println(integers.removeAll(integers));
            System.out.println(integers);
        }
    }
    
    运行结果:
        [1, 2]
    	true
    	[]
    
  10. remove()

    功能:删除动态数组里的单个元素

    语法:

    • arraylist.remove(Object obj):删除指定元素,obj 要删除的元素,如果 obj 出现多次,则删除第一次出现的元素
    • arraylist.remove(int index):删除指定索引位置的元素,index 要删除元素索引值

    返回值:如果是 obj 删除成功返回 true,如果是 index 则返回删除的元素,如果索引范围超出范围抛出 IndexOutOfBoundsException 异常

    public class test {
        public static void main(String[] args){
            ArrayList<Object> integers = new ArrayList<>();
            integers.add("aaa");
            integers.add("bbb");
            System.out.println(integers.remove(1));
            System.out.println(integers.remove("aaa"));
        }
    }
    
    运行结果:
        bbb
        true
    
  11. size()

    功能:返回动态数组中元素的数量

    语法:arraylist.size()

    public class test {
        public static void main(String[] args){
            ArrayList<Object> integers = new ArrayList<>();
            integers.add("aaa");
            integers.add("bbb");
            System.out.println(integers.size());
        }
    }
    
    运行结果:
        2
    
  12. isEmpty()

    功能:用于判断动态数组是否为空

    语法:arraylist.isEmpty()

    返回值:数组中不存在任何元素返回 true,存在元素返回 false

    public class test {
        public static void main(String[] args){
            ArrayList<Object> integers = new ArrayList<>();
            integers.add("aaa");
            integers.add("bbb");
            System.out.println(integers.isEmpty());
        }
    }
    
    运行结果:
        false
    
  13. subList()

    功能:截取并返回动态数组中的一部分

    语法:arraylist.subList(int fromIndex, int toIndex)

    	- fromIndex:截取元素的起始位置,包含
    	- toIndex:截取元素的结束位置,不包含
    

    返回值:返回截取部分,如果 fromIndex 小于 0 或大于数组长度抛出 IndexOutOfBoundsException 异常,如果 fromIndex 大于 toIndex 抛出 lllegalArgumentException 异常

    public class test {
        public static void main(String[] args){
            ArrayList<Object> integers = new ArrayList<>();
            integers.add("aaa");
            integers.add("bbb");
            integers.add("ccc");
            integers.add("ddd");
            System.out.println(integers.subList(1, 3));
        }
    }
    
    运行结果:
       [bbb, ccc]
    
  14. sort()

    功能:根据指定顺序对动态数组中的元素进行排序

    语法:arraylist.sort(Comparator c)

    	- Comparator.naturalOrder():自然排序
    	- Comparator.reverseOrder():反转排序
    

    返回值:不返回值,只是更改动态数组列表中元素的顺序

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            integers.add("ccc");
            integers.add("bbb");
            integers.add("aaa");
            integers.add("ddd");
            System.out.println(integers);
            integers.sort(Comparator.naturalOrder());
            System.out.println(integers);
            integers.sort(Comparator.reverseOrder());
            System.out.println(integers);
        }
    }
    
    运行结果:
        [ccc, bbb, aaa, ddd]
    	[aaa, bbb, ccc, ddd]
        [ddd, ccc, bbb, aaa]
    
  15. toArray()

    功能:将 ArrayList 对象转换为数组

    语法:arraylist.toArray(T[] arr)

    	- T[] arr,可选参数,用于存储数组元素的数组,T 是数组的类型
    

    返回值:如果有 T[] arr,则返回 T 类型的数组,如果没有返回 Object 类型的数组

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            integers.add("ccc");
            integers.add("bbb");
            integers.add("aaa");
            integers.add("ddd");
            String[] strs = new String[integers.size()];
            integers.toArray(strs);
            for (String str : strs) {
                System.out.println(str);
            }
        }
    }
    
    运行结果:
        ccc
        bbb
        aaa
        ddd
    
  16. toString()

    功能:将整个 arraylist 转换为一个 String 类型

    语法:arraylist.toString()

    返回值:返回 arraylist 的字符串表示形式

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            integers.add("ccc");
            integers.add("bbb");
            integers.add("aaa");
            integers.add("ddd");
            System.out.println(integers.toString());
        }
    }
    
    运行结果:
        [ccc, bbb, aaa, ddd]
    
  17. ensureCapacity()

    功能:设置具有指定容量大小的动态数组

    语法:arraylist.ensureCapacity(int minCapacity)

    	- minCapacity:动态数组的容量
    

    无返回值

    设置大小为3,但是还是可以添加进去,因为arraylist 会自动调整大小

    使用ensureCapacity()方法:如果我们使用 ensureCapacity() 方法调整 arraylist 的大小,那么 arraylist 将会马上调整为指定的容量大小。否则,每次添加元素时都会调整 arraylist 的大小。

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            integers.ensureCapacity(3);
            integers.add("ccc");
            integers.add("bbb");
            integers.add("aaa");
            integers.add("ddd");
            System.out.println(integers.toString());
        }
    }
    
    运行结果:
        [ccc, bbb, aaa, ddd]
    
  18. lastIndexOf()

    功能:返回指定元素在动态数组中最后一次出现的位置

    语法:arraylist.lastIndexOf(Object obj)

    	- obj:查找的元素
    

    返回值:返回指定元素最后出现的位置的索引值,如果 obj 元素在动态数组中重复出现,返回在数组中最后出现 obj 的元素索引值,如果动态数组中不存在指定元素返回 -1

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            integers.ensureCapacity(3);
            integers.add("ccc");
            integers.add("bbb");
            integers.add("aaa");
            integers.add("aaa");
            integers.add("aaa");
            integers.add("ddd");
            System.out.println(integers.lastIndexOf("aaa"));
        }
    }
    
    运行结果:
        4
    
  19. retainAll()

    功能:用于保留 arraylist 中在指定集合中也存在的那些元素,也就是删除指定集合中不存在的那些元素

    语法:arraylist.retainAll(Collection c)

    - collection:集合参数
    

    返回值:如果arraylist 中删除了元素则返回 true;如果arraylist类中存在的元素与指定 collection 的类中元素不兼容抛出 ClassCastException 异常;如果 arraylist 包含 null 元素,并且指定 collection 不允许 null 元素抛出 NullPointerException

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            ArrayList<String> integers1 = new ArrayList<>();
            integers.add("ccc");
            integers.add("bbb");
            integers.add("ddd");
            integers1.add("bbb");
            System.out.println(integers.retainAll(integers1));
            System.out.println(integers);
        }
    }
    
    运行结果:
        true
    	[bbb]
    
  20. containsAll()

    功能:用于检测 arraylist 是否包含指定集合中的所有元素

    语法:arraylist.containsAll(Collection c)

    	- collection:集合参数
    

    返回值:如果动态数组中包含的集合中的所有元素,则返回true;如果arraylist中存在的元素与指定collection中的元素不兼容抛出 ClassCastException;如果collection中包含 null 元素,并且arraylist中不允许 null 值抛出 NullPointerException 异常

    理解为:containsAll() 方法检查了 collection 是否是动态数组中的一个子集

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            ArrayList<String> integers1 = new ArrayList<>();
            integers.add("ccc");
            integers.add("bbb");
            integers.add("ddd");
            integers1.add("bbb");
            System.out.println(integers.containsAll(integers1));
            System.out.println(integers1.containsAll(integers));
        }
    }
    
    运行结果:
        true
        false
    
  21. trimToSize()

    功能:将动态数组中的容量调整为数组中的元素个数

    语法:arraylist.trimToSize()

    没有返回值,仅更改 arraylist 的容量

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            integers.add("ccc");
            integers.add("bbb");
            integers.add("ddd");
            integers.trimToSize();
            System.out.println(integers.size());
        }
    }
    
    运行结果;
        3
    

    ArrayList trimToSize() 优点:

    ArrayList 工作原理:内部使用数组存储元素,当数组将被存满会创建一个新的数组,容量是当前数组的1.5倍,同时,所有元素都将移至新的元素,假设内部数组已满,又添加一个元素,ArrayList容量就会以相同的比例扩展(即前一个数组的 1.5 倍)。这种情况下,内部数组中将有一些未分配的空间,这时 trimToSize() 方法可以删除未分配的空间并更改 ArrayList 的容量,使其等于 ArrayList 中的元素个数。

  22. removeRange()

    功能:用于删除指定索引之间存在的元素

    语法:arraylist.removeRange(int fromIndex, int toIndex)

    	- fromIndex:索引起始位置,包含
    	- toIndex:索引结束位置,不包含
    

    返回值:无,仅删除一部分动态数组元素,从 fromIndex 到 toIndex -1 的动态数组元素;如果 fromIndex 或者 toIndex 索引超出范围,或者 toIndex < fromIndex 抛出 IndexOutOfBoundException 异常

    public class test extends ArrayList<String>{
        public static void main(String[] args) {
            test integers = new test();
            integers.add("aaa");
            integers.add("bbb");
            integers.add("ccc");
            integers.add("ddd");
            integers.add("eee");
            integers.removeRange(1,3);
            System.out.println(integers);
        }
    }
    
    运行结果;
        [aaa, ddd, eee]
    

    removeRange() 方法是受保护的,所以通常需要继承 ArrayList 类,继承后使用 test 类来创建一个动态数组。

    removeRange() 不常用,通常使用 ArrayList subList() 和 ArrayList clear() 方法实现。

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            integers.add("aaa");
            integers.add("bbb");
            integers.add("ccc");
            integers.add("ddd");
            integers.add("eee");
            integers.subList(1,3).clear();
            System.out.println(integers);
        }
    }
    
    运行结果:
        [aaa, ddd, eee]
    
  23. removeIf()

    功能:用于删除所有满足特定条件的数组元素

    语法:arraylist.removeIf(Predicate filter)

    	- filter:过滤器,判断元素是否要删除
    

    返回值:如果删除返回 true

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            integers.add("aaa");
            integers.add("bbb");
            integers.add("ccc");
            integers.add("ddd");
            integers.add("eee");
            //删除名称带有 b 的元素
            integers.removeIf(e -> e.contains("b"));
            System.out.println(integers);
        }
    }
    
    运行结果:
        [aaa, ccc, ddd, eee]
    

    e -> e.contains(“b”):如果元素中包含 b,返回true

    removeIf()如果e -> e.contains(“b”)返回 true 删除该元素

  24. replaceAll()

    功能:用于将给定的操作内容替换掉数组中每一个元素

    语法:arraylist.replaceAll(UnaryOperator operator)

    	- operator:要替换到动态数组的元素或者一系列操作
    

    没有返回值

    public class test {
        public static void main(String[] args) {
            ArrayList<String> integers = new ArrayList<>();
            integers.add("aaa");
            integers.add("bbb");
            integers.add("ccc");
            integers.add("ddd");
            integers.add("eee");
            //将所有元素更改为大写
            integers.replaceAll(e -> e.toUpperCase());
            System.out.println(integers);
        }
    }
    
    运行结果:
        [AAA, BBB, CCC, DDD, EEE]
    
  25. forEach()

    功能:遍历动态数组中每一个元素并执行特定操作

    语法:arraylist.forEach(Consumer action)

    	- action:对每个元素执行的操作
    

    没有返回值

    public class test {
        public static void main(String[] args) {
            ArrayList<Integer> integers = new ArrayList<>();
            integers.add(1);
            integers.add(2);
            integers.add(3);
            integers.add(4);
            integers.add(5);
            integers.forEach((e) -> {
                e *= 10;
                System.out.println(e + "");
            });
        }
    }
    
    运行结果:
        10
        20
        30
        40
        50
    

参考文献:

juejin.cn/post/684490…

juejin.cn/post/705670…