Arrays.copyOf 以 newLength 为准创建新数组,不自动修正长度:newLength > 原长则填充默认值,= 则等长拷贝,< 则截断,< 0 直接抛 NegativeArraySizeException;底层用 Math.min 防越界,并提前校验 null。

Arrays.copyOf 是 Java 中最常用的数组拷贝工具之一,它看似简单,但内部实现细节和边界处理稍有不慎就容易引发 ArrayIndexOutOfBoundsException 或静默截断/填充问题。它的核心不是直接调用 System.arraycopy 就完事,而是有一套明确的长度校验、类型推导与新数组构造逻辑。
copyOf 如何决定新数组长度与类型
该方法本质是泛型桥接方法,最终委托给 Object[] 版本或基本类型专用重载(如 copyOf(int[], int))。关键点在于:它严格以第二个参数 newLength 为准创建新数组,不参考原数组长度做自动修正。
- 若
newLength > original.length:新数组扩容,多出位置用默认值填充(null、0、false等) - 若
newLength == original.length:等长拷贝,等价于深拷贝(仅一层引用) - 若
0 <= newLength < original.length:截断拷贝,只复制前newLength个元素 - 若
newLength < 0:直接抛NegativeArraySizeException(在分配新数组前就失败)
底层调用 System.arraycopy 的安全边界
copyOf 在完成新数组创建后,会调用 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength))。注意这个 Math.min —— 它是防止越界的真正守门员。
- 即使你传入
newLength = 1000但原数组只有 5 个元素,也只会拷贝 5 个,不会越界 - 如果原数组为
null,copyOf会立即抛NullPointerException(不等到arraycopy阶段) -
System.arraycopy本身不校验源数组是否为空,但copyOf提前做了防御性检查
实战中容易踩的坑与规避方式
日常开发中,开发者常把 copyOf 当作“安全版 arraycopy”,却忽略其行为隐含语义:
立即学习“Java免费学习笔记(深入)”;
-
不要依赖原数组长度做逻辑判断后再调用 copyOf:比如先写
if (arr.length > 10) doX();,再Arrays.copyOf(arr, 10)——若arr为空,doX()不执行,但copyOf仍会返回长度为 10 的全零数组,可能破坏后续流程 -
泛型数组拷贝需注意类型擦除限制:对
List<String>[]这类嵌套泛型数组,copyOf返回的是Object[],强转可能触发ClassCastException -
大数据量场景慎用无脑扩容:如循环中反复
copyOf(arr, arr.length + 1)模拟动态数组,时间复杂度退化为 O(n²),应改用ArrayList
替代方案与何时该换用其他机制
当需求超出 copyOf 的能力边界时,可考虑:
- 需要浅拷贝+过滤:用
Stream.of(arr).filter(...).toArray() - 需要深拷贝对象数组:手动遍历并调用
clone()或序列化工具 - 需要偏移拷贝(非从 0 开始):直接用
System.arraycopy(original, fromIndex, copy, 0, length) - 需要不可变视图:用
Arrays.asList(arr).unmodifiableList()(注意底层数组仍可变)
newLength 是唯一长度指令、原数组只提供数据源,就能避开绝大多数误用。


















