• 设计模式之原型模式(Prototype)


    原型模式

    如果已经有一个对象了,你想创建一个对象,而且对象里面的属性和已经存在的对象的属性差不多,就可以使用clone方法
    克隆一个出来
    在这里插入图片描述

    实现原型模式需要实现标记型接口Cloneable -->标记型接口 : 里面没有需要实现的方法(空接口)
    一般会重写clone方法 --> 如果只是重新clone方法,而没有实现Cloneable接口,调用时会报异常
    一般用于一个对象的属性以及确定,需要产生很多相同或大部分属性相同的对象的时候
    需要区分深克隆和浅克隆

    java自带,Object类里面有个Object.clone()。也称为克隆模式
    clone方法是protected native方法 C++实现 只能子类调用

    浅克隆:
    Object的clone,是在内存里面重新创建一个对象,copy过来原来对象的属性,如果是基本数据类型,拷贝的是值过去,
    如果是引用数据类型,拷贝的是对象的内存地址,指向的是同一个对象,互相有影响
    有没有方法把引用的对象也拷贝一份呢? --> 深克隆

    /**
     * 浅克隆
     */
    
    public class Test {
        public static void main(String[] args) throws Exception {
            Person p1 = new Person();
            // 克隆
            Person p2 = (Person)p1.clone();
            // 基本数据类型,值直接copy过来
            System.out.println(p2.age + " " + p2.score);
            System.out.println(p2.loc);
            // 引用数据类型,copy的是内存地址,指向的是同一个对象,所以相等
            System.out.println(p1.loc == p2.loc); // true
            // 如果p1对象的loc改变了,p2的loc也会改变
            p1.loc.street = "sh";
            System.out.println(p2.loc); // sh
    
        }
    }
    
    // 实现Cloneable接口
    class Person implements Cloneable {
        int age = 8;
        int score = 100;
    
        Location loc = new Location("bj", 22);
        // 实现clone方法
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    class Location {
        String street;
        int roomNo;
    
        @Override
        public String toString() {
            return "Location{" +
                    "street='" + street + '\'' +
                    ", roomNo=" + roomNo +
                    '}';
        }
    
        public Location(String street, int roomNo) {
            this.street = street;
            this.roomNo = roomNo;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    深克隆:
    引用的对象Location也实现Cloneable接口以及clone方法,在clone Person对象的时候将原来对象的loc也clone一份出来,
    然后新clone出来 的对象的loc引用指向clone处理的loc

    /**
     * 深克隆的处理
     */
    public class Test {
        public static void main(String[] args) throws Exception {
            Person p1 = new Person();
            Person p2 = (Person)p1.clone();
            System.out.println(p2.age + " " + p2.score); // 8 100
            System.out.println(p2.loc);
            // 不是同一个对象了
            System.out.println(p1.loc == p2.loc); // false
            p1.loc.street = "sh";
            // 改变p1的loc不好影响p2
            System.out.println(p2.loc); // bj
        }
    }
    
    class Person implements Cloneable {
        int age = 8;
        int score = 100;
    
        Location loc = new Location("bj", 22);
        @Override
        public Object clone() throws CloneNotSupportedException {
            // clone一份新的对象出来
            Person p = (Person)super.clone();
            // 将原来的loc,也clone一份出来,新对象的loc指针指向clone处理的loc对象
            p.loc = (Location)loc.clone();
            return p;
        }
    }
    // 被引用的对象实现Cloneable接口以及clone方法
    class Location implements Cloneable {
        String street;
        int roomNo;
    
        @Override
        public String toString() {
            return "Location{" +
                    "street='" + street + '\'' +
                    ", roomNo=" + roomNo +
                    '}';
        }
    
        public Location(String street, int roomNo) {
            this.street = street;
            this.roomNo = roomNo;
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    引用数据类型,在深克隆的时候,是需要被克隆一份的,上面的String也是引用数据类型,clone的时候也需要将它克隆一份吗?
    不需要。
    String类型放在了常量池里面,比如说第一个Person对象里面的String指向的是常量池里面的"bj",clone出来的对象也是指向的常量池里面的"bj",
    如果第一个Person对象里面的String变成了"sh",是不会影响第二个对象的,因为只是第一个对象里面的String指向了常量池里面的"sh",被克隆出来
    的对象还是指向的"bj"。

    /**
     * String需要进一步深克隆吗?
     */
    public class Test {
        public static void main(String[] args) throws Exception {
            Person p1 = new Person();
            Person p2 = (Person)p1.clone();
            System.out.println(p2.age + " " + p2.score);
            System.out.println(p2.loc);
    
            System.out.println(p1.loc == p2.loc); // false
            p1.loc.street = "sh";
            System.out.println(p2.loc);
    
            p1.loc.street.replace("sh", "sz");
            // 改变p1里面的string,不好影响p2
            System.out.println(p2.loc.street); // bj
        }
    }
    
    class Person implements Cloneable {
        int age = 8;
        int score = 100;
    
        Location loc = new Location("bj", 22);
        @Override
        public Object clone() throws CloneNotSupportedException {
            Person p = (Person)super.clone();
            p.loc = (Location)loc.clone();
            return p;
        }
    }
    
    class Location implements Cloneable {
        String street;
        int roomNo;
    
        @Override
        public String toString() {
            return "Location{" +
                    "street='" + street + '\'' +
                    ", roomNo=" + roomNo +
                    '}';
        }
    
        public Location(String street, int roomNo) {
            this.street = street;
            this.roomNo = roomNo;
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    下面的例子中,String用的是StringBuilder,Person 1和Person 2里面的String都是指向的同一个StringBuilder,所以
    当Person 1的String改变之后,Person 2的String也会改变。
    怎么解决? --> 深克隆的时候,也需要把StringBuilder克隆一份

    /**
     * String需要进一步深克隆吗?
     */
    public class Test {
        public static void main(String[] args) throws Exception {
            Person p1 = new Person();
            Person p2 = (Person)p1.clone();
            // loc 经过clone之后指向的不是同一个对象
            System.out.println("p1.loc == p2.loc? " + (p1.loc == p2.loc)); // false
            // p1和p2里面的String指向的是同一个StringBuilder,所以当p1里面的String改变的时候,
            // p2的也会改变
            p1.loc.street.reverse();
            System.out.println(p2.loc.street); // jb
        }
    }
    
    class Person implements Cloneable {
        int age = 8;
        int score = 100;
    
        Location loc = new Location(new StringBuilder("bj"), 22);
        @Override
        public Object clone() throws CloneNotSupportedException {
            Person p = (Person)super.clone();
            p.loc = (Location)loc.clone();
            return p;
        }
    }
    
    class Location implements Cloneable {
        StringBuilder street;
        int roomNo;
    
        @Override
        public String toString() {
            return "Location{" +
                    "street='" + street + '\'' +
                    ", roomNo=" + roomNo +
                    '}';
        }
    
        public Location(StringBuilder street, int roomNo) {
            this.street = street;
            this.roomNo = roomNo;
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    深克隆用的少,面试也问的少,了解就行

  • 相关阅读:
    11.CF522D Closest Equals 线段树+离线询问
    每天一个设计模式之享元模式(Flyweight Pattern)
    2023大厂高频面试题之Vue篇(3)
    东北最大城商行退出异地助贷,发力区域自营业务
    C++实现基于自动机的句子分词程序
    11.cuBLAS开发指南中文版--cuBLAS中的Level-1函数amax()和amin()
    如何购买并配置华为云服务器?
    google colab上让 python 视觉化套件 matplotlib 显示中文
    数据结构与算法复习:第三十一弹
    ThreadLocal会用可不够
  • 原文地址:https://blog.csdn.net/u011069294/article/details/134379259