<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 對象的克隆——原型模式(三) 7.4 帶附件的周報 通過引入原型模式,Sunny軟件公司OA系統支持工作周報的快速克隆,極大提高了工作周報的編寫效率,受到員工的一致好評。但有員工又發現一個問題,有些工作周報帶有附件,例如經理助理“小龍女”的周報通常附有本周項目進展報告匯總表、本周客戶反饋信息匯總表等,如果使用上述原型模式來復制周報,周報雖然可以復制,但是周報的附件并不能復制,這是由于什么原因導致的呢?如何才能實現周報和附件的同時復制呢?我們在本節將討論如何解決這些問題。 在回答這些問題之前,先介紹一下兩種不同的克隆方法,淺克隆(ShallowClone)和深克隆(DeepClone)。在Java語言中,數據類型分為值類型(基本數據類型)和引用類型,值類型包括int、double、byte、boolean、char等簡單數據類型,引用類型包括類、接口、數組等復雜類型。淺克隆和深克隆的主要區別在于是否支持引用類型的成員變量的復制,下面將對兩者進行詳細介紹。 1.淺克隆 在淺克隆中,如果原型對象的成員變量是值類型,將復制一份給克隆對象;如果原型對象的成員變量是引用類型,則將引用對象的地址復制一份給克隆對象,也就是說原型對象和克隆對象的成員變量指向相同的內存地址。簡單來說,在淺克隆中,當對象被復制時只復制它本身和其中包含的值類型的成員變量,而引用類型的成員對象并沒有復制,如圖7-4所示: ![](http://my.csdn.net/uploads/201204/03/1333464896_9252.gif) 圖7-4 淺克隆示意圖 在Java語言中,通過覆蓋Object類的clone()方法可以實現淺克隆。為了讓大家更好地理解淺克隆和深克隆的區別,我們首先使用淺克隆來實現工作周報和附件類的復制,其結構如圖7-5所示: ![](http://my.csdn.net/uploads/201204/03/1333464920_5154.gif) 圖7-5 帶附件的周報結構圖(淺克隆) 附件類Attachment代碼如下: ``` //附件類 class Attachment { private String name; //附件名 public void setName(String name) { this.name = name; } public String getName() { return this.name; } public void download() { System.out.println("下載附件,文件名為" + name); } } ``` 修改工作周報類WeeklyLog,修改后的代碼如下: ``` //工作周報WeeklyLog class WeeklyLog implements Cloneable { //為了簡化設計和實現,假設一份工作周報中只有一個附件對象,實際情況中可以包含多個附件,可以通過List等集合對象來實現 private Attachment attachment; private String name; private String date; private String content; public void setAttachment(Attachment attachment) { this.attachment = attachment; } public void setName(String name) { this.name = name; } public void setDate(String date) { this.date = date; } public void setContent(String content) { this.content = content; } public Attachment getAttachment(){ return (this.attachment); } public String getName() { return (this.name); } public String getDate() { return (this.date); } public String getContent() { return (this.content); } //使用clone()方法實現淺克隆 public WeeklyLog clone() { Object obj = null; try { obj = super.clone(); return (WeeklyLog)obj; } catch(CloneNotSupportedException e) { System.out.println("不支持復制!"); return null; } } } ``` 客戶端代碼如下所示: ``` class Client { public static void main(String args[]) { WeeklyLog log_previous, log_new; log_previous = new WeeklyLog(); //創建原型對象 Attachment attachment = new Attachment(); //創建附件對象 log_previous.setAttachment(attachment); //將附件添加到周報中 log_new = log_previous.clone(); //調用克隆方法創建克隆對象 //比較周報 System.out.println("周報是否相同? " + (log_previous == log_new)); //比較附件 System.out.println("附件是否相同? " + (log_previous.getAttachment() == log_new.getAttachment())); } } ``` 編譯并運行程序,輸出結果如下: ``` 周報是否相同? false 附件是否相同? true ``` 由于使用的是淺克隆技術,因此工作周報對象復制成功,通過“==”比較原型對象和克隆對象的內存地址時輸出false;但是比較附件對象的內存地址時輸出true,說明它們在內存中是同一個對象。 2.深克隆 在深克隆中,無論原型對象的成員變量是值類型還是引用類型,都將復制一份給克隆對象,深克隆將原型對象的所有引用對象也復制一份給克隆對象。簡單來說,在深克隆中,除了對象本身被復制外,對象所包含的所有成員變量也將復制,如圖7-6所示: ![](http://my.csdn.net/uploads/201204/03/1333464924_1911.gif) 圖7-6 深克隆示意圖 在Java語言中,如果需要實現深克隆,可以通過序列化(Serialization)等方式來實現。序列化就是將對象寫到流的過程,寫到流中的對象是原有對象的一個拷貝,而原對象仍然存在于內存中。通過序列化實現的拷貝不僅可以復制對象本身,而且可以復制其引用的成員對象,因此通過序列化將對象寫到一個流中,再從流里將其讀出來,可以實現深克隆。需要注意的是能夠實現序列化的對象其類必須實現Serializable接口,否則無法實現序列化操作。下面我們使用深克隆技術來實現工作周報和附件對象的復制,由于要將附件對象和工作周報對象都寫入流中,因此兩個類均需要實現Serializable接口,其結構如圖7-7所示: ![](http://my.csdn.net/uploads/201204/03/1333464931_1578.gif) 圖7-7 帶附件的周報結構圖(深克隆) 修改后的附件類Attachment代碼如下: ``` import java.io.*; //附件類 class Attachment implements Serializable { private String name; //附件名 public void setName(String name) { this.name = name; } public String getName() { return this.name; } public void download() { System.out.println("下載附件,文件名為" + name); } } ``` 工作周報類WeeklyLog不再使用Java自帶的克隆機制,而是通過序列化來從頭實現對象的深克隆,我們需要重新編寫clone()方法,修改后的代碼如下: ``` import java.io.*; //工作周報類 class WeeklyLog implements Serializable { private Attachment attachment; private String name; private String date; private String content; public void setAttachment(Attachment attachment) { this.attachment = attachment; } public void setName(String name) { this.name = name; } public void setDate(String date) { this.date = date; } public void setContent(String content) { this.content = content; } public Attachment getAttachment(){ return (this.attachment); } public String getName() { return (this.name); } public String getDate() { return (this.date); } public String getContent() { return (this.content); } //使用序列化技術實現深克隆 public WeeklyLog deepClone() throws IOException, ClassNotFoundException, OptionalDataException { //將對象寫入流中 ByteArrayOutputStream bao=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(bao); oos.writeObject(this); //將對象從流中取出 ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray()); ObjectInputStream ois=new ObjectInputStream(bis); return (WeeklyLog)ois.readObject(); } } ``` 客戶端代碼如下所示: ``` class Client { public static void main(String args[]) { WeeklyLog log_previous, log_new = null; log_previous = new WeeklyLog(); //創建原型對象 Attachment attachment = new Attachment(); //創建附件對象 log_previous.setAttachment(attachment); //將附件添加到周報中 try { log_new = log_previous.deepClone(); //調用深克隆方法創建克隆對象 } catch(Exception e) { System.err.println("克隆失敗!"); } //比較周報 System.out.println("周報是否相同? " + (log_previous == log_new)); //比較附件 System.out.println("附件是否相同? " + (log_previous.getAttachment() == log_new.getAttachment())); } } ``` 編譯并運行程序,輸出結果如下: ``` 周報是否相同? false 附件是否相同? false ``` 從輸出結果可以看出,由于使用了深克隆技術,附件對象也得以復制,因此用“==”比較原型對象的附件和克隆對象的附件時輸出結果均為false。深克隆技術實現了原型對象和克隆對象的完全獨立,對任意克隆對象的修改都不會給其他對象產生影響,是一種更為理想的克隆實現方式。 擴展 > Java語言提供的Cloneable接口和Serializable接口的代碼非常簡單,它們都是空接口,這種空接口也稱為標識接口,標識接口中沒有任何方法的定義,其作用是告訴JRE這些接口的實現類是否具有某個功能,如是否支持克隆、是否支持序列化等。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看