<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深克隆和淺克隆有什么區(qū)別?它的實(shí)現(xiàn)方式有哪些?

          共 4897字,需瀏覽 10分鐘

           ·

          2021-07-20 12:56

          什么是淺克隆和深克隆

          • 淺克隆(Shadow Clone)是把原型對象中成員變量為值類型的屬性都復(fù)制給克隆對象,把原型對象中成員變量為引用類型的引用地址也復(fù)制給克隆對象,也就是原型對象中如果有成員變量為引用對象,則此引用對象的地址是共享給原型對象和克隆對象的。

          • 簡單來說就是淺克隆只會復(fù)制原型對象,但不會復(fù)制它所引用的對象

          • 深克隆(Deep Clone)是將原型對象中的所有類型,無論是值類型還是引用類型,都復(fù)制一份給克隆對象,也就是說深克隆會把原型對象和原型對象所引用的對象,都復(fù)制一份給克隆對象,如下圖所示:


          如何實(shí)現(xiàn)克隆

          在 Java 語言中要實(shí)現(xiàn)克隆則需要實(shí)現(xiàn) Cloneable 接口,并重寫 Object 類中的 clone() 方法,實(shí)現(xiàn)代碼如下:

          public class CloneExample {

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

                  // 創(chuàng)建被賦值對象

                  People p1 = new People();

                  p1.setId(1);

                  p1.setName("Java");

                  // 克隆 p1 對象

                  People p2 = (People) p1.clone();

                  // 打印名稱

                  System.out.println("p2:" + p2.getName());

              }

              static class People implements Cloneable {

                  // 屬性

                  private Integer id;

                  private String name;

                  /**

                   * 重寫 clone 方法

                   * @throws CloneNotSupportedException

                   */


                  @Override

                  protected Object clone() throws CloneNotSupportedException {

                      return super.clone();

                  }

                  public Integer getId() {

                      return id;

                  }

                  public void setId(Integer id) {

                      this.id = id;

                  }

                  public String getName() {

                      return name;

                  }

                  public void setName(String name) {

                      this.name = name;

                  }

              }

          }

          執(zhí)行結(jié)果為:

          p2:Java

          在 java.lang.Object 中對 clone() 方法的約定有哪些?

          • 對于所有對象來說,x.clone() !=x 應(yīng)當(dāng)返回 true,因?yàn)榭寺ο笈c原對象不是同一個(gè)對象;

          • 對于所有對象來說,x.clone().getClass() == x.getClass() 應(yīng)當(dāng)返回 true,因?yàn)榭寺ο笈c原對象的類型是一樣的;

          • 對于所有對象來說,x.clone().equals(x) 應(yīng)當(dāng)返回 true,因?yàn)槭褂?equals 比較時(shí),它們的值都是相同的。

          Arrays.copyOf() 是深克隆還是淺克???

          • 如果是數(shù)組類型,我們可以直接使用 Arrays.copyOf() 來實(shí)現(xiàn)克隆,實(shí)現(xiàn)代碼如下:

          People[] o1 = {new People(1"Java")};

          People[] o2 = Arrays.copyOf(o1, o1.length);

          // 修改原型對象的第一個(gè)元素的值

          o1[0].setName("Jdk");

          System.out.println("o1:" + o1[0].getName());

          System.out.println("o2:" + o2[0].getName());

          執(zhí)行結(jié)果:

          o1:Jdk

          o2:Jdk
          • 從結(jié)果可以看出,我們在修改克隆對象的第一個(gè)元素之后,原型對象的第一個(gè)元素也跟著被修改了,這說明 Arrays.copyOf() 其實(shí)是一個(gè)淺克隆。

          • 因?yàn)閿?shù)組比較特殊數(shù)組本身就是引用類型,因此在使用 Arrays.copyOf() 其實(shí)只是把引用地址復(fù)制了一份給克隆對象,如果修改了它的引用對象,那么指向它的(引用地址)所有對象都會發(fā)生改變,因此看到的結(jié)果是,修改了克隆對象的第一個(gè)元素,原型對象也跟著被修改了。

          深克隆的實(shí)現(xiàn)方式有幾種?

          • 所有對象都實(shí)現(xiàn)克隆方法;

          • 通過構(gòu)造方法實(shí)現(xiàn)深克隆;

          • 使用 JDK 自帶的字節(jié)流實(shí)現(xiàn)深克隆;

          • 使用第三方工具實(shí)現(xiàn)深克隆,比如 Apache Commons Lang;

          • 使用 JSON 工具類實(shí)現(xiàn)深克隆,比如 Gson、FastJSON 等。

          具體代碼實(shí)現(xiàn)方式可以查看:
          https://shimo.im/docs/L9kBMnZ56GTnDRqK/ 《深克隆和淺克隆有什么區(qū)別?它的實(shí)現(xiàn)方式有哪些?》,可復(fù)制鏈接后用石墨文檔 App 或小程序打開

          Java 中的克隆為什么要設(shè)計(jì)成,既要實(shí)現(xiàn)空接口 Cloneable,還要重寫 Object 的 clone() 方法?

          • Java 中實(shí)現(xiàn)克隆需要兩個(gè)主要的步驟,一是 實(shí)現(xiàn) Cloneable 空接口,二是重寫 Object 的 clone() 方法再調(diào)用父類的克隆方法 (super.clone())

          從源碼中可以看出 Cloneable 接口誕生的比較早,JDK 1.0 就已經(jīng)存在了,因此從那個(gè)時(shí)候就已經(jīng)有克隆方法了,那我們怎么來標(biāo)識一個(gè)類級別對象擁有克隆方法呢?克隆雖然重要,但我們不能給每個(gè)類都默認(rèn)加上克隆,這顯然是不合適的,那我們能使用的手段就只有這幾個(gè)了:

          • 在類上新增標(biāo)識,此標(biāo)識用于聲明某個(gè)類擁有克隆的功能,像 final 關(guān)鍵字一樣;

          • 使用 Java 中的注解;

          • 實(shí)現(xiàn)某個(gè)接口;

          • 繼承某個(gè)類。

          第一個(gè),為了一個(gè)重要但不常用的克隆功能, 單獨(dú)新增一個(gè)類標(biāo)識,這顯然不合適;第二個(gè),因?yàn)榭寺」δ艹霈F(xiàn)的比較早,那時(shí)候還沒有注解功能,因此也不能使用;第三點(diǎn)基本滿足我們的需求,第四點(diǎn)和第一點(diǎn)比較類似,為了一個(gè)克隆功能需要犧牲一個(gè)基類,并且 Java 只能單繼承,因此這個(gè)方案也不合適。采用排除法,無疑使用實(shí)現(xiàn)接口的方式是那時(shí)最合理的方案了,而且在 Java 語言中一個(gè)類可以實(shí)現(xiàn)多個(gè)接口。

          • 那為什么要在 Object 中添加一個(gè) clone() 方法呢?

          因?yàn)?clone() 方法語義的特殊性,因此最好能有 JVM 的直接支持,既然要 JVM 直接支持,就要找一個(gè) API 來把這個(gè)方法暴露出來才行,最直接的做法就是把它放入到一個(gè)所有類的基類 Object 中,這樣所有類就可以很方便地調(diào)用到了。


          瀏覽 58
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色激情在线观看小视频 | 人人操操人人操操 | 国产精品成人久久久久久久 | 激情欧美在线 | 小黄片在线免费观看 |