Prototype_原型模式

原型模式,就是拷贝,通过拷贝一个已经创建的原型实例,来创建一个和原型相同或相似的新对象。
Java中自带克隆方法,实现Cloneable接口,并重写clone方法。需要注意深拷贝和浅拷贝,默认方法是浅拷贝,即原型对象和克隆对象中的引用类型的对象所指向的地址值相同,都指向同一个对象,(就是克隆的时候是引用传递,不是值传递)。如果需要深拷贝可以通过改造clone方法,或通过序列化反序列化等方式来实现。

演示浅拷贝

  • 实现Cloneable接口:这是一个标记性接口,里面没有需要我们实现的方法,不实现这个接口编译器不报错,但运行报错。
  • 重写clone方法:Object对象中的clone方法是一个native方法,就是一个Java调用非Java代码的接口,clone方法是用C++写的,没有Java的原码,所有如果想使用clone方法必须重写clone方法。clone方法声明:protected native Object clone() throws CloneNotSupportedException;
public class Person implements Cloneable{
    public String name = "lin";
    public Date date = new Date();
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "name: "+name+"\ndate: "+date+"\ndateHash: "+date.hashCode();
    }
}

创建原型实例lin,并克隆出新实例copyLin。分别打印name,date,date的哈希值,实例的哈希值。

    public static void main(String[] args) throws CloneNotSupportedException {
        Person lin = new Person();
        Person copyLin = (Person) lin.clone();
        System.out.println(lin.toString() + "\nhashcode: "+lin.hashCode());
        System.out.println(copyLin.toString() + "\nhashcode: "+copyLin.hashCode());
    }

测试结果,实例的哈希值不一样,说明真的新建了实例,但Date引用的哈希值一样,说明并没有克隆出新的Date,属于浅拷贝。

通过改造clone方法实现深拷贝

在重写clone方法时,将对象的引用也进行克隆

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person person = (Person) super.clone();
        person.date = (Date) this.date.clone();
        return person;
    }

进行测试,克隆后修改了克隆实例引用的Date的值

public static void main(String[] args) throws CloneNotSupportedException {
        Person lin = new Person();
        Person copyLin = (Person) lin.clone();
        copyLin.date.setTime(100000000);
        System.out.println(lin.toString() + "\nhashcode: "+lin.hashCode());
        System.out.println(copyLin.toString() + "\nhashcode: "+copyLin.hashCode());
    }

结果只有克隆出来的实例的Date值被修改了,原型实例的Date值不变,说明是深克隆。

posted @ 2022-07-27 12:09  独游空想家  阅读(18)  评论(0编辑  收藏  举报