上一篇
java怎么定义动态数组
- 后端开发
- 2025-08-06
- 5
在 Java 中可通过
ArrayList
实现动态数组,需导入
java.util.ArrayList
,`List list = new
在 Java 中,传统意义上的“原生数组”(如 int[] arr = new int[5];
)一旦创建,其长度便不可更改,若需实现类似“动态数组”的功能(即可根据需求自动扩展或收缩的数组),主要有以下几种核心方案及最佳实践:
一、最主流方案:使用 java.util.ArrayList
(推荐)
ArrayList
是 Java 集合框架提供的 动态数组实现类,底层基于原生数组,但封装了自动扩容逻辑,并提供丰富的 API。
关键特性与操作详解
操作 | 描述 | 示例代码 | 备注 |
---|---|---|---|
创建空列表 | 新建一个无初始容量的动态数组 | 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(); |
若需特定类型需强制转换 |
️ 注意事项
- 类型安全:必须指定泛型类型(如
ArrayList<String>
),否则需显式类型转换。 - 失败快速:尝试访问不存在的索引会直接抛出异常,建议先用
size()
判断。 - 内存效率:频繁增删可能导致多次扩容/缩容,可预估初始容量优化性能。
示例完整代码
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
,可通过以下方式模拟动态数组的行为:
核心思路
- 维护内部缓冲区:使用原生数组存储数据。
- 跟踪有效长度:单独变量记录当前元素数量。
- 自动扩容策略:当空间不足时,创建更大的新数组并复制旧数据。
简易实现示例
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[]
,无法直接转为基本类型