克隆创建新数组对象,地址不同、内存独立,基本类型数组完全隔离,但对象数组仅浅拷贝引用;四种方式中arraycopy最快,clone语义直观但慢,for循环适合小数组且可转换;浅拷贝不复制对象实例,需深拷贝时应评估必要性;克隆时机比方式更重要,避免不当暴露或高频克隆大数组。

克隆不是复制引用,而是创建新数组对象
Java 中的数组是对象,调用 clone() 得到的是一个全新的数组实例,地址不同、内存独立。原始数组和克隆数组互不影响——改新数组的元素,原数组不会变;反之亦然。这点对基本类型数组(如 int[]、double[])完全成立。但要注意:它只保证“数组容器”独立,不保证“容器里的对象”也独立。
四种常用克隆方式,性能和语义各不相同
选错方式会拖慢程序或埋下隐患:
- System.arraycopy():JVM 级优化,最快,适合中大型数组(数千元素起)。需手动 new 目标数组,类型和长度必须匹配。
- Arrays.copyOf():内部调用 arraycopy,但多了长度计算和新数组分配,比前者慢 10–20%。优势是写法简洁,支持自动扩容或截断。
- clone():语义最直观,“一行搞定”,但实测速度仅为 arraycopy 的 1/9–1/10;对象数组仍是浅拷贝,容易误以为已隔离。
- for 循环:小数组(≤4 元素)可能略快,但随长度增长性能快速下降;唯一能边复制边转换(如过滤、映射、类型转换)的方式。
浅拷贝对对象数组意味着共享对象实例
基本类型数组克隆后彻底独立,没问题。但 String[]、Person[] 这类对象数组,clone() 或 arraycopy 只复制引用,不复制引用指向的对象本身:
- 修改 cloned[0].name,original[0].name 也会变;
- 这不是 bug,是浅拷贝的定义决定的;
- 真需要隔离,得走深拷贝路径:手写递归 clone、JSON 序列化反序列化、或用 ObjectOutputStream + ObjectInputStream;
- 这些操作代价远高于数组复制本身,应先评估是否真有必要——多数场景用不可变对象(如 String、LocalDateTime)或防御性复制字段更轻量。
克隆时机比方式更重要
克隆本身不耗资源,但错在不该克隆时克隆,或克隆了不该暴露的数组:
- 返回私有数组字段时直接 return array,外部可修改内部状态——应克隆后再返回;
- 多线程间传递数组,若只读可共享;若某线程要修改,必须克隆一份再操作;
- 高频调用方法中反复克隆大数组,可能引发频繁 GC 和内存压力;
- 考虑替代方案:用不可变包装(如 Collections.unmodifiableList)、或设计为接收副本而非自行克隆。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











