Cloneable接口本身没有任何方法,它仅仅是告诉你实现这个接口的对象允许克隆(clone),要实现clone需要覆盖Object类中的clone()方法。这里需要捕获CloneNotSupportedException异常。
拷贝对象往往会导致创建创建它的类的一个新的实例,同时拷贝内部的数据结构,这个过程没有调用构造器。
浅拷贝
对于要克隆的对象,对于其基本数据类型的属性,复制一份给新产生的对象,对于非基本数据类型的属性,仅仅复制一份引用给新产生的对象,即新产生的对象和原始对象中的非基本数据类型的属性都指向的是同一个对象
如果每个域包含一个基本类型的值,或者包含一个指向不可变对象的引用,那么可以直接使用super.clone()。代码如下:
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();//1.5以后覆盖方法的返回类型可以是被覆盖方法的返回类型的子类型
}
深拷贝
在浅度克隆的基础上,对于要克隆的对象中的非基本数据类型的属性对应的类,也实现克隆,这样对于非基本数据类型的属性,复制的不是一份引用,即新产生的对象和原始对象中的非基本数据类型的属性指向的不是同一个对象。要克隆的类和类中所有非基本数据类型的属性对应的类都要实现java.lang.Cloneable接口和重写java.lang.Object.clone()方法。
所有实现了Cloneable接口的类都应该用一个公有的方法覆盖clone。此公有方法首先调用super.clone(),然后修正任何需要修正的域。
代码见最后测试代码。
使用对象序列化和反序列化实现深度克隆
我在网上看到有说使用序列化和反序列化实现深度克隆,很受启发。所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。对象的序列化还有另一个容易被大家忽略的功能就是对象复制(Clone),Java中通过Clone机制可以复制大部分的对象,但是众所周知,Clone有深度Clone和浅度Clone,如果你的对象非常非常复杂,并且想实现深层 Clone,如果使用序列化,不会超过10行代码就可以解决。不过还有很多问题需要注意,比如transient修饰的变量不会被序列化等等。
下面是测试的代码,有些不规范的地方多担待:
import java.io.*;
/**
* Created by SUN on 2017/8/3.
* 深拷贝与浅拷贝
*/
public class test02 {
public static void testClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {
A_beclone A = new A_beclone("xiaoming",1,1);
A_beclone B = A.clone();
A_beclone C = A.cloneByOS();
System.out.println("A:"+A);
System.out.println("B:"+B);
System.out.println("C:"+C);
B.stu.age=2;
B.id=2;
C.stu.age=3;
C.id=3;
System.out.println("A:"+A+"\nB:"+B+"\nC:"+C);
System.out.println("A hashCode:"+A.hashCode()+"\nB hashCode:"+B.hashCode()+"\nC hashCode:"+C.hashCode());
System.out.println("Astu hashCode:"+A.stu.hashCode()+"\nBstu hashCode:"+B.stu.hashCode()+
"\nCstu hashCode:"+C.stu.hashCode());
//浅拷贝,只复制基本类型,对于引用类型复制的是引用,指向的还是同一个对象
//深拷贝,对于引用类型,同样要实现Cloneable接口
}
}
class Student implements Cloneable,Serializable{
public String name;
public int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
@Override
public String toString(){
return "Name:"+name+" Age:"+age;
}
}
class A_beclone implements Cloneable,Serializable{
public Student stu;
public int id;
public A_beclone(String name,int age,int id){
this.id=id;
this.stu=new Student(name,age);
}
public A_beclone(){}
@Override
public String toString(){
return "ID:"+id+" "+stu.toString();
}
@Override//实现深拷贝,浅拷贝则直接return super.clone();
public A_beclone clone() throws CloneNotSupportedException {
A_beclone result = (A_beclone) super.clone();
result.stu=stu.clone();
return result;
}
//通过序列化拷贝
public A_beclone cloneByOS() throws IOException, ClassNotFoundException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.dat"));
oos.writeObject(this);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.dat"));
A_beclone result = (A_beclone)ois.readObject();
ois.close();
return result;
}
}
输出如下:
A:ID:1 Name:xiaoming Age:1
B:ID:1 Name:xiaoming Age:1
C:ID:1 Name:xiaoming Age:1
A:ID:1 Name:xiaoming Age:1
B:ID:2 Name:xiaoming Age:2//若是浅拷贝,B.stu会指向A.stu,B.stu改变会影响到A.stu的值
C:ID:3 Name:xiaoming Age:3
A hashCode:1836019240
B hashCode:931919113
C hashCode:1607521710 //深拷贝每个实例的hashCode都不同,包括下面的stu
Astu hashCode:325040804
Bstu hashCode:764977973
Cstu hashCode:381259350
以上,日后还会继续扩充,有误请指正,大家共同进步!