<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 深拷貝與淺拷貝 ### 一、何謂 “object clone” > 顧名思義clone就是一個相同東西的副本,是一個具體存在的復制體,是一個從生物科學開始變得熟悉的術語。在計算機行業,該術語被廣泛用于指Compaq,戴爾等人對IBM PC的模仿。而在java語言中,clone方法被對象調用,所以會復制對象。 ### 二、object clone的用法 (1)方法摘要 | 作用域 | 類型 | 方法 | 描述 | | --- | --- | --- | --- | | protected | Object | clone() | 克隆實現了Cloneable接口的對象 | 注意事項:clone方法是被native修飾的,簡單的講就是被Native修飾的方法在被調用時指向的是一個非java代碼的具體實現,這個實現可能是其他語言或者操作系統。 (2)clone規則: ~~~ 1、 基本類型 如果變量是基本類型,則拷貝其值,比如int、float等。 2、 對象 如果變量是一個實例對象,則拷貝其地址引用,也就是說新對象和原來對象是共用實例變量的。 3、 String字符串 若變量為String字符串,則拷貝其地址引用。但是在修改時,它會從字符串池中重新生成一個新的字符串,原有的對象保持不變。復制代碼 ~~~ (2)示例1: ~~~ 實現clone方法的步驟: 1. 實現Cloneable接口 2. 重載Object類中的clone()方法,重載時需定義為public 3. 在重載方法中,調用super.clone()復制代碼 ~~~ ~~~ public class Book implements Cloneable { private int id; private String name; public Book() {} public Book(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Object clone() throws CloneNotSupportedException { return (Book)super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { Book book1 = new Book(); book1.setName("基礎系列1"); Book book2 = (Book) book1.clone(); System.out.println("圖書1:" + book1.getName()); System.out.println("圖書2:" + book2.getName()); book2.setName("基礎系列2"); System.out.println("圖書1:" + book1.getName()); System.out.println("圖書2:" + book2.getName()); } }復制代碼 ~~~ 運行結果: ~~~ 圖書1:基礎系列1 圖書2:基礎系列1 圖書1:基礎系列1 圖書2:基礎系列2復制代碼 ~~~ 從運行結果看這應該是深克隆的,但為什么是淺克隆呢?從*string不可變*(原對象和克隆對象中的string屬性引用的是同一地址)的角度出發結果應該是淺克隆,但從結果出發卻又是深克隆,所以從這一角度來說clone對string是深克隆。 注意事項:如果沒有implements Cloneable的類調用Object.clone()方法就會拋出CloneNotSupportedException (3)示例2: ~~~ public class Book implements Cloneable { //在示例1的基礎上增加bookBorrow的引用 private BookBorrow bookBorrow; public Book() {} public Book(int id, String name, BookBorrow bookBorrow) { this.id = id; this.name = name; this.bookBorrow = bookBorrow; } public BookBorrow getBookBorrow() { return bookBorrow; } public void setBookBorrow(BookBorrow bookBorrow) { this.bookBorrow = bookBorrow; } @Override public Object clone() throws CloneNotSupportedException { Book book = (Book)super.clone(); //這里注釋掉就是淺克隆,否則就是深克隆 book.bookBorrow = (BookBorrow)bookBorrow.clone(); return book; } @Override public String toString() { return "BOOK[id="+id+",name="+name+",bookBorrow:"+bookBorrow+"]"; } public static void main(String[] args) throws CloneNotSupportedException { BookBorrow bookBorrow = new BookBorrow(1,1); Book book1 = new Book(1,"基礎系列1",bookBorrow); Book book2 = (Book) book1.clone(); System.out.println("圖書1:" + book1.toString()); System.out.println("圖書2:" + book2.toString()); book2.setName("基礎系列2"); book2.setBookBorrow(new BookBorrow(5,5)); System.out.println("圖書1:" + book1.toString()); System.out.println("圖書2:" + book2.toString()); } } public class BookBorrow implements Cloneable{ private int id; private int borstate; public BookBorrow(int id, int borstate) { this.id = id; this.borstate = borstate; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getBorstate() { return borstate; } public void setBorstate(int borstate) { this.borstate = borstate; } @Override public Object clone() throws CloneNotSupportedException { return (BookBorrow)super.clone(); } @Override public String toString() { return "BookBorrow[id="+id+",borstate="+borstate+"]"; } }復制代碼 ~~~ 運行結果: ~~~ 圖書1:BOOK[id=1,name=基礎系列1,bookBorrow:BookBorrow[id=1,borstate=1]] 圖書2:BOOK[id=1,name=基礎系列1,bookBorrow:BookBorrow[id=1,borstate=1]] 圖書1:BOOK[id=1,name=基礎系列1,bookBorrow:BookBorrow[id=1,borstate=1]] 圖書2:BOOK[id=1,name=基礎系列2,bookBorrow:BookBorrow[id=5,borstate=5]]復制代碼 ~~~ 從結果看這里是一個標準的深克隆實現,深克隆實現的一個主要前提是當前對象引用的對象或對象的對象引用的對象都實現了*常規用法1*并且在重載clone方法中調用其引用對象的clone方法。 例: ~~~ @Override public Object clone() throws CloneNotSupportedException { Book book = (Book)super.clone(); //這里注釋掉就是淺克隆,否則就是深克隆 book.bookBorrow = (BookBorrow)bookBorrow.clone(); return book; }復制代碼 ~~~ 注意事項:示例2給出的例子是相對簡單且常見的類,在實際開發中clone的對象可能依賴第三方的jar包或者引用層級過深不好修改的對象,如果是這種情況則建議采用示例3的做法,使用序列化clone。 (3)示例3: 序列化clone類 ~~~ public class CloneUtils { public static <T extends Serializable> T clone(T obj){ T cloneObj = null; try { //寫入字節流 ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream obs = new ObjectOutputStream(out); obs.writeObject(obj); obs.close(); //分配內存,寫入原始對象,生成新對象 ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray()); ObjectInputStream ois = new ObjectInputStream(ios); //返回生成的新對象 cloneObj = (T) ois.readObject(); ois.close(); } catch (Exception e) { e.printStackTrace(); } return cloneObj; } } public class BookBorrow implements Serializable{ ... //去掉clone方法,繼承Serializable } public class Book implements Serializable { ... //去掉clone方法,繼承Serializable public static void main(String[] args) throws CloneNotSupportedException { BookBorrow bookBorrow = new BookBorrow(1,1); Book book1 = new Book(1,"基礎系列1",bookBorrow); Book book2 = CloneUtils.clone(book1); System.out.println("圖書1:" + book1.toString()); System.out.println("圖書2:" + book2.toString()); book2.setName("基礎系列2"); book2.setBookBorrow(new BookBorrow(5,5)); System.out.println("圖書1:" + book1.toString()); System.out.println("圖書2:" + book2.toString()); } }復制代碼 ~~~ 執行結果: ~~~ 圖書1:BOOK[id=1,name=基礎系列1,bookBorrow:BookBorrow[id=1,borstate=1]] 圖書2:BOOK[id=1,name=基礎系列1,bookBorrow:BookBorrow[id=1,borstate=1]] 圖書1:BOOK[id=1,name=基礎系列1,bookBorrow:BookBorrow[id=1,borstate=1]] 圖書2:BOOK[id=1,name=基礎系列2,bookBorrow:BookBorrow[id=5,borstate=5]]復制代碼 ~~~ 序列化克隆無需繼承,通過序列化工具類可實現深克隆同等效果。然而克隆沒有銀彈,*序列化這種方式在效率上比之原clone有所不如*。 ### 二、object clone原理 *本次講解將基于示例1做出解釋:* 為了不丟失上下文而貼出的測試代碼,將會以2部分講解object clone的原理 ~~~ public static void main(String[] args) throws CloneNotSupportedException { //第一部分 Book book1 = new Book(); book1.setName("基礎系列1"); Book book2 = (Book) book1.clone(); System.out.println("圖書1:" + book1.getName()); System.out.println("圖書2:" + book2.getName()); //第二部分 book2.setName("基礎系列2"); System.out.println("圖書1:" + book1.getName()); System.out.println("圖書2:" + book2.getName()); }復制代碼 ~~~ **第一部分執行結果**: ~~~ 圖書1:基礎系列1 圖書2:基礎系列1復制代碼 ~~~ 淺克隆原理圖: :-: ![](https://box.kancloud.cn/f30033aec4be04b84b473b2b79fc8f31_730x421.jpg) 從圖中可以看出clone的name引用的是同一個值,那為什么前面又說是深克隆呢?原因就是在這一步中并沒有修改name所以他們是淺克隆,引用的是同一個name變量值。那接下來執行第二部分得出的結果和原理圖如你所想對象完全隔離了。 **第二部分執行結果**: ~~~ 圖書1:基礎系列1 圖書2:基礎系列2復制代碼 ~~~ 深克隆原理圖: :-: ![](https://box.kancloud.cn/fb7dc35ffc3fa6ab75aa67b0d8f35dca_730x421.jpg) 從圖可以看出修改了name屬性值,clone會從堆中重新生成一個對象被克隆對象引用,而原對象保持不變,從這一角度出發的確是深克隆。 ##### clone原理小結 : 前面的原理介紹是以示例1做為藍本介紹的,示例2 的原理和示例1類似,唯一區別是多了屬性對象而屬性對象在clone中也只會拷貝引用地址,要想實現深克隆就只能在引用的對象或引用對象的對象中中添加clone方法實現即可實現深克隆。 ### 三、object clone的實際用途 1、精心設計一個淺克隆對象被程序緩存,作為功能模塊模板;每次有用戶調用這個模塊則將可變部分替換成用戶需要的信息即可。 示例: 功能:發郵件 描述:給同組的用戶發送郵件,郵件內容相同(不可變)發送的用戶不同(可變) 2、精心設計一個深克隆對象本程序緩存,作為功能模塊的初始對象,例如:“游客模式”每個游客進入系統訪問的都是初始對象,基于初始對象發展出多條變化不一的游覽路線。只要你想的到設計巧妙,很多功能都能應用object clone。 ### 四、總結 本文分3部分介紹了object clone,分別介紹了clone的用法、原理和用途; object clone歸結就是可變和不可變兩個特性,在實際的開發中我們可以基于這2個特性設計出性能良好的功能模塊。 參考資料: * [細說 Java 的深拷貝和淺拷貝 - 承香墨影 - SegmentFault 思否](https://segmentfault.com/a/1190000010648514) * [(基礎系列)object clone 的用法、原理和用途 - 掘金](https://juejin.im/post/59bfc707f265da0646188bca)
                  <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>

                              哎呀哎呀视频在线观看