数组拷贝是java框架高性能基础设施,spring beanutils、mybatis批量插入、guava/arrayutils工具类、netty缓冲区等均依赖system.arraycopy实现零分配、低gc、安全切片与高效同步。

数组拷贝在框架源码中不是“可有可无”的辅助操作,而是支撑高性能、安全性和语义正确性的基础设施。它常出现在序列化、缓存更新、参数校验、集合扩容、对象克隆等关键路径中。下面从主流 Java 框架出发,结合真实源码逻辑,说明几种典型应用。
Spring BeanUtils 的属性拷贝底层依赖 arraycopy
Spring 的 BeanUtils.copyProperties() 表面是对象属性复制,但当处理数组类型字段(如 String[] roles)时,内部会委托到 org.springframework.util.ClassUtils 或直接调用 System.arraycopy 进行浅拷贝。例如:
- 若源对象字段为
int[] data = {1,2,3},目标对象同名字段为int[]类型,Spring 不新建数组,而是用arraycopy复制元素; - 这种设计避免了反射循环赋值的开销,也规避了对基本类型数组做
clone()的额外对象创建; - 注意:它不处理嵌套数组或引用类型数组的深拷贝——这是有意为之的设计取舍,保持轻量和确定性。
MyBatis 批量插入时的参数数组切片
MyBatis 在执行 <foreach></foreach> 批量插入时,若 SQL 参数超长(如单次插入 5000 条),驱动或数据库可能拒绝。框架内部会调用 System.arraycopy 对参数集合做分片:
- 将原始
List<user></user>转为数组后,按每 1000 条切一块; - 每次切片都通过
arraycopy(src, start, dest, 0, length)提取子数组,而非新建ArrayList.subList()(后者是视图,仍持原始引用); - 这样确保每个批次参数独立,避免多线程下修改干扰,也防止 GC 时因长引用链延迟回收。
Guava 和 Apache Commons 的工具类封装
Guava 的 ObjectArrays.concat() 和 Commons Lang 的 ArrayUtils.addAll() 都基于 System.arraycopy 实现:
- 例如
ArrayUtils.addAll(new String[]{"a"}, "b", "c")内部先计算总长度,new 一个新数组,再用两次arraycopy分别拷贝原数组和可变参数; - 相比手动 for 循环,它省去边界判断和索引管理,且 JVM 对 native
arraycopy有深度优化(如内存对齐、SIMD 指令); - 这类工具方法被 Spring、Hibernate 等大量间接调用——比如 Hibernate 初始化代理对象的字段快照时,就复用 Commons 的数组合并逻辑。
Netty 缓冲区写入与数组切片
Netty 的 ByteBuf 在堆内内存模式下,writeBytes(byte[] src) 方法内部不直接复制整个数组,而是:
- 检查剩余可写空间是否足够;
- 若够,调用
System.arraycopy(src, srcIndex, memoryArray, writerIndex, length)直接落盘; - 若不够,触发扩容并再次 arraycopy ——整个过程零对象分配、无中间包装,保障 IO 路径极致性能;
- 这个模式也被 Kafka Producer、Dubbo 序列化模块借鉴,用于快速填充字节数组缓冲区。











