Java对象的深层拷贝


在实际工作中,为了不破坏数据源,我们首先想到的可能是把数据源对象进行一个拷贝,这样以为会得到一个与原对象有一样的域or一样的数据结构的对象。

思想是正确的,但结果是危险的,因为Object中实现的Cloneable接口后它的clone()方法是私有的,所以其子类要想克隆,就必须覆写clone()方法,在clone里面调用super.clone()。

值得注意的是,super.clone()只是一个浅层拷贝,即,它只能对基本类型的数据进行一个拷贝,而对于这个对象里面有可变引用的类型,它将破坏被克隆的约束条件。在运行期可能会抛出空指针异常。那要怎么做,才能对可变引用数据类型进行一个拷贝,且不破坏对象呢?</p><p>网上有一种做法,叫深层拷贝,自己可以上网查下,下面我就记录下《Effective Java》(第2版)中实现的一种方法,那就是对原对象中的可变引用数据,递归的调用clone,以达到深层拷贝的效果。如下:

public class Stack{  
 private Object[] elements;  
 private int size = 0;  
 private static final int DEFAULT_CAP = 20;  
  
 public Stack(){  
  elements = new Object[DEFAULT_CAP];  
}  
//一些其它方法  
}  
@Override  
public Stack clone(){  
 try{  
  Stack stack= (Stack)super.clone();  
  stack.elements = elements.clone();  
return stack;  
}catch(CloneNotSupportedException e){  
  throw new AssertionError();  
 }  
}  


下面着重来记下Java利用序列化来实现深层拷贝

我们都知道,在写一个Model时,会习惯性的让它实现Serializable接口。以让对象达到可序列化的目的。这样我们就可以利用其序列化与反序列化,通过流就可以达到对象的深层拷贝了。如下:

public Object deepClone() {    
   //将对象写到流里    
   ByteArrayOutoutStream bo=new ByteArrayOutputStream();    
   ObjectOutputStream oo=new ObjectOutputStream(bo);    
   oo.writeObject(this);    
   //从流里读出来    
   ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());    
   ObjectInputStream oi=new ObjectInputStream(bi);    
   return(oi.readObject());    
}

下面贴出网上的一个例子:

package com.king.cloneable;

import java.io.*;

/**
 * 通过串行化实现深复制
 */
class Teacher implements Serializable {
    String name;
    int age;

    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

public class DeepStudent2 implements Serializable {
    String name;//常量对象
    int age;
    Teacher t;//学生1和学生2的引用值都是一样的。

    public DeepStudent2(String name, int age, Teacher t) {
        this.name = name;
        this.age = age;
        this.t = t;
    }

    public Object deepClone() throws IOException, ClassNotFoundException {//将对象写到流里
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(this);//从流里读出来
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        return (oi.readObject());
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Teacher t = new Teacher("tangliang", 30);
        DeepStudent2 s1 = new DeepStudent2("zhangsan", 18, t);
        DeepStudent2 s2 = (DeepStudent2) s1.deepClone();
        s2.t.name = "tony";
        s2.t.age = 40;
        //学生1的老师不改变
        System.out.println("name=" + s1.t.name + "," + "age=" + s1.t.age);
    }
}


参考文献:

1、《Effective Java》

2、Java对象的深复制和浅复制











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值