java浅克隆和深克隆的定义

转自: http://wxg6203.iteye.com/blog/649648

 

深克隆与浅克隆


大家知道,对象是互相引用的,即对象中可能包含了另一个对象的引用,举例如:有一个Order对象,Order对象中又包含了LineItems对象,然后LineItems对象又包含了Item对象。


好了,现在我有一个Order对象order1,它包含了一个LineItems对象items,这表示的是有一个订单order1,订单的内容是items。


好的,现在有另一个客户想要一份订单,内容跟order1完全一样,那么在系统的逻辑层我们怎么做呢?很简单,order2=order1.clone(). 我们知道clone方法是在内存中生成一个新的对象,而不是只得到原对象的引用。这时候,有人说话了:“哦,明白了我们对order2的成员变量进行修改,是不会影响order1的。” 很可惜,这句话只对了一半。


假设order类有一个成员变量name,当然改变order2.name不会影响order1.name,因为他们在不同的内存区域。但是如果改变 order1.items呢?很遗憾,简单地使用order1.clone,是会影响到order2.items的。原因很简单,就是因为clone方法默认的是浅克隆,即不会克隆对象引用的对象,而只是简单地复制这个引用。所以在上例中,items对象在内存中只有一个,order1和order2都指向它,任何一个对象对它的修改都会影响另一个对象。


那相对浅克隆,深克隆自然就是会克隆对象引用的对象了。也就是说,在上例中,改变order1.items并不会影响order2.items了。因为内存中有两个一样的items。


如果实现深克隆?

一个方法自然是重写clone方法,添加如order.items=(LineItems)items.clone()的语句,也就是人为地添加对引用对象的复制。这个方法的缺点是如果引用对象有很多,或者说引用套引用很多重,那么太麻烦了。业界常用的方法是使用串行化然后反串行化的方法来实现深克隆。由于串行化后,对象写到流中,所有引用的对象都包含进来了,所以反串行化后,对等于生成了一个完全克隆的对象。绝!


这个方法的要求是对象(包括被引用对象)必须事先了Serializable接口,否则就要用transient关键字将其排除在复制过程中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,拷贝和拷贝都是用于复制对象的概念。 拷贝是指创建一个新对象,然后将原始对象的非静态字段复制到新对象中。如果字段是基本类型,则对该字段执行逐位复制;如果字段是引用类型,则复制引用而不是引用的对象。 拷贝是指创建一个新对象,然后递归地复制原始对象及其所有引用的对象。这意味着在拷贝中,即使字段是引用类型,也会创建一个新的对象并复制其内容。 要实现拷贝,可以使用`clone()`方法。该方法在`Object`类中定义,并且可以由任何类继承和覆盖。要使一个类支持克隆,需要实现`Cloneable`接口,并且覆盖`clone()`方法。 示例代码如下: ```java class MyClass implements Cloneable { private int value; private MyObject obj; public MyClass(int value, MyObject obj) { this.value = value; this.obj = obj; } public int getValue() { return value; } public MyObject getObj() { return obj; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } class MyObject { private String name; public MyObject(String name) { this.name = name; } public String getName() { return name; } } public class Main { public static void main(String[] args) throws CloneNotSupportedException { MyObject obj = new MyObject("Object 1"); MyClass obj1 = new MyClass(10, obj); MyClass obj2 = (MyClass) obj1.clone(); System.out.println(obj1.getObj().getName()); // Output: Object 1 System.out.println(obj2.getObj().getName()); // Output: Object 1 obj.setName("Object 2"); System.out.println(obj1.getObj().getName()); // Output: Object 2 (原始对象和拷贝对象引用同一个对象) System.out.println(obj2.getObj().getName()); // Output: Object 2 } } ``` 需要注意的是,拷贝只复制了对象的引用,而不是对象本身。因此,如果修改了原始对象中的引用对象,那么拷贝对象也会受到影响。 要实现拷贝,可以使用序列化和反序列化。通过将对象写入字节流,然后从字节流读取对象,可以创建一个全新的对象。这种方法需要确保所有相关的类都实现了`Serializable`接口。 示例代码如下: ```java import java.io.*; class MyClass implements Serializable { private int value; private MyObject obj; public MyClass(int value, MyObject obj) { this.value = value; this.obj = obj; } public int getValue() { return value; } public MyObject getObj() { return obj; } } class MyObject implements Serializable { private String name; public MyObject(String name) { this.name = name; } public String getName() { return name; } } public class Main { public static <T> T deepCopy(T object) throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(object); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (T) ois.readObject(); } public static void main(String[] args) throws IOException, ClassNotFoundException { MyObject obj = new MyObject("Object 1"); MyClass obj1 = new MyClass(10, obj); MyClass obj2 = deepCopy(obj1); System.out.println(obj1.getObj().getName()); // Output: Object 1 System.out.println(obj2.getObj().getName()); // Output: Object 1 obj.setName("Object 2"); System.out.println(obj1.getObj().getName()); // Output: Object 1 (原始对象和拷贝对象引用不同的对象) System.out.println(obj2.getObj().getName()); // Output: Object 1 } } ``` 通过序列化和反序列化可以实现拷贝,因为它会创建一个全新的对象,而不是引用原始对象的对象。这样,即使修改了原始对象中的引用对象,拷贝对象也不会受到影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值