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

          深入理解淺拷貝和深拷貝

          共 2688字,需瀏覽 6分鐘

           ·

          2021-01-25 20:44

          0x01:概述

          Java中的對象拷貝 ( Object Copy ) 是指將一個對象的所有屬性(成員變量)拷貝到另一個有著相同類類型的對象中去。例如,對象 A 和對象 B 都屬于類 S,具有屬性 a 和 b。那么對對象 A 進行拷貝操作賦值給對象 B 就是:

          B.a?=?A.a;??
          B.b?=?A.b;

          拷貝對象是很常見的,主要是為了在新的上下文環(huán)境中復(fù)用現(xiàn)有對象的部分或全部數(shù)據(jù)。Java中的對象拷貝主要分為

          • 淺拷貝( Shallow Copy )

          • 深拷貝( Deep Copy )

          Java中的數(shù)據(jù)類型分為基本數(shù)據(jù)類型引用數(shù)據(jù)類型。對于這兩種數(shù)據(jù)類型,在進行賦值操作、用作方法參數(shù)或返回值時,會有值傳遞和引用(地址)傳遞的差別。

          淺拷貝(Shallow Copy)

          • 對于數(shù)據(jù)類型是基本數(shù)據(jù)類型的成員變量,淺拷貝會直接進行值傳遞,也就是將該屬性值復(fù)制一份給新的對象。因為是兩份不同的數(shù)據(jù),所以對其中一個對象的該成員變量值進行修改,不會影響另一個對象拷貝得到的數(shù)據(jù)。

          • 對于數(shù)據(jù)類型是引用數(shù)據(jù)類型的成員變量,比如說成員變量是某個數(shù)組、某個類的對象等,那么淺拷貝會進行引用傳遞,也就是只是將該成員變量的引用值(內(nèi)存地址)復(fù)制一份給新的對象。因為實際上兩個對象的該成員變量都指向同一個實例。在這種情況下,在一個對象中修改該成員變量會影響到另一個對象的該成員變量值。

          具體模型如下圖所示,可以看到基本數(shù)據(jù)類型的成員變量,對其值創(chuàng)建了新的拷貝;而引用數(shù)據(jù)類型的成員變量的實例仍然是只有一份,兩個對象的該成員變量都指向同一個實例。

          0x02:淺拷貝的實現(xiàn)方式

          • 拷貝構(gòu)造方法實現(xiàn)淺拷貝

          拷貝構(gòu)造方法指的是該類的構(gòu)造方法參數(shù)為該類的對象。使用拷貝構(gòu)造方法可以很好地完成淺拷貝,直接通過一個現(xiàn)有的對象創(chuàng)建出與該對象屬性相同的新的對象。

          • 重寫clone()方法進行淺拷貝

          Object類是類結(jié)構(gòu)的根類,其中有一個方法

          protected?Object?clone()?throws?CloneNotSupportedException

          這個方法就是進行的淺拷貝。有了這個淺拷貝模板,可以通過調(diào)用clone()方法來實現(xiàn)對象的淺拷貝。但是需要注意:

          (1)Object類雖然有這個方法,但是這個方法是受保護的(被protected修飾),所以無法直接使用。

          (2)使用clone方法的類必須實現(xiàn)Cloneable接口,否則會拋出異常CloneNotSupportedException。

          對于這兩點,我們的解決方法是:在要使用clone方法的類中重寫clone()方法,通過super.clone()調(diào)用Object類中的原clone方法。


          0x03:深拷貝的實現(xiàn)方式

          首先介紹對象圖的概念。設(shè)想一下,一個類有一個對象,其成員變量中又有一個對象,該對象指向另一個對象,另一個對象又指向另一個對象,直到一個確定的實例。這就形成了對象圖。那么對于深拷貝來說,不僅要復(fù)制對象的所有基本數(shù)據(jù)類型的成員變量值,還要為所有引用數(shù)據(jù)類型的成員變量申請存儲空間,并復(fù)制每個引用數(shù)據(jù)類型成員變量所引用的對象,直到該對象可達的所有對象。也就是說,對象進行深拷貝要對整個對象圖進行拷貝。

          一句話,深拷貝對引用數(shù)據(jù)類型的成員變量的對象圖中所有的對象都開辟了內(nèi)存空間;而淺拷貝只是傳遞地址指向,新的對象并沒有對引用數(shù)據(jù)類型創(chuàng)建內(nèi)存空間。深拷貝模型如下圖所示,可以看到所有的成員變量都進行了復(fù)制。

          因為創(chuàng)建內(nèi)存空間和拷貝整個對象圖,所以深拷貝相比于淺拷貝速度較慢并且花銷較大。

          • 重寫clone方法來實現(xiàn)深拷貝

          與通過重寫clone方法實現(xiàn)淺拷貝的基本思路一樣,只需要為對象圖的每一層的每一個對象都實現(xiàn)Cloneable接口并重寫clone方法,最后在最頂層的類的重寫的clone方法中調(diào)用所有的clone方法即可實現(xiàn)深拷貝。簡單的說只要每一層的每個對象都進行淺拷貝,就等于實現(xiàn)了深拷貝。

          @Override
          public?Object?clone()?{
          ????//深拷貝
          ????try?{
          ????????//?直接調(diào)用父類的clone()方法
          ????????Student?student?=?(Student)?super.clone();
          ????????student.引用對象?=?(引用對象)?引用對象.clone();
          ????????return?student;
          ????}?catch?(CloneNotSupportedException?e)?{
          ????????return?null;
          ????}
          }
          • 對象序列化實現(xiàn)深拷貝

          雖然層次調(diào)用clone方法可以實現(xiàn)深拷貝,但是顯然代碼量實在太大。特別對于屬性數(shù)量比較多、層次比較深的類而言,每個類都要重寫clone方法太過繁瑣。將對象序列化為字節(jié)序列后,默認(rèn)會將該對象的整個對象圖進行序列化,再通過反序列即可完美地實現(xiàn)深拷貝。

          //將對象寫入流中
          ByteArrayOutputStream?outputStream?=?new?ByteArrayOutputStream();
          ObjectOutputStream?objectOutputStream?=?new?ObjectOutputStream(outputStream);
          objectOutputStream.writeObject(拷貝對象);

          //從流中取出
          ByteArrayInputStream?inputStream?=?new?ByteArrayInputStream(outputStream.toByteArray());
          ObjectInputStream?objectInputStream?=?new?ObjectInputStream(inputStream);
          return?(拷貝對象)objectInputStream.readObject();
          • JSON或者XML方式實現(xiàn)深拷貝

          因為一個POJO對象可以通過JSON庫變成一個json字符串(通過XML庫變成一個xml字符串),再通過對應(yīng)的類庫又反序列化成另外一個完整的對象。

          String?json?=JSON.toJSONString(src);
          T?object?=?JSON.parseObject(json,?clazz);

          喜歡,在看

          +轉(zhuǎn)發(fā)

          瀏覽 46
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  伊人大香蕉在线免费 | 青草青青青视频 | 波多野结衣AV在线 | 国内免费av | 午夜看片无码 |