亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java中的深拷貝和淺拷貝介紹

2019-11-26 15:36:08
字體:
來源:轉載
供稿:網友

一、引言
   對象拷貝(Object Copy)就是將一個對象的屬性拷貝到另一個有著相同類類型的對象中去。在程序中拷貝對象是很常見的,主要是為了在新的上下文環境中復用對象的部分或全部 數據。Java中有三種類型的對象拷貝:淺拷貝(Shallow Copy)、深拷貝(Deep Copy)、延遲拷貝(Lazy Copy)。

二、淺拷貝

1、什么是淺拷貝
   淺拷貝是按位拷貝對象,它會創建一個新對象,這個對象有著原始對象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是內存地址(引用類型),拷貝的就是內存地址 ,因此如果其中一個對象改變了這個地址,就會影響到另一個對象。


  在圖中,SourceObject有一個int類型的屬性 "field1"和一個引用類型屬性"refObj"(引用ContainedObject類型的對象)。當對SourceObject做淺拷貝時,創建了CopiedObject,它有一個包含"field1"拷貝值的屬性"field2"以及仍指向refObj本身的引用。由于"field1"是基本類型,所以只是將它的值拷貝給"field2",但是由于"refObj"是一個引用類型, 所以CopiedObject指向"refObj"相同的地址。因此對SourceObject中的"refObj"所做的任何改變都會影響到CopiedObject。

2、如何實現淺拷貝

下面是實現淺拷貝的一個例子

復制代碼 代碼如下:

public class Subject {
    private String name;
   public Subject(String s) {
      name = s;
   }
   public String getName() {
      return name;
   }
   public void setName(String s) {
      name = s;
   }
}
public class Student implements Cloneable {
    // 對象引用
   private Subject subj;

   private String name;

   public Student(String s, String sub) {
      name = s;
      subj = new Subject(sub);
   }

   public Subject getSubj() {
      return subj;
   }

   public String getName() {
      return name;
   }

   public void setName(String s) {
      name = s;
   }

   /**
    *  重寫clone()方法
    * @return
    */
   public Object clone() {
      //淺拷貝
      try {
         // 直接調用父類的clone()方法
         return super.clone();
      } catch (CloneNotSupportedException e) {
         return null;
      }
   }
}
public class CopyTest {
    public static void main(String[] args) {
        // 原始對象
        Student stud = new Student("John", "Algebra");
        System.out.println("Original Object: " + stud.getName() + " - " + stud.getSubj().getName());
        // 拷貝對象
        Student clonedStud = (Student) stud.clone();
        System.out.println("Cloned Object: " + clonedStud.getName() + " - " + clonedStud.getSubj().getName());
        // 原始對象和拷貝對象是否一樣:
        System.out.println("Is Original Object the same with Cloned Object: " + (stud == clonedStud));
        // 原始對象和拷貝對象的name屬性是否一樣
        System.out.println("Is Original Object's field name the same with Cloned Object: " +
     (stud.getName() == clonedStud.getName()));
        // 原始對象和拷貝對象的subj屬性是否一樣
        System.out.println("Is Original Object's field subj the same with Cloned Object: " +
    (stud.getSubj() == clonedStud.getSubj()));
        stud.setName("Dan");
        stud.getSubj().setName("Physics");
        System.out.println("Original Object after it is updated: " + stud.getName() + " - " +
     stud.getSubj().getName());
        System.out.println("Cloned Object after updating original object: " + clonedStud.getName() +
     " - " + clonedStud.getSubj().getName());
    }
}

輸出結果如下:
 Original Object: John - Algebra
 Cloned Object: John - Algebra
 Is Original Object the same with Cloned Object: false
 Is Original Object's field name the same with Cloned Object: true
 Is Original Object's field subj the same with Cloned Object: true
 Original Object after it is updated: Dan - Physics
 Cloned Object after updating original object: John - Physics

     在這個例子中,我讓要拷貝的類Student實現了Clonable接口并重寫Object類的clone()方法,然后在方法內部調用super.clone()方法。從輸出結果中我們可以看到,對原始對象stud的"name"屬性所做的改變并沒有影響到拷貝對象clonedStud,但是對引用對象subj的"name"屬性所做的改變影響到了拷貝對象clonedStud。

三、深拷貝
1、什么是深拷貝
   深拷貝會拷貝所有的屬性,并拷貝屬性指向的動態分配的內存。當對象和它所引用的對象一起拷貝時即發生深拷貝。深拷貝相比于淺拷貝速度較慢并且花銷較大。



在上圖中,SourceObject有一個int類型的屬性 "field1"和一個引用類型屬性"refObj1"(引用ContainedObject類型的對象)。當對SourceObject做深拷貝時,創建了CopiedObject,它有一個包含"field1"拷貝值的屬性"field2"以及包含"refObj1"拷貝值的引用類型屬性"refObj2" 。因此對SourceObject中的"refObj"所做的任何改變都不會影響到CopiedObject

2、如何實現深拷貝
   下面是實現深拷貝的一個例子。只是在淺拷貝的例子上做了一點小改動,Subject 和CopyTest 類都沒有變化。

復制代碼 代碼如下:

public class Student implements Cloneable {
   // 對象引用
   private Subject subj;

   private String name;

   public Student(String s, String sub) {
      name = s;
      subj = new Subject(sub);
   }

   public Subject getSubj() {
      return subj;
   }

   public String getName() {
      return name;
   }

   public void setName(String s) {
      name = s;
   }

   /**
    * 重寫clone()方法
    *
    * @return
    */
   public Object clone() {
      // 深拷貝,創建拷貝類的一個新對象,這樣就和原始對象相互獨立
      Student s = new Student(name, subj.getName());
      return s;
   }
}

輸出結果如下:
  Original Object: John - Algebra
 Cloned Object: John - Algebra
 Is Original Object the same with Cloned Object: false
 Is Original Object's field name the same with Cloned Object: true
 Is Original Object's field subj the same with Cloned Object: false
 Original Object after it is updated: Dan - Physics
 Cloned Object after updating original object: John - Algebra

  很容易發現clone()方法中的一點變化。因為它是深拷貝,所以你需要創建拷貝類的一個對象。因為在Student類中有對象引用,所以需要在Student類中實現Cloneable接口并且重寫clone方法。

3、通過序列化實現深拷貝
    也可以通過序列化來實現深拷貝。序列化是干什么的?它將整個對象圖寫入到一個持久化存儲文件中并且當需要的時候把它讀取回來, 這意味著當你需要把它讀取回來時你需要整個對象圖的一個拷貝。這就是當你深拷貝一個對象時真正需要的東西。請注意,當你通過序列化進行深拷貝時,必須確保對象圖中所有類都是可序列化的。

復制代碼 代碼如下:

public class ColoredCircle implements Serializable {
   private int x;
   private int y;

   public ColoredCircle(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }

   @Override
   public String toString() {
      return "x=" + x + ", y=" + y;
   }
}
public class DeepCopy {

   public static void main(String[] args) throws IOException {
      ObjectOutputStream oos = null;
      ObjectInputStream ois = null;

      try {
         // 創建原始的可序列化對象
         ColoredCircle c1 = new ColoredCircle(100, 100);
         System.out.println("Original = " + c1);

         ColoredCircle c2 = null;

         // 通過序列化實現深拷貝
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         oos = new ObjectOutputStream(bos);
         // 序列化以及傳遞這個對象
         oos.writeObject(c1);
         oos.flush();
         ByteArrayInputStream bin = new ByteArrayInputStream(bos.toByteArray());
         ois = new ObjectInputStream(bin);
         // 返回新的對象
         c2 = (ColoredCircle) ois.readObject();

         // 校驗內容是否相同
         System.out.println("Copied   = " + c2);
         // 改變原始對象的內容
         c1.setX(200);
         c1.setY(200);
         // 查看每一個現在的內容
         System.out.println("Original = " + c1);
         System.out.println("Copied   = " + c2);
      } catch (Exception e) {
         System.out.println("Exception in main = " + e);
      } finally {
         oos.close();
         ois.close();
      }
   }
}

輸出結果如下:
 Original = x=100, y=100
 Copied = x=100, y=100
 Original = x=200, y=200
 Copied = x=100, y=100
這里,你只需要做以下幾件事兒:
(1)確保對象圖中的所有類都是可序列化的
(2)創建輸入輸出流
(3)使用這個輸入輸出流來創建對象輸入和對象輸出流
(4)將你想要拷貝的對象傳遞給對象輸出流
(5)從對象輸入流中讀取新的對象并且轉換回你所發送的對象的類

    在這個例子中,我創建了一個ColoredCircle對象c1然后將它序列化 (將它寫到ByteArrayOutputStream中). 然后我反序列化這個序列化后的對象并將它保存到c2中。隨后我修改了原始對象c1。然后結果如你所見,c1不同于c2,對c1所做的任何修改都不會影響c2。

注意,序列化這種方式有其自身的限制和問題:
因為無法序列化transient變量, 使用這種方法將無法拷貝transient變量。

   再就是性能問題。創建一個socket, 序列化一個對象, 通過socket傳輸它, 然后反序列化它,這個過程與調用已有對象的方法相比是很慢的。所以在性能上會有天壤之別。如果性能對你的代碼來說是至關重要的,建議不要使用這種方式。它比通過實現Clonable接口這種方式來進行深拷貝幾乎多花100倍的時間。

四、延遲拷貝
   延遲拷貝是淺拷貝和深拷貝的一個組合,實際上很少會使用。 當最開始拷貝一個對象時,會使用速度較快的淺拷貝,還會使用一個計數器來記錄有多少對象共享這個數據。當程序想要修改原始的對象時,它會決定數據是否被共享(通過檢查計數器)并根據需要進行深拷貝。
   延遲拷貝從外面看起來就是深拷貝,但是只要有可能它就會利用淺拷貝的速度。當原始對象中的引用不經常改變的時候可以使用延遲拷貝。由于存在計數器,效率下降很高,但只是常量級的開銷。而且, 在某些情況下, 循環引用會導致一些問題。

五、如何選擇
  如果對象的屬性全是基本類型的,那么可以使用淺拷貝,但是如果對象有引用屬性,那就要基于具體的需求來選擇淺拷貝還是深拷貝。我的意思是如果對象引用任何時候都不會被改變,那么沒必要使用深拷貝,只需要使用淺拷貝就行了。如果對象引用經常改變,那么就要使用深拷貝。沒有一成不變的規則,一切都取決于具體需求。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品视频专区| 久久久国产成人精品| 91国产精品电影| 欧美黑人一级爽快片淫片高清| 成人黄色av免费在线观看| 久久久999精品视频| 亚洲国产成人在线视频| 久久视频在线免费观看| 91麻豆桃色免费看| 亚洲国产欧美自拍| 欧美激情一区二区三区成人| 色偷偷亚洲男人天堂| 亚洲第一网站男人都懂| 亚洲国产又黄又爽女人高潮的| 91sao在线观看国产| 日韩美女福利视频| 国产一区av在线| 久久天天躁狠狠躁夜夜爽蜜月| 成人免费观看网址| 国产欧亚日韩视频| 久久久久久久网站| 国产乱人伦真实精品视频| 久久久久久久影院| 国模私拍一区二区三区| 国产精品高清在线| 国产精品久久久久久久久免费| 一区二区三区久久精品| 欧美成人三级视频网站| 亚洲第一网站男人都懂| 欧美最猛性xxxxx亚洲精品| 国产一级揄自揄精品视频| 高潮白浆女日韩av免费看| 992tv成人免费视频| 国产欧美亚洲精品| 福利二区91精品bt7086| 色综合91久久精品中文字幕| 国产精品高潮呻吟久久av野狼| 国产精品久久久久久久久久| 国产精品视频白浆免费视频| 久久躁日日躁aaaaxxxx| 亚洲午夜未满十八勿入免费观看全集| 精品久久久久久电影| 欧美性69xxxx肥| 欧美交受高潮1| 欧美日韩免费区域视频在线观看| 久久伊人免费视频| 欧美激情一二区| 久久精品男人天堂| 精品久久久久久久久久久久| 日本中文字幕成人| 亚洲精品久久久久久久久久久久久| 亚洲精品国产成人| 久久久久久97| 欧美日韩国产成人高清视频| 91国产视频在线| 亚洲人精品午夜在线观看| 欧美激情国产日韩精品一区18| 欧美一级淫片丝袜脚交| 日韩高清免费观看| 欧美极品美女电影一区| 黑人与娇小精品av专区| 精品高清美女精品国产区| 欧美一区三区三区高中清蜜桃| 色哟哟亚洲精品一区二区| 91久久嫩草影院一区二区| 亚洲国产欧美一区二区三区久久| 最近2019年好看中文字幕视频| 国产精品一区二区久久久久| 亚洲日韩欧美视频一区| 欧美日韩午夜视频在线观看| 91精品久久久久久久久久另类| 欧美激情久久久| 成人免费高清完整版在线观看| 日韩在线视频国产| 成人网在线免费看| 欧美成人国产va精品日本一级| 97香蕉超级碰碰久久免费的优势| 久久色在线播放| 一本一本久久a久久精品牛牛影视| 日本aⅴ大伊香蕉精品视频| 亚洲国产精品福利| 国产精品狠色婷| 日韩在线视频播放| 国产亚洲一区精品| 久久久伊人日本| 亚洲精品永久免费精品| 久久久综合免费视频| 久久久国产一区二区三区| 亚洲第一精品电影| 精品国产自在精品国产浪潮| 久久精品国产清自在天天线| 久青草国产97香蕉在线视频| 久久久国产精彩视频美女艺术照福利| 亚洲爱爱爱爱爱| 日韩在线观看免费全| 欧美激情免费在线| 欧美人在线视频| 久久久久成人精品| 日韩在线视频网| 欧美疯狂做受xxxx高潮| 欧美疯狂xxxx大交乱88av| 91精品视频免费| 国产丝袜高跟一区| 久久精品视频网站| 亚洲人成在线电影| 国产精品电影一区| 国自产精品手机在线观看视频| 日韩精品中文字幕在线播放| 久久精品一偷一偷国产| 免费不卡在线观看av| 亚洲日本aⅴ片在线观看香蕉| 午夜伦理精品一区| 欧美性猛交xxxx久久久| 欧美日韩国产一区二区| 国语自产在线不卡| 欧美日韩国产限制| www.午夜精品| 亚洲欧美日韩国产中文专区| 午夜精品美女自拍福到在线| 国产精品99蜜臀久久不卡二区| 欧美日韩国产第一页| 九九热99久久久国产盗摄| 国产成人精品在线观看| 8090理伦午夜在线电影| 久久国产精品偷| 97精品久久久| 久久精品国产久精国产思思| 久久久99免费视频| 久久艳片www.17c.com| 欧美成人高清视频| 91精品国产自产在线观看永久| 久久夜精品va视频免费观看| 欧美性猛交丰臀xxxxx网站| 亚洲精品电影在线观看| 中文字幕欧美日韩精品| 在线视频精品一| 亚洲片av在线| 成人性教育视频在线观看| 欧美激情视频一区二区三区不卡| 黑人巨大精品欧美一区免费视频| 久久久久久久久综合| 国产精品久久久久久久一区探花| 97视频免费在线观看| 岛国视频午夜一区免费在线观看| 日韩中文字幕网站| 亚洲欧美日韩国产成人| 欧美激情高清视频| 欧美精品在线第一页| 久久国产一区二区三区| 亚洲精品videossex少妇| 亚洲成人av中文字幕| 国产精品视频网| 2019中文字幕免费视频| 91亚洲精华国产精华| 国产精品成人国产乱一区| 亚洲激情免费观看| 欧美另类第一页| 久久国产精品影视| 亚洲国产精品成人精品| 日韩欧美一区二区三区| 1769国产精品| 久久视频国产精品免费视频在线| 日韩免费视频在线观看| 久热在线中文字幕色999舞|