深入理解ArrayList:从Java原生实现到手写一个ArrayList

Java原生ArrayList解析

基本结构

Java的ArrayList是基于数组实现的动态列表,主要特点包括:

  1. 动态扩容:当元素数量超过当前容量时,自动扩容(通常增加50%)

  2. 快速随机访问:通过索引访问元素的时间复杂度为O(1)

  3. 有序集合:保持元素的插入顺序

核心实现机制

java 复制代码
// JDK中的关键字段
transient Object[] elementData; // 存储元素的数组缓冲区
private int size; // 列表中实际元素数量
private static final int DEFAULT_CAPACITY = 10; // 默认初始容量

扩容机制

java 复制代码
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    elementData = Arrays.copyOf(elementData, newCapacity);
}

时间复杂度分析

  • 访问元素:O(1)

  • 添加元素(尾部):平均O(1),最坏O(n)(需要扩容)

  • 插入/删除元素(非尾部):O(n)(需要移动元素)

自定义MyArrayList实现

java 复制代码
package com.zsy;

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;

/**
 * 自定义动态数组实现,支持泛型元素存储和基本列表操作
 *
 * <p>本实现提供类似Java ArrayList的核心功能,包括:</p>
 * <ul>
 *   <li>动态扩容机制(默认初始容量10,按2倍扩容)</li>
 *   <li>支持索引访问和修改</li>
 *   <li>提供元素遍历功能</li>
 *   <li>实现基本的增删改查操作</li>
 * </ul>
 *
 * <p><b>特性说明:</b></p>
 * <ul>
 *   <li>时间复杂度:随机访问O(1),插入/删除平均O(n)</li>
 *   <li>空间复杂度:O(n)</li>
 *   <li><b>非线程安全</b> - 多线程环境下需要外部同步</li>
 * </ul>
 *
 * @param <E> 列表元素类型
 * @author zsy
 * @see List
 */
public class MyArrayList<E> implements List<E> {

    /**
     * 当前列表中实际存储的元素数量
     */
    private int size;

    /**
     * 列表当前分配的存储容量
     */
    private int capacity;

    /**
     * 存储列表元素的数组缓冲区
     */
    private Object[] elements;

    /**
     * 构造一个初始容量为10的空列表
     */
    public MyArrayList() {
        this(10);
    }

    /**
     * 构造具有指定初始容量的空列表
     *
     * @param initialCapacity 初始容量
     * @throws IllegalArgumentException 如果初始容量为负数
     */
    public MyArrayList(int initialCapacity) {
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        }
        this.capacity = initialCapacity;
        this.elements = new Object[initialCapacity];
    }

    /**
     * 将指定元素追加到列表末尾
     *
     * @param element 要添加的元素
     */
    @Override
    public void add(E element) {
        ensureCapacity();
        elements[size++] = element;
    }

    /**
     * 在列表的指定位置插入指定元素
     *
     * @param element 要插入的元素
     * @param index 插入位置的索引
     * @throws IndexOutOfBoundsException 如果索引超出范围
     */
    @Override
    public void add(E element, int index) {
        rangeCheckForAdd(index);
        ensureCapacity();
        System.arraycopy(elements, index, elements, index + 1, size - index);
        elements[index] = element;
        size++;
    }

    /**
     * 移除并返回列表中指定位置的元素
     *
     * @param index 要移除元素的索引
     * @return 被移除的元素
     * @throws IndexOutOfBoundsException 如果索引超出范围
     */
    @Override
    public E remove(int index) {
        rangeCheck(index);
        E oldValue = elementData(index);
        int numMoved = size - index - 1;
        if (numMoved > 0) {
            System.arraycopy(elements, index + 1, elements, index, numMoved);
        }
        elements[--size] = null; // 清除引用,帮助GC
        return oldValue;
    }

    /**
     * 从列表中移除首次出现的指定元素
     *
     * @param element 要移除的元素
     * @return 如果列表包含该元素则返回true
     */
    @Override
    public boolean remove(E element) {
        for (int i = 0; i < size; i++) {
            if (Objects.equals(element, elements[i])) {
                remove(i);
                return true;
            }
        }
        return false;
    }

    /**
     * 替换列表中指定位置的元素
     *
     * @param index 要替换元素的索引
     * @param element 要存储的元素
     * @return 先前在指定位置的元素
     * @throws IndexOutOfBoundsException 如果索引超出范围
     */
    @Override
    public E set(int index, E element) {
        rangeCheck(index);
        E oldValue = elementData(index);
        elements[index] = element;
        return oldValue;
    }

    /**
     * 返回列表中指定位置的元素
     *
     * @param index 要返回元素的索引
     * @return 列表中指定位置的元素
     * @throws IndexOutOfBoundsException 如果索引超出范围
     */
    @Override
    public E get(int index) {
        rangeCheck(index);
        return elementData(index);
    }

    /**
     * 返回列表中的元素数量
     *
     * @return 列表中的元素数量
     */
    @Override
    public int size() {
        return size;
    }

    /**
     * 返回此列表中元素的迭代器
     *
     * @return 按适当顺序包含此列表中所有元素的迭代器
     */
    @Override
    public Iterator<E> iterator() {
        return new ArrayListIterator();
    }

    // ========== 私有辅助方法 ==========

    /**
     * 确保列表有足够的容量容纳新元素
     */
    private void ensureCapacity() {
        if (size == capacity) {
            resize();
        }
    }

    /**
     * 扩容列表存储容量
     */
    private void resize() {
        int newCapacity = capacity * 2;
        Object[] newElements = new Object[newCapacity];
        System.arraycopy(elements, 0, newElements, 0, size);
        elements = newElements;
        capacity = newCapacity;
    }

    /**
     * 检查索引是否在有效范围内
     */
    private void rangeCheck(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

    /**
     * 检查添加操作的索引是否在有效范围内
     */
    private void rangeCheckForAdd(int index) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

    /**
     * 构造索引越界异常信息
     */
    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size;
    }

    /**
     * 获取指定位置的元素(带类型转换)
     */
    @SuppressWarnings("unchecked")
    private E elementData(int index) {
        return (E) elements[index];
    }

    // ========== 内部迭代器实现 ==========

    /**
     * 列表迭代器实现
     */
    private class ArrayListIterator implements Iterator<E> {
        /**
         * 当前迭代位置
         */
        private int cursor;

        /**
         * 检查是否还有更多元素可迭代
         *
         * @return 如果迭代有更多元素则返回true
         */
        @Override
        public boolean hasNext() {
            return cursor != size;
        }

        /**
         * 返回迭代中的下一个元素
         *
         * @return 迭代中的下一个元素
         * @throws NoSuchElementException 如果迭代没有更多元素
         */
        @Override
        public E next() {
            if (cursor >= size) {
                throw new NoSuchElementException();
            }
            return elementData(cursor++);
        }
    }
}
相关推荐
想会飞的蒲公英33 分钟前
计算机怎样读取中文文本:编码、清洗与标准化
人工智能·python·自然语言处理
腻害兔1 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
SeaTunnel1 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
深度研习笔记1 小时前
OpenCV工业视觉实战09|项目EXE打包+工控机无环境部署+后台常驻运行,彻底脱离Python环境,完成项目最终交付
python·opencv·webpack
碎光拾影2 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
CCPC不拿奖不改名2 小时前
大模型推理架构与开源生态知识整理
数据库·windows·python·架构·langchain·开源·github
奋发向前wcx2 小时前
y1,y2总复习笔记5 2026.7.19
数据结构·笔记·算法
Marst Code2 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
databook2 小时前
当散点图不够用时:用 t-SNE 可视化多维数据
python·数据分析·数据可视化
Miao121313 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言