跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

Java ArrayList 底层原理与核心方法手写实现

Java ArrayList 基于动态数组实现,掌握其底层逻辑对优化性能至关重要。通过手写实现核心类,演示了数组初始化、自动扩容(grow)、元素插入(add)、查找(indexOf)、修改(set)及删除(remove)的具体流程。内容涵盖边界校验、内存移动策略及异常处理机制,帮助开发者从源码层面理解集合框架的设计思想与潜在风险。

Ne0发布于 2026/3/29更新于 2026/10/2296 浏览
Java ArrayList 底层原理与核心方法手写实现

Java ArrayList 底层原理与核心方法手写实现

ArrayList 是 Java 集合框架中 List 接口的动态数组实现,它提供了便捷的增删查改操作。通过手写实现其核心逻辑,我们可以更透彻地理解顺序表在内存中的存储方式、扩容机制以及边界处理策略。

类结构定义

实现的核心在于维护一个内部数组和一个记录有效元素个数的变量。默认容量通常设为 10,当数据量超过当前容量时触发扩容。

import java.util.Arrays;

public class MyArrayList {
    private int[] arr;      // 存储数据的数组
    private int usedSize;   // 有效数据个数
    public static final int DEFAULT_CAPACITY = 10; // 默认容量

    public MyArrayList() {
        this.arr = new int[DEFAULT_CAPACITY];
        this.usedSize = 0;
    }
}

核心方法实现

1. 添加元素(末尾)

向列表末尾添加元素前,必须检查数组是否已满。如果 usedSize 等于数组长度,说明空间不足,需要调用扩容方法。

public void add(int data) {
    if (isFull()) {
        grow();
    }
    this.arr[this.usedSize] = data;
    this.usedSize++;
}

private boolean isFull() {
    return this.usedSize == this.arr.length;
}

// 扩容策略:通常为原容量的 2 倍
private void grow() {
    this.arr = Arrays.copyOf(this.arr, 2 * this.arr.length);
}

这里采用 2 倍扩容是为了平衡内存占用和频繁扩容带来的性能损耗。虽然会牺牲一定空间,但能减少数组复制的次数。

2. 指定位置插入

在指定位置插入元素时,除了检查容量,还需要验证索引合法性。如果插入位置在中间,需要将后续元素整体向后移动一位,腾出空位。

public void add(int pos, int data) {
    if (isFull()) {
        grow();
    }
    checkPos(pos, "add 方法执行的时候 pos 位置不合法");

    if (pos == usedSize) {
        arr[pos] = data;
        usedSize++;
        return;
    }

    for (int i = usedSize - 1; i >= pos; i--) {
        arr[i + 1] = arr[i];
    }
    arr[pos] = data;
    usedSize++;
}

private void checkPos(int pos, String msg) {
    if (pos < 0 || pos > usedSize) {
        throw new PosIllegalityException(msg);
    }
}

注意循环的方向,必须从后向前移动,否则前面的数据会被覆盖导致丢失。

3. 查找与判断

判断是否包含某个元素或获取元素下标,本质上都是线性遍历。对于基本数据类型,直接比较值即可;如果是对象引用,则需使用 equals 方法。

public boolean contains(int toFind) {
    for (int i = 0; i < this.usedSize; i++) {
        if (arr[i] == toFind) {
            return true;
        }
    }
    return false;
}

public int indexOf(int toFind) {
    for (int i = 0; i < this.usedSize; i++) {
        if (arr[i] == toFind) {
            return i;
        }
    }
    return -1;
}

4. 获取与修改

获取和修改操作都需要严格的边界校验。访问空列表或越界索引都会抛出异常,这是保证程序健壮性的关键。

public int get(int pos) {
    if (isEmpty()) {
        throw new EmptyListException("当前顺序表为空");
    }
    checkPos(pos, "get 方法的 pos 位置不合法");
    return arr[pos];
}

public void set(int pos, int value) {
    if (isEmpty()) {
        throw new EmptyListException("当前顺序表为空");
    }
    checkPos(pos, "set 方法执行的时候 pos 位置不合法" + pos);
    arr[pos] = value;
}

private boolean isEmpty() {
    return usedSize == 0;
}

5. 删除元素

删除指定值的元素时,先找到其索引。若存在,则将后续元素向前覆盖,最后将有效长度减一。对于引用类型,建议将最后一个元素置为 null 以便 GC 回收。

public void remove(int toRemove) {
    if (isEmpty()) {
        throw new EmptyListException("当前顺序表为空");
    }
    int index = indexOf(toRemove);
    if (index == -1) {
        System.out.println("没有你要删除的数据");
        return;
    }
    for (int i = index; i < usedSize - 1; i++) {
        arr[i] = arr[i + 1];
    }
    usedSize--;
    // arr[usedSize] = null; // 引用类型建议手动置空
}

6. 工具方法

获取当前大小和清空列表相对简单,主要是重置计数器和清理数据。

public int size() {
    return this.usedSize;
}

public void clear() {
    for (int i = 0; i < this.usedSize; i++) {
        arr[i] = 0;
    }
    usedSize = 0;
}

总结

通过上述手写过程,我们不仅复现了 ArrayList 的基础功能,更理解了动态数组背后的设计权衡。无论是扩容时的内存分配,还是插入删除时的数据搬运,都直接影响着程序的运行效率。在实际开发中,了解这些底层细节有助于我们在面对大数据量场景时做出更合理的选择。

目录

  1. Java ArrayList 底层原理与核心方法手写实现
  2. 类结构定义
  3. 核心方法实现
  4. 1. 添加元素(末尾)
  5. 2. 指定位置插入
  6. 3. 查找与判断
  7. 4. 获取与修改
  8. 5. 删除元素
  9. 6. 工具方法
  10. 总结

更多推荐文章

查看全部
  • SQL Server 2019 安装与配置实战指南
  • RAG 检索增强生成:现状、挑战与优化思路
  • 通义万相 2.1 文生图技术特性与异构算力部署解析
  • Java 开发环境优化:Maven 镜像与 Spring 脚手架配置
  • VSCode 本地部署 DeepSeek,打造私人 AI 编程助手
  • C++ 核心数据结构:Stack 与 Queue 类深度解析
  • Ollama v0.17.0 发布:OpenClaw 自动化集成、VRAM 动态上下文与 Tokenizer 优化
  • 基于 Django 框架搭建 WebAPI 项目实战
  • 龙年 AI 生成封面图片玩法与变现指南
  • 近端策略优化算法 PPO 详解与代码实现
  • Ollama 本地 CPU 部署开源大模型教程
  • AI Agent 架构深度解析:从原理到应用
  • ToClaw 与 OpenClaw:AI 数字助理的功能定位对比
  • 二分算法实战:A-B 数对与高考志愿匹配
  • 2025 年 12 月 C++ 一级真题解析:电子学会编程等级考试
  • OpenClaw 开源 AI 助手:功能特性与云端部署指南
  • Windows 三种网络类型详解及 eNSP 实验防火墙配置方案
  • JavaScript 核心语法与常用 API 速查
  • 全球人工智能行业报告:AI 重塑千行百业
  • MySQL 核心机制与性能优化实战总结

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online