克隆对象

1. 为什么要实现克隆

克隆是为了复制一个对象,protected native Object clone() throws CloneNotSupportedException;是native方法,比在java代码中一个个复制对象的属性要简洁并且速度快

克隆对象一般应该实现三个语义:

  1. x.clone() != x will be true保证克隆对象将有单独的内存地址分配。
  2. x.clone().getClass() == x.getClass() will be true,非强制性,原始和克隆的对象应该具有相同的类类型,但它不是强制性的。
  3. x.clone().equals(x),非强制性,原始和克隆的对象应该是平等的equals()方法使用,但它不是强制性的。

克隆分为两种:ShallowClone浅克隆和DeepClone深度克隆,深度克隆支持引用类型的成员变量的复制。

2. 如何实现克隆

浅克隆的一般步骤是

  1. 被克隆的对象类或者其父类实现了Cloneable接口;
  2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象;
  3. 这种方法克隆的对象与源对象的类成员变量是同一个对象。
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);
    }
}

深度克隆一种方法是:

  1. 类中成员变量需要继承Cloneable接口,然后并重写clone()方法,将方法修饰符修改为public
  2. 被克隆的类或者其父类实现Cloneable接口,然后重写clone()方法,将方法修饰符修改为public,并在方法中调用成员变量的clone方法;
  3. 基本思路同浅克隆。

另一种实现深度克隆的方式是序列化:==如果引用链过长,则我们可以通过序列化的方式进行克隆**,示例代码:
[注]:克隆不收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接口;

posted on 2018-04-21 13:41  coderDu  阅读(129)  评论(0编辑  收藏  举报