在实际工作中,为了不破坏数据源,我们首先想到的可能是把数据源对象进行一个拷贝,这样以为会得到一个与原对象有一样的域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》