当前位置:首页 > 后端开发 > 正文

java怎么定义动态数组

在 Java 中可通过 ArrayList 实现动态数组,需导入 java.util.ArrayList,`List list = new

在 Java 中,传统意义上的“原生数组”(如 int[] arr = new int[5];)一旦创建,其长度便不可更改,若需实现类似“动态数组”的功能(即可根据需求自动扩展或收缩的数组),主要有以下几种核心方案及最佳实践:


一、最主流方案:使用 java.util.ArrayList(推荐)

ArrayList 是 Java 集合框架提供的 动态数组实现类,底层基于原生数组,但封装了自动扩容逻辑,并提供丰富的 API。

java怎么定义动态数组  第1张

关键特性与操作详解

操作 描述 示例代码 备注
创建空列表 新建一个无初始容量的动态数组 List<Integer> list = new ArrayList<>(); 默认初始容量约10,满后自动扩容至1.5倍
指定初始容量 预分配足够空间减少后续扩容次数 new ArrayList<>(20); 适合已知大致数据量的场景
添加元素 向列表末尾追加元素 list.add(42); 时间复杂度 O(1)(均摊)
插入元素 在指定位置插入元素 list.add(1, "Hello"); 后续元素后移,时间复杂度 O(n)
获取元素 根据索引获取元素 Integer num = list.get(0); 索引从0开始,越界抛 IndexOutOfBoundsException
修改元素 更新指定位置的元素 list.set(2, 99); 原位置元素被覆盖
删除元素 移除指定位置或对象的第一个匹配项 list.remove(0); / list.remove("A"); 时间复杂度 O(n)
清空列表 保留容器,清除所有元素 list.clear(); 不等于重新创建新列表
获取大小 返回当前元素个数 int size = list.size(); 区别于原生数组的 length 属性
转换为数组 将列表转为原生数组 Object[] arr = list.toArray(); 若需特定类型需强制转换

️ 注意事项

  1. 类型安全:必须指定泛型类型(如 ArrayList<String>),否则需显式类型转换。
  2. 失败快速:尝试访问不存在的索引会直接抛出异常,建议先用 size() 判断。
  3. 内存效率:频繁增删可能导致多次扩容/缩容,可预估初始容量优化性能。

示例完整代码

import java.util.ArrayList;
import java.util.List;
public class DynamicArrayExample {
    public static void main(String[] args) {
        // 创建初始容量为5的整型动态数组
        List<Integer> dynamicArray = new ArrayList<>(5);
        // 添加元素(自动扩容)
        dynamicArray.add(10); // [10]
        dynamicArray.add(20); // [10, 20]
        dynamicArray.add(30); // [10, 20, 30]
        // 插入元素到索引1的位置
        dynamicArray.add(1, 15); // [10, 15, 20, 30]
        // 修改索引2的元素
        dynamicArray.set(2, 25); // [10, 15, 25, 30]
        // 删除索引1的元素
        dynamicArray.remove(1); // [10, 25, 30]
        // 遍历打印所有元素
        for (Integer num : dynamicArray) {
            System.out.println(num); // 输出:10, 25, 30
        }
        // 转换为原生数组
        Integer[] nativeArray = dynamicArray.toArray(new Integer[0]);
        System.out.println("原生数组长度:" + nativeArray.length); // 输出:3
    }
}

️ 二、手动模拟动态数组(学习目的)

若不使用 ArrayList,可通过以下方式模拟动态数组的行为:

核心思路

  1. 维护内部缓冲区:使用原生数组存储数据。
  2. 跟踪有效长度:单独变量记录当前元素数量。
  3. 自动扩容策略:当空间不足时,创建更大的新数组并复制旧数据。

简易实现示例

public class ManualDynamicArray {
    private int[] data;      // 内部存储数组
    private int size;       // 当前元素个数
    private static final int DEFAULT_CAPACITY = 10;
    public ManualDynamicArray() {
        data = new int[DEFAULT_CAPACITY];
        size = 0;
    }
    // 添加元素(核心方法)
    public void add(int element) {
        if (size == data.length) {
            // 扩容:创建新数组(容量翻倍)
            int newCapacity = data.length  2;
            int[] newData = new int[newCapacity];
            System.arraycopy(data, 0, newData, 0, data.length);
            data = newData;
        }
        data[size++] = element;
    }
    // 获取元素
    public int get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("索引越界");
        }
        return data[index];
    }
    // 获取当前元素个数
    public int size() {
        return size;
    }
}

️ 局限性说明

  • 此实现仅包含基础功能,缺少 ArrayList 的完整特性(如中间插入、删除、迭代器等)。
  • 实际开发中强烈建议直接使用 ArrayList,此处仅为演示原理。

️ 三、与其他结构的对比选择

结构 动态数组能力 随机访问速度 插入/删除效率 适用场景
ArrayList O(1) O(n) 频繁读操作,少量写
LinkedList O(n) O(1) 频繁插入/删除
HashSet/TreeSet N/A O(1)/O(log n) 无序/有序唯一性存储
Vector O(1) O(n) 老旧类,已被 ArrayList 取代

四、常见问题解答(FAQs)

Q1: ArrayList 的初始容量设置多大合适?

A: 根据业务场景预估,若已知数据量接近某个数值(如1000),可直接设置初始容量为该值以避免多次扩容,若不确定,使用默认构造函数即可,Java会自动处理扩容,盲目设置过大容量会浪费内存。

Q2: 如何将 ArrayList 转换为基本类型数组?(如 int[]

A: 由于泛型擦除机制,需借助流式API或循环手动转换:

// 方法1:使用流(Java 8+)
List<Integer> list = Arrays.asList(1, 2, 3);
int[] primitiveArray = list.stream().mapToInt(Integer::intValue).toArray();
// 方法2:循环转换
int[] arr = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
    arr[i] = list.get(i);
}

注意:直接调用 toArray() 返回的是 Object[],无法直接转为基本类型

0