Java 数组本身是定长结构,创建之后长度固定,原生没有提供 delete 删除方法,所以 java 数组删除指定位置元素不能直接原地把元素抹除,标准做法是新建一个长度减一的新数组,把删除位置前面元素原样复制,删除位置后面所有元素向前移动一位,最后把新数组赋值给原数组引用,这个是 Java 基础非常经典的考点,很多新手会误以为数组可以像 ArrayList 一样直接 remove,混淆定长数组和动态集合的区别,数组删除指定位置元素核心难点是下标边界判断,如果传入的下标小于 0 或者大于等于数组长度,必须做异常判断,否则会出现数组下标越界异常,同时还要考虑空数组 只有一个元素的特殊场景,实现方式可以手写循环移动,也可以使用 System.arraycopy 系统原生方法,System.arraycopy 性能优于普通 for 循环,底层是 native 本地方法,大批量元素移动的时候效率更高,理解这个原理之后,也能明白 ArrayList 底层 remove 方法本质也是同样的元素移位逻辑,只是 ArrayList 封装好了,不需要开发者手动新建数组。
核心实现思路
第一步校验目标下标,判断 index 是否合法,下标范围必须是 0 到原数组长度减一。第二步创建新数组,新数组长度等于原数组长度减一。第三步复制删除下标之前的元素到新数组。第四步把删除下标之后的元素,整体向前平移一位写入新数组。第五步将新数组引用赋值给原来数组变量,完成删除操作。
两种实现方式对比
| 实现方式 | 特点 | 优点 | 缺点 |
|---|---|---|---|
| for 循环手动移位 | 纯 Java 代码,逻辑直观 | 容易理解,适合学习原理 | 元素数量大的时候性能偏低 |
| System.arraycopy | JDK 原生拷贝方法 | 底层 native 实现,拷贝速度快 | 需要理解参数含义,新手不容易看懂 |
示例代码 手写 for 循环版本
public class ArrayDeleteDemo {
public static int[] deleteByIndex(int[] arr, int index) {
if (arr == null || arr.length == 0) {
throw new IllegalArgumentException("数组为空,无法执行删除");
}
if (index < 0 || index >= arr.length) {
throw new ArrayIndexOutOfBoundsException("指定位置下标非法");
}
int[] newArr = new int[arr.length - 1];
for (int i = 0; i < newArr.length; i++) {
if (i < index) {
newArr[i] = arr[i];
} else {
newArr[i] = arr[i + 1];
}
}
return newArr;
}
}
示例代码 System.arraycopy 版本
public class ArrayDeleteDemo2 {
public static int[] deleteByIndex(int[] arr, int index) {
if (arr == null || arr.length == 0) {
throw new IllegalArgumentException("数组为空,无法执行删除");
}
if (index < 0 || index >= arr.length) {
throw new ArrayIndexOutOfBoundsException("指定位置下标非法");
}
int[] newArr = new int[arr.length - 1];
System.arraycopy(arr, 0, newArr, 0, index);
System.arraycopy(arr, index + 1, newArr, index, arr.length - index - 1);
return newArr;
}
}
System.arraycopy 参数含义,源数组,源数组起始下标,目标数组,目标数组起始下标,拷贝元素个数,第一段拷贝删除位置前面元素,第二段拷贝删除位置后面全部元素向前平移。
扩展说明 引用类型数组
上面示例是 int 基本数据类型数组,如果是 String 自定义对象这类引用类型数组,删除指定位置元素逻辑完全一致,同样是新建数组,元素向前移位,只是数组里面保存的是对象引用,移位只是复制引用地址,不会销毁对象本身,对象是否回收由 GC 决定。
重要注意事项
第一 原数组对象本身没有被修改,只是引用指向了新数组,旧数组如果没有其他引用,会被垃圾回收。第二 如果业务频繁需要删除指定位置元素,不推荐使用原生数组,应该改用 ArrayList,ArrayList 底层已经封装移位逻辑,动态扩容,代码更简洁。第三 删除之后数组长度减少一位,后面所有元素下标全部前移,后续遍历要注意新下标变化。第四 如果数组只有一个元素,删除之后新数组长度为 0,属于合法空数组,代码需要兼容这个场景。
总结,java 数组删除指定位置元素本质就是新建短一位数组加元素前移,因为数组定长这个底层特性,无法原地缩减长度,面试经常考察这个知识点,同时要区分数组和 ArrayList 的 remove 底层实现原理,日常开发频繁增删优先使用集合类,原生数组适合固定长度数据存储。
【常见问题】
问题 1 java 数组删除指定位置元素为什么不能直接原地删除
回答 1 java 数组删除指定位置元素,因为 Java 数组创建之后长度固定,不支持动态缩短,所以 java 数组删除指定位置元素只能新建长度减一的新数组,完成元素前移,不能直接原地删除元素。
问题 2 java 数组删除指定位置元素 System.arraycopy 和 for 循环哪个更快
回答 1 java 数组删除指定位置元素,System.arraycopy 底层是 native 本地方法,性能优于普通 for 循环,java 数组删除指定位置元素在大数据量场景优先使用 System.arraycopy 实现移位拷贝。
问题 3 java 数组删除指定位置元素和 ArrayList remove 底层一样吗
回答 3 java 数组删除指定位置元素核心是元素向前移位,ArrayList 的 remove 指定下标底层原理和 java 数组删除指定位置元素逻辑相同,只是 ArrayList 已经封装好移位操作,并且支持动态扩容。
问题 4 java 数组删除指定位置元素如果下标越界会怎么样
回答 4 java 数组删除指定位置元素的时候,如果传入下标小于 0 或者大于等于数组长度,会触发数组下标越界异常,所以 java 数组删除指定位置元素代码必须提前做下标合法性校验。
【免责申明】
本文介绍的 java 数组删除指定位置元素相关内容仅作为 Java 基础学习参考,代码示例为教学演示,生产业务代码需要结合异常处理 业务校验完善,本文不构成强制编码规范。


