arrays.copyofrange是长数组截取最直接安全的选择,其底层调用jvm优化的system.arraycopy,满足拷贝长度≥16、类型一致、索引合法时性能接近最优;但高频调用、伪深拷贝、越界试探易引发gc压力或异常,应依场景切换为预分配buffer、sublist或bytebuffer.slice等方案。

Arrays.copyOfRange 是处理长数组截取最直接、安全且语义清晰的选择,它不追求“绝对最快”,而是在可读性、安全性与性能之间取得平衡。对长数组而言,关键不是避免使用它,而是理解它何时高效、何时该让位给更底层的方案。
为什么 copyOfRange 对长数组依然可靠
它底层调用 System.arraycopy,属于 JVM 高度优化的 native 方法,对大块内存搬运有 SIMD 指令支持。只要满足以下条件,其性能就接近最优:
- 拷贝长度 ≥ 16(实测临界点,小于此值时 JNI 开销占比上升)
- 源数组与目标类型一致(如 int[] → int[]),无隐式装箱或类型转换
- 索引范围合法(
0 ≤ from ≤ to ≤ original.length),避免运行时校验开销
长数组场景下的性能避坑点
真正拖慢长数组处理的,常是误用方式而非方法本身:
- 在高频循环中反复调用
copyOfRange:每次都会新建数组对象,触发 GC 压力。若需多次切片(如分页读取大数据流),应预分配一个复用缓冲区,改用System.arraycopy - 用它做“伪深拷贝”:对
String[]或MyObj[]调用copyOfRange,只复制引用,不复制对象内容。若后续修改原对象影响业务逻辑,需额外处理,而非指望该方法解决 - 越界试探式写法:如
copyOfRange(arr, start, start + pageSize)未校验start + pageSize ≤ arr.length,会导致ArrayIndexOutOfBoundsException,长数组下异常捕获成本更高
什么情况下该换其他方案
当明确知道数据特征或控制粒度要求更高时,主动切换更合适:
- 需要固定长度多次切片(如网络帧解析):直接复用已分配的
byte[] buffer,配合System.arraycopy(src, offset, buffer, 0, len),省去对象创建开销 - 只读遍历某段、无需新数组:用
Arrays.asList(arr).subList(from, to)(注意仅适用于对象数组)或自定义视图封装,实现零拷贝访问 - 原始数据来自文件或堆外内存:考虑
ByteBuffer.slice()或MappedByteBuffer,避免将整块长数组载入堆内
实用建议:一行代码背后的权衡
写 int[] slice = Arrays.copyOfRange(data, 100000, 100100); 很简单,但它隐含一次 100 元素的新数组分配。如果这是日志采样中的常规操作,累计起来就是可观的 GC 活动。更好的做法是:
- 确认是否真需要“新数组”——能否复用、能否延迟拷贝、能否只传索引范围?
- 对超长数组(千万级+),优先用
System.arraycopy+ 预分配目标数组,尤其在吞吐敏感服务中 - 搭配 JFR 或 VisualVM 观察实际分配速率,而不是凭经验判断“应该够快”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











