学习一下Java的ArrayList和contains函数和扩容机制

起因

在Leetcode上做题写了两种暴力解法,但是执行效率上不太一样。

时间上差很远,内存虽然差不多但是前者击败30%,后者击败94%。这两种解法区别是用一条ArrayList还是两条来存数据,所以contains虽然执行次数一样但是检测的长度上不一样,而且ArrayList的扩容次数也不一样,所以学习一下。

contains(Object o)

直接翻(JDK8)源码:

nullobject区分开来还是因为equals有一方是null的话都会导致异常. 合并一起写的话可以用Objects.equals(obj1, obj2)的写法.

所以显然暴力解法用到的contains原理就是朴实无华的一遍遍搜索所以时间特别长.

ArrayList扩容机制

省流: 直接看最下面的grow函数.

如果是默认的ArrayList, 添加元素时会先计算数组长度, 如果元素个数+1大于当前数组长度+1大于elementData.length时进行扩容,扩容后的数组大小是: oldCapacity + (oldCapacity >> 1) 可以理解成1.5倍扩容。

涉及到的源码:

Java 复制代码
// 向指定索引位置插入元素
public void add(int index, E element) {
    // 检查索引范围
    rangeCheckForAdd(index);

    // 确保容量足够
    ensureCapacityInternal(size + 1);  // 增加 modCount(用于支持并发修改的计数器)
    // 使用 System.arraycopy 将元素后移,为新元素腾出位置, 这是跟另一个add的区别⭐⭐⭐⭐⭐
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    elementData[index] = element; // 在指定位置插入新元素
    size++; // 更新列表大小
}

// 在列表末尾添加元素
public boolean add(E e) {
    // 确保容量足够
    ensureCapacityInternal(size + 1);  // 增加 modCount
    elementData[size++] = e; // 在列表末尾添加新元素
    return true;
}

// 内部方法:确保容量足够
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

// 内部方法:计算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        // 如果内部数组为空,返回默认容量或所需容量中的较大者
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity; // 否则返回所需容量
}

// 内部方法:确保容量足够
private void ensureExplicitCapacity(int minCapacity) {
    modCount++; // 增加并发修改计数器

    // 检查容量是否足够,如果不够则扩展
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

// 内部方法:扩展容量
private void grow(int minCapacity) {
    // 溢出安全的代码
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量通常为旧容量的1.5倍
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity; // 如果新容量小于所需容量,使用所需容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity); // 处理可能的巨大容量情况
    // 使用 Arrays.copyOf 扩展数组容量
    elementData = Arrays.copyOf(elementData, newCapacity);
}

实际上Array.copyof底层调用的还是System.arraycopy.

相关推荐
想学习java初学者7 小时前
SpringBoot整合Vertx-Mqtt多租户(优化版)
java·spring boot·后端
AC赳赳老秦7 小时前
政企内网落地:OpenClaw 离线环境深度适配方案,无外网场景下本地化模型对接与全功能使用
java·大数据·运维·python·自动化·deepseek·openclaw
weixin_449173657 小时前
在 Java 中,‌线程安全的 List‌ 主要有以下几种实现方式,它们的效率取决于具体的使用场景(尤其是读写比例):
java·线程安全的list
砚底藏山河7 小时前
股票数据API接口:如何获取股票历历史分时KDJ数据
java·python·maven
MegaDataFlowers9 小时前
运行若依项目
java
lulu12165440789 小时前
JetBrains IDE 终极AI编程方案:CC GUI插件让Claude Code和Codex丝滑运行
java·ide·人工智能·python·ai编程
('-')9 小时前
八股复习2:Java Array list和Linked list
java·开发语言
逸Y 仙X10 小时前
Elasticsearch时间类型实战
java·大数据·elasticsearch·搜索引擎·全文检索
Gerardisite10 小时前
企微批量群发消息指南:用 QiWe 省掉人工操作
java·python·机器人·企业微信
青山师12 小时前
动态代理深度解析:JDK与CGLIB底层实现与实战
java·设计模式·面试·动态代理·java面试·cglib