設計模型之原型模型與cloneable接口(深度克隆與淺度克隆區別)

      原型模型應該屬於容易理解簡單設計模型了,若是咱們有個對象A,須要大量能夠對它進行拷貝,或者須要在一個循環體內建立對象,假如對象建立過程比較複雜或者循環次數不少的話,使用原型模式能夠簡化建立過程,並且可使系統的總體性能提升不少。克隆的對象可能包含一些已經修改過的屬性,保留着你想克隆對象的值,而new出來的對象的屬性全是一個新的對象,對應的屬性沒有值,因此咱們還要從新給這個對象賦值。即當須要一個新的對象來保存當前對象的「狀態」就靠clone方法了。那麼我把這個對象的臨時屬性一個一個的賦值給我新new的對象不也行嘛?能夠是能夠,可是一來麻煩不說,二來,你們經過源碼發現clone是一個native方法,快,在底層實現的。數組

 使用原型模式複製對象不會調用類的構造方法,而是經過cloneable接口的clone方法來完成的,它直接在內存中複製數據,所以不會調用到類的構造方法。不但構造方法中的代碼不會執行,甚至訪問權限都對原型模式無效。ide

 

 克隆時候咱們須要注意,咱們有區分淺克隆和深克隆。性能

淺克隆是指拷貝對象時僅僅拷貝對象自己(包括對象中的基本變量),而不拷貝對象包含的引用指向的對象。測試

深克隆不只拷貝對象自己,並且拷貝對象包含的引用指向的全部對象。 this

object類的clone方法只會拷貝對象中的基本的數據類型,對於數組、容器對象、引用對象等都不會拷貝,這就是淺拷貝。若是要實現深度拷貝,必須將原型中的數據、容器對象、引用對象等另行拷貝。spa

具體不一樣地方以下圖所示:.net

簡單來講,淺度克隆就是隻是實現了cloneable接口,默認的是實現了super的方法,默認的是使用object的克隆方法,它只能對基本類型進行一個複製,而對於指向對象的引用不能作複製,值是把克隆的引用都指向了是原來對象同一塊內存(假複製),這個同一塊內存的任何參數發生了變化,相關引用也取值必然也是發生變化。設計

深度克隆實際上是須要咱們覆蓋重寫cloneable接口,咱們對若是默認裏面還含有對象的引用,再進行一個複製,這樣才能達到給複製對象裏面引用對象開闢一個新的內存,才能達到真正的徹底複製。對象

下面咱們看個例子:blog

//建立一個老師對象,每一個學生都有一個老師,咱們這兒只是用來測試cloneable接口的問題

public class Teacher implements Cloneable{

 public    String name;
 
 public Teacher(){
     name = "init teacher";
 }

 @Override
    protected Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return super.clone();
    }
}

 

public class Student implements Cloneable {
    private int age;
    private String name;
    private Teacher teacher = new Teacher();
    
    
 
    public Teacher getTeacher() {
        return teacher;
    }


    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public String toString() {
        return "Student [age=" + age + ", name=" + name + "]";
    }
 
    @Override
    public Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub

//深度克隆
//        Student s = (Student) super.clone();
//        s.teacher = (Teacher) s.teacher.clone();
//        return s;

        //淺度克隆
        return super.clone();
    }
 
    /**
     * @param args
     * @throws CloneNotSupportedException
     */
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1 = new Student(20, "張三");
//        Teacher teacher = new Teacher();
//        student1.setTeacher(teacher);
        student1.teacher.name = "李老師";
        Student student2 = (Student) student1.clone();
        student2.teacher.name = "張老師";
        student2.setAge(22);// 注意修改student2的age值 可是沒有影響 student1的值
        System.out.println("student1:" + student1.getName() + "-->"+ student1.getAge() + " --->" + student1.teacher.name);
        System.out.println("student2:" + student2.getName() + "-->"+ student2.getAge()+ " --->" + student2.teacher.name);
 
    }
}

咱們看看淺克隆打印結果:

student1:張三-->20 --->張老師
student2:張三-->22 --->張老師

深克隆打印結果:

student1:張三-->20 --->李老師
student2:張三-->22 --->張老師

 

以上內容有部分參考

https://blog.csdn.net/lovezhaohaimig/article/details/80372233

相關文章
相關標籤/搜索