Java深入學習26:Java深度克隆


Java深入學習26:Java深度克隆

深克隆和淺克隆區別

  淺克隆: 只copy對象引用,不copy對象本身。即對象地址不變,仍然只存在一個對象。

  深克隆: 不僅拷貝對象本身,而且拷貝對象包含的引用指向的所有對象。

 

深克隆的兩個方案

方案1——實現Cloneable接口,重寫Object類地 clone()方法

  分如下三步

  1. 對象的類實現Cloneable接口(必須,否則會拋出CloneNotSupportedException異常);

  2. 覆蓋Object類的clone()方法 (覆蓋clone()方法,將訪問修飾符改為public,默認是protected);

  3. 在clone()方法中調用super.clone();

public class CloneTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        Student stu = new Student("A");
        Student deep = stu.clone();//深克隆
        Student shallow = stu;//淺克隆
        shallow.setName("B");
        System.out.println("original: " + stu);//Student{name='B'}
        System.out.println("deep: " + deep);//Student{name='A'}
        System.out.println("shallow: " + shallow);//Student{name='B'}

    }


}

class Student implements  Cloneable{
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

 @Override public Student clone() throws CloneNotSupportedException { return (Student) super.clone(); }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

 

深克隆的多級深克隆問題:

  重寫clone()方法,只會深克隆類和類中所有非基本數據類型的屬性對應的類。對於類中的屬性對應的類,是無法深克隆的,如果深克隆類中的屬性對應的類,需要額外的調用類中的屬性對應的類clone方法

public class CloneTest {

    public static void main(String[] args) throws CloneNotSupportedException {

        School sch  = new School("a",new Student("A"));
        School deepSch = sch.clone();//深克隆
        School shallowSch = sch;//淺克隆
        shallowSch.getStu().setName("B");
        System.out.println(sch);//School{name='a', stu=Student{name='B'}}
        System.out.println(deepSch);//School{name='a', stu=Student{name='A'}}
        System.out.println(shallowSch);// School{name='a', stu=Student{name='B'}}

    }

}

class School implements  Cloneable{
    private String name;
    private Student stu;


    @Override
    public School clone() throws CloneNotSupportedException {
        //return (School)super.clone();//該方法無法深克隆Sch中的Student
 School clone = (School) super.clone(); clone.setStu(this.stu.clone()); return clone;

    }


    public School(String name, Student stu) {
        this.name = name;
        this.stu = stu;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Student getStu() {
        return stu;
    }

    public void setStu(Student stu) {
        this.stu = stu;
    }

    @Override
    public String toString() {
        return "School{" +
                "name='" + name + '\'' +
                ", stu=" + stu +
                '}';
    }
}

 

方案2——序列化深克隆

什么是序列化?

  1- java序列化是指把java對象轉換為字節序列的過程,而java反序列化是指把字節序列恢復為java對象的過程

  2- 序列化:對象序列化的最主要的用處就是在傳遞和保存對象的時候,保證對象的完整性和可傳遞性。序列化是把對象轉換成有序字節流,以便在網絡上傳輸或者保存在本地文件中。序列化后的字節流保存的java對象的狀態以及相關的描述信息。序列化機制的核心作用就是對象狀態的保存與重建。

  3- 反序列化:客戶端從文件中或網絡上獲得序列化后的對象字節流后,根據字節流中所保存的對象狀態及描述信息,通過反序列化重建對象。

  4- 序列化就是把實體對象狀態按照一定的格式寫入到有序字節流,反序列化就是從有序字節流重建對象,恢復對象狀態

 

import java.io.*;

public class SerializeDeepCloneTest {
    public static void main(String[] args) {
        SchoolSeri sch = new SchoolSeri("zjut",new StudentSeri("tyj"));
        SchoolSeri schSeri = null;
        System.out.println(sch);
        try {
            schSeri = SerializeDeepCloneUtil.deepClone(sch);
            System.out.println(sch);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(sch == schSeri);
    }
}

class SerializeDeepCloneUtil{

    //序列化深克隆
    static <T extends Serializable> T deepClone(T obj){
        if(obj ==null){
            return null;
        }

        T cloneObj = null;

        //序列化
        ByteArrayOutputStream bout = null;
        ObjectOutputStream oos = null;
        try {
            //創建字節數組輸出流
            //new ByteArrayOutputStream() Creates a new byte array output stream.
            bout = new ByteArrayOutputStream();
            //創建對象輸出流
            //new ObjectOutputStream(OutputStream out): Creates an ObjectOutputStream that writes to the specified OutputStream.
            oos = new ObjectOutputStream(bout);
            //向對象輸出流中寫數據
            //void writeObject(Object obj): Write the specified object to the ObjectOutputStream.
            oos.writeObject(obj);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            close(oos);
            close(bout);
        }

        //反序列化
        ByteArrayInputStream bin = null;
        ObjectInputStream ois = null;

        try {
            //創建字節數組輸入流
            //new ByteArrayInputStream(byte buf[]): Creates a ByteArrayInputStream so that it  uses buf as its buffer array.
            bin = new ByteArrayInputStream(bout.toByteArray());
            //創建對象輸入流
            //new  ObjectInputStream(InputStream in): Creates an ObjectInputStream that reads from the specified InputStream.
            ois = new ObjectInputStream(bin);
            //從對象輸入流中讀取數據
            //Object readObject(): Read an object from the ObjectInputStream.
            cloneObj = (T)ois.readObject();

        } catch (IOException  | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            close(ois);
            close(bin);
        }
        return cloneObj;
    }


    //關閉流
    private static void close(Closeable closeable){
        if(closeable != null){
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

 

 

public class SchoolSeri implements Serializable{
    private String name;
    private StudentSeri stu;

    public SchoolSeri(String name, StudentSeri stu) {
        this.name = name;
        this.stu = stu;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public StudentSeri getStu() {
        return stu;
    }

    public void setStu(StudentSeri stu) {
        this.stu = stu;
    }

    @Override
    public String toString() {
        return "School{" +
                "name='" + name + '\'' +
                ", stu=" + stu +
                '}';
    }
}

public class StudentSeri implements Serializable{

    private String name;

    public StudentSeri(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

 

END

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM