以下是为 ArrayList
类中各个方法添加详细源代码阅读注释后的完整代码:
public class ArrayList<E> { // 表示 ArrayList 的默认初始容量,当创建一个未指定初始容量的 ArrayList 时,会使用这个值作为初始容量。 private static final int DEFAULT_CAPACITY = 10; // 用于表示空的 ArrayList 实例的共享空数组,当指定初始容量为 0 时会使用这个数组。 private static final Object[] EMPTY_ELEMENTDATA = {}; // 用于默认大小的空实例的共享空数组,与 EMPTY_ELEMENTDATA 区分开来,以便在添加第一个元素时知道要将容量扩展到多大。 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 存储 ArrayList 元素的数组缓冲区,ArrayList 的容量就是这个数组的长度。 // 任何初始状态下 elementData 等于 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList, // 在添加第一个元素时会将容量扩展到 DEFAULT_CAPACITY transient Object[] elementData; // non-private to simplify nested class access //表示 ArrayList 中实际包含的元素数量。 private int size; public ArrayList(int initialCapacity) { if (initialCapacity > 0) { // 如果初始容量大于 0,则创建一个指定容量的新数组 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { // 如果初始容量等于 0,则使用 EMPTY_ELEMENTDATA 空数组 this.elementData = EMPTY_ELEMENTDATA; } else { // 如果初始容量小于 0,则抛出异常 throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); } } // 构造一个初始容量为 10 的空列表 public ArrayList() { // 使用 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 空数组,在添加第一个元素时会扩展到默认容量 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // 可分配数组的最大大小。一些虚拟机在数组中会保留一些头部信息, // 尝试分配更大的数组可能会导致 OutOfMemoryError 异常,提示请求的数组大小超过了虚拟机的限制。 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; public boolean add(E e) { // 确保内部容量足够容纳新元素,会触发容量扩展逻辑 ensureCapacityInternal(size + 1); // 将元素添加到数组的末尾,并将列表大小加 1 elementData[size++] = e; return true; } // 确保内部容量足够容纳指定数量的元素。 // 首先计算所需的最小容量,然后调用 ensureExplicitCapacity 方法进行容量检查和扩展。 private void ensureCapacityInternal(int minCapacity) { // 计算所需的最小容量 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } // 确保数组的容量足够容纳指定数量的元素。 // 如果所需的最小容量大于当前数组的长度,则调用 grow 方法进行扩容。 private void ensureExplicitCapacity(int minCapacity) { if (minCapacity - elementData.length > 0) // 当所需容量大于当前数组长度时,进行扩容操作 grow(minCapacity); } // 计算所需的最小容量。 // 如果当前数组是 DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则返回默认容量和指定最小容量中的较大值; // 否则返回指定的最小容量。 private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 如果是默认大小的空数组,返回默认容量和最小容量中的较大值 return Math.max(DEFAULT_CAPACITY, minCapacity); } // 否则返回最小容量 return minCapacity; } // 增加数组的容量,以确保它至少能够容纳指定数量的元素。 // 期望的最小容量 private void grow(int minCapacity) { // 记录旧容量 int oldCapacity = elementData.length; // 新容量为旧容量的 1.5 倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) // 如果新容量小于所需的最小容量,则将新容量设置为最小容量 newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) // 如果新容量超过最大数组大小,调用 hugeCapacity 方法处理 newCapacity = hugeCapacity(minCapacity); // 使用 Arrays.copyOf 方法将旧数组元素复制到新数组中 elementData = Arrays.copyOf(elementData, newCapacity); } // 处理超大容量需求。 // 如果最小容量为负数(溢出),则抛出 OutOfMemoryError 异常 // 否则,如果最小容量大于最大数组大小,返回 Integer.MAX_VALUE,否则返回最大数组大小。 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow // 最小容量为负数,抛出内存溢出异常 throw new OutOfMemoryError(); // 如果最小容量大于最大数组大小,返回 Integer.MAX_VALUE,否则返回最大数组大小 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } // 返回指定元素在列表中第一次出现的索引,如果列表中不包含该元素,则返回 -1。 // 更正式地说,返回满足条件 <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> 的最小索引 <tt>i</tt>, // 如果没有这样的索引,则返回 -1。 public int indexOf(Object o) { if (o == null) { // 如果要查找的元素为 null,则遍历数组查找第一个 null 元素 for (int i = 0; i < size; i++) if (elementData[i] == null) return i; } else { // 如果要查找的元素不为 null,则使用 equals 方法遍历数组查找匹配元素 for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } // 未找到匹配元素,返回 -1 return -1; } // 返回指定元素在列表中最后一次出现的索引,如果列表中不包含该元素,则返回 -1。 // 更正式地说,返回满足条件 <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> 的最大索引 <tt>i</tt>, // 如果没有这样的索引,则返回 -1。 public int lastIndexOf(Object o) { if (o == null) { // 如果要查找的元素为 null,则从数组末尾开始遍历查找最后一个 null 元素 for (int i = size - 1; i >= 0; i--) if (elementData[i] == null) return i; } else { // 如果要查找的元素不为 null,则从数组末尾开始使用 equals 方法遍历查找匹配元素 for (int i = size - 1; i >= 0; i--) if (o.equals(elementData[i])) return i; } // 未找到匹配元素,返回 -1 return -1; } // 获取指定索引位置的元素。 // 该方法将数组中的元素强制转换为泛型类型 E 并返回。 @SuppressWarnings("unchecked") E elementData(int index) { // 将数组中的元素强制转换为泛型类型 E 并返回 return (E) elementData[index]; } // 删除列表中指定位置的元素,并将后续元素向左移动(索引减 1)。 public E remove(int index) { // 检查索引是否越界 rangeCheck(index); // 获取要删除的元素 E oldValue = elementData(index); // 计算需要移动的元素数量 int numMoved = size - index - 1; if (numMoved > 0) // 如果需要移动元素,则使用 System.arraycopy 方法将后续元素向左移动 System.arraycopy(elementData, index + 1, elementData, index, numMoved); // 将最后一个元素置为 null,以便垃圾回收 elementData[--size] = null; // 返回被删除的元素 return oldValue; } // 如果列表中存在指定元素,则删除该元素的第一次出现。如果列表中不包含该元素,则列表保持不变。 // 更正式地说,删除满足条件 <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> 的最小索引 <tt>i</tt> 对应的元素(如果存在这样的元素)。 // 如果列表中包含指定元素(即列表因调用此方法而发生了变化),则返回 <tt>true</tt>。 // 要从列表中删除的元素(如果存在) // 如果列表中包含指定元素,则返回 true public boolean remove(Object o) { if (o == null) { // 如果要删除的元素为 null,则遍历数组查找第一个 null 元素并删除 for (int index = 0; index < size; index++) if (elementData[index] == null) { // 调用 fastRemove 方法快速删除元素 fastRemove(index); return true; } } else { // 如果要删除的元素不为 null,则使用 equals 方法遍历数组查找匹配元素并删除 for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { // 调用 fastRemove 方法快速删除元素 fastRemove(index); return true; } } // 未找到要删除的元素,返回 false return false; } // 私有删除方法,跳过边界检查且不返回被删除的值。 private void fastRemove(int index) { // 计算需要移动的元素数量 int numMoved = size - index - 1; if (numMoved > 0) // 如果需要移动元素,则使用 System.arraycopy 方法将后续元素向左移动 System.arraycopy(elementData, index + 1, elementData, index, numMoved); // 将最后一个元素置为 null,以便垃圾回收 elementData[--size] = null; } // 删除列表中的所有元素。调用此方法后,列表将为空。 public void clear() { // 将数组中的所有元素置为 null,以便垃圾回收 for (int i = 0; i < size; i++) elementData[i] = null; // 将列表大小置为 0 size = 0; } // 检查给定的索引是否在有效范围内。如果不在范围内,则抛出适当的运行时异常。 // 此方法不检查索引是否为负数,因为它总是在进行数组访问之前立即使用,而数组访问会在索引为负数时抛出 ArrayIndexOutOfBoundsException 异常。 private void rangeCheck(int index) { if (index >= size) // 如果索引大于等于列表大小 throw new IndexOutOfBoundsException(); } }