克隆对象
- 写的很好
- 源码注解
1. 为什么要实现克隆
克隆是为了复制一个对象,protected native Object clone() throws CloneNotSupportedException;
是native方法,比在java代码中一个个复制对象的属性要简洁并且速度快。
克隆对象一般应该实现三个语义:
x.clone() != x will be true
保证克隆对象将有单独的内存地址分配。x.clone().getClass() == x.getClass() will be true
,非强制性,原始和克隆的对象应该具有相同的类类型,但它不是强制性的。x.clone().equals(x)
,非强制性,原始和克隆的对象应该是平等的equals()方法使用,但它不是强制性的。
克隆分为两种:ShallowClone浅克隆和DeepClone深度克隆,深度克隆支持引用类型的成员变量的复制。
2. 如何实现克隆
浅克隆的一般步骤是:
- 被克隆的对象类或者其父类实现了
Cloneable
接口; - 覆盖
clone()
方法,访问修饰符设为public。方法中调用super.clone()
方法得到需要的复制对象; - 这种方法克隆的对象与源对象的类成员变量是同一个对象。
class Person implements Cloneable{
public String name;
}
class Address{
public String add;
public Address(String add) {
this.add = add;
}
}
class Student extends Person{
public Address address;
public Student(String name, Address address) {
this.name=name;
this.address=address;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return name+":"+address.add;
}
}
public class InstanceClone {
public static void main(String[] args) throws CloneNotSupportedException {
Address add=new Address("handan");
Student s1=new Student("du",add);
Student s2=(Student)s1.clone();
System.out.println(s1);
System.out.println(s2);
add.add="zhongguo";
System.out.println(s1);
System.out.println(s2);
}
}
深度克隆一种方法是:
- 类中成员变量需要继承
Cloneable
接口,然后并重写clone()
方法,将方法修饰符修改为public; - 被克隆的类或者其父类实现
Cloneable
接口,然后重写clone()
方法,将方法修饰符修改为public,并在方法中调用成员变量的clone
方法; - 基本思路同浅克隆。
另一种实现深度克隆的方式是序列化:==如果引用链过长,则我们可以通过序列化的方式进行克隆**,示例代码:
[注]:克隆不收transient
限制:
try(FileOutputStream f=new FileOutputStream("E:\\object.dat");
ObjectOutputStream o=new ObjectOutputStream(f)) {
o.writeObject(s1);
} catch (IOException e) {
e.printStackTrace();
}
try(FileInputStream f=new FileInputStream("E:\\object.dat");
ObjectInputStream in=new ObjectInputStream(f)){
Student s3=(Student)in.readObject();
System.out.println(s3);
}catch (Exception e){
e.printStackTrace();
}
- 成员变量也需要实现
Serializable
接口;