Java中的克隆clone以及对数组的复制

本文详细解析了浅克隆与深克隆的区别,并通过Java数组复制的例子具体说明了这两种克隆方式的不同表现,特别关注一维和二维数组的复制过程及技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、浅克隆和深克隆

    1. 浅克隆(shadow clone)

    只需要复制对象的字段值,对于8种基本类型,如int,long,float等,则复制值;对于复合数据类型仅复制该字段值,如数组则复制地址,对于对象变量则复制对象的reference。

    2.深克隆(deep clone)

    深克隆和浅克隆的区别在于复合数据类型的复制。若对象中的某个字段为复合类型,在克隆对象的时候,需要为该字段重新创建对象。

二、Java数组的复制

1. 定义一个数组int[] a={3,1,4,2,5}; int[] b=a;  数组b只是对数组a的又一个引用,即浅拷贝。

  如果改变数组b中元素的值,其实是改变了数组a的元素的值,要实现深度复制,可以用clone或者System.arrayCopy

<span style="white-space:pre">	</span><pre name="code" class="java">int[] a={3,1,4,2,5};
int[] b=a.clone();
b[0]=10;
System.out.println(b[0]+"  "+a[0]);




但是clone和System.arrayCopy都是对一维数组的深度复制。

  2. 对于二维数组则不一样:

int[][] a={{3,1,4,2,5},{4,2}};
int[][] b=a.clone();
b[0][0]=10;
System.out.println(b[0][0]+"  "+a[0][0]);


输出为10。

10所以clone并不能直接作用于二维数组。

   因为java中没有二维数组的概念,只有数组的数组。所以二维数组a中存储的实际上是两个一维数组的引用。当调用clone函数时,是对这两个引用进行了复制。

  3. 要证明,只需看下面的输出

int[][] a={{3,1,4,2,5},{4,2}};
int[][] b=a.clone();
b[0][0]=10;
System.out.println(b[0][0]+"  "+a[0][0]);
System.out.println(a[0]==b[0]);


第5句输出为true.

用clone对二维数组进行复制,要在每一维上调用clone函数。

int[][] a={{3,1,4,2,5},{4,2}};
int[][] b=new int[a.length][];
for(int i=0;i<a.length;i++)
{ b[i]=a[i].clone();} 
b[0][0]=10;
System.out.println(b[0][0]+"  "+a[0][0]);
System.out.println(b[0]==a[0]);

输出为10  3 false

三、小结:

   数组的复制方法现在至少有四个思路:

   1. 使用循环结构 这种方法最灵活。唯一不足的地方可能就是代码较多

   2. 使用Object类的clone()方法, 这种方法最简单,得到原数组的一个副本。灵活形也最差。效率最差,尤其是在数组元素很大或者复制对象数组时。

   3. 使用Systems的arraycopy这种方法被告之速度最快,并且灵活性也较好,可以指定原数组名称、以及元素的开始位置、复制的元素的个数,目标数组名称、目标数组的位置。

   4. Arrarys类的copyOf()方法与copyOfRange()方法可实现对数组的复制

### Java中的复制实现及其与浅复制的区别 #### 深复制的概念 在Java中,深复制是指创建一个新的对象,并且该新对象的所有字段也都是新的对象实例。这意味着原始对象和副本之间没有任何共享的数据结构[^1]。 #### 浅复制的特点 相比之下,浅复制复制对象的引用而不是实际的对象本身。因此,在浅复制的情况下,如果修改了被引用对象的内容,则这些更改会反映到所有的引用上。 #### 实现深复制的方法之一:通过`clone()`方法 一种常见的实现方式是重写`Object`类中的`clone()`方法来支持深复制。下面是一个例子: ```java public class DeepCopyExample implements Cloneable { private int[] numbers; public DeepCopyExample(int[] nums) { this.numbers = nums; } @Override protected Object clone() throws CloneNotSupportedException { // 调用父类的克隆方法得到当前对象的一个浅拷贝 DeepCopyExample clonedObj = (DeepCopyExample) super.clone(); // 对数组进行手动深拷贝 clonedObj.numbers = new int[this.numbers.length]; System.arraycopy(this.numbers, 0, clonedObj.numbers, 0, this.numbers.length); return clonedObj; } } ``` 上述代码展示了如何利用`super.clone()`来进行初步的浅复制操作,随后针对内部可变组件执行额外的手动复制逻辑以完成真正的深复制过程。 #### 使用序列化机制实现深复制 另一种常用的技术涉及将对象转换为其字节流表示形式(即序列化),然后再将其反序列化回内存中形成完全独立的新实例。这种方法适用于实现了`Serializable`接口的所有类型的复杂数据结构。 以下是基于此技术的具体实践案例: ```java import java.io.*; public class SerializationDeepCopy<T extends Serializable> implements Serializable { public static <T extends Serializable> T deepClone(T obj) throws IOException, ClassNotFoundException { try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bis)) { out.writeObject(obj); // 序列化原对象至字节数组输出流 return (T)in.readObject(); // 反序列化读取回来作为新对象返回 } } } ``` 这里定义了一个通用工具函数用于任何满足条件的目标类型做深层复制处理。 #### 主要差异总结表 | 特性 | 浅复制 | 深复制 | |-------------------|-------------------------------------------|------------------------------------------| | **资源消耗** | 较低 | 高 | | **性能影响** | 更高效 | 相对较慢 | | **适用场景** | 当不需要担心嵌套对象状态同步时可以接受 | 如果希望彻底隔离两个对象则必需采用 | ### 结论 综上所述,无论是采取覆盖默认行为还是借助外部辅助手段如序列化的途径都可以达成目的;然而具体选用哪种策略取决于项目需求以及待解决的实际问题背景等因素综合考量决定最佳方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值