4.jdk源码阅读之ArrayList(下)

1. 写在前面

接着上一篇文章,我们继续来分析jdk ArrayList的源码
上一篇文章我们看了向ArrayList中添加元素的底层实现,对应的,jdk也提供了从ArrayList中删除元素的操作,在看代码之前我先抛出几个问题大家可以一起思考下:

  1. 将元素从数组中删除底层是怎么实现的?
  2. 元素删除后 数组会缩容吗?

2. remove源码解读

ArrayList提供了两种移除元素的方式,一种是根据下标,另外一种根据对应的目标元素。

2.1 根据下标

 /**
     * 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) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
  1. rangeCheck(index)
    这个方法用于检查索引是否在有效范围内。如果索引超出范围,则抛出 IndexOutOfBoundsException 异常。源代码如下:
  /**
     * 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.
     */
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
  1. modCount++
    modCount 是 ArrayList 的一个字段,用于记录对列表结构的修改次数(如添加、删除操作)。它用于支持 fail-fast 机制,检测并发修改。

  2. 获取旧值
    获取并保存要删除的元素,用于方法返回。elementData(index) 是一个私有方法,用于根据索引获取元素。

  3. 计算需要移动的元素数量

int numMoved = size - index - 1;

计算从指定索引到最后一个元素之间的元素数量,这些元素需要向左移动一个位置。

  1. 移动元素
if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index, numMoved);

如果需要移动的元素数量大于 0,则使用 System.arraycopy 方法将 index+1 位置后的所有元素向左移动一个位置,覆盖掉被删除元素的位置。

  1. 清除最后一个元素
elementData[--size] = null; // clear to let GC do its work

将数组中最后一个有效元素位置置为 null,以便垃圾回收器(GC)能够回收该对象。同时,减少 size 表示列表的当前大小。

2.2 根据目标元素

/**
    * 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;
   }
  1. 检查元素是否为 null
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;
        }
}

  • 这个方法首先检查传入的元素 o 是否为 null。
    • 如果 o 为 null,则遍历列表,查找第一个 null 元素的位置,并调用 fastRemove(index) 方法删除该元素,然后返回 true。
    • 如果 o 不为 null,则遍历列表,查找第一个等于 o 的元素的位置,并调用 fastRemove(index) 方法删除该元素,然后返回 true。
  1. 辅助方法 fastRemove
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
}

fastRemove 方法用于在指定索引处快速删除元素,并将后续元素左移以填补空缺

  • 增加 modCount 以支持 fail-fast 机制。
  • 计算需要移动的元素数量,并使用 System.arraycopy 方法将这些元素左移一个位置。
  • 将数组中最后一个有效元素位置置为 null,以便垃圾回收器(GC)能够回收该对象。
  • 减少 size 表示列表的当前大小。

系列文章

1.JDK源码阅读之环境搭建

2.JDK源码阅读之目录介绍

3.jdk源码阅读之ArrayList(上)

4.jdk源码阅读之ArrayList(下)

5.jdk源码阅读之HashMap

6.jdk源码阅读之HashMap(下)

7.jdk源码阅读之ConcurrentHashMap(上)

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

至真源

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

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

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

打赏作者

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

抵扣说明:

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

余额充值