国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

使用序列化實現對象的拷貝

2019-11-11 02:41:10
字體:
來源:轉載
供稿:網友

我們知道在java中存在這個接口Cloneable,實現該接口的類都會具備被拷貝的能力,同時拷貝是在內存中進行,在性能方面比我們直接通過new生成對象來的快,特別是在大對象的生成上,使得性能的提升非常明顯。然而我們知道拷貝分為深拷貝和淺拷貝之分,但是淺拷貝存在對象屬性拷貝不徹底問題。關于深拷貝、淺拷貝的請參考這里:漸析java的淺拷貝和深拷貝

       一、淺拷貝問題

      我們先看如下代碼:

[java] view plain copy 在CODE上查看代碼片public class Person implements Cloneable{      /** 姓名 **/      public class Client {      public static void main(String[] args) {          //寫封郵件          Email email = new Email("請參加會議","請與今天12:30到二會議室參加會議...");                    Person person1 =  new Person("張三",email);                    Person person2 =  person1.clone();          person2.setName("李四");          Person person3 =  person1.clone();          person3.setName("王五");                    person1.getEmail().setContent("請與今天12:00到二會議室參加會議...");                    System.out.println(person1.getName() + "的郵件內容是:" + person1.getEmail().getContent());          System.out.println(person2.getName() + "的郵件內容是:" + person2.getEmail().getContent());          System.out.println(person3.getName() + "的郵件內容是:" + person3.getEmail().getContent());      }  }         在這里同樣是使用張三該對象實現對李四、王五拷貝,最后將張三的郵件內容改變為:請與今天12:00到二會議室參加會議...。但是結果是:

[java] view%20plain copy 張三的郵件內容是:請與今天12:00到二會議室參加會議...  李四的郵件內容是:請與今天12:00到二會議室參加會議...  王五的郵件內容是:請與今天12:00到二會議室參加會議...  

      這里我們就疑惑了為什么李四和王五的郵件內容也發送了改變呢?讓他們提前30分鐘到人家會有意見的!

      其實出現問題的關鍵就在于clone()方法上,我們知道該clone()方法是使用Object類的clone()方法,但是該方法存在一個缺陷,它并不會將對象的所有屬性全部拷貝過來,而是有選擇性的拷貝,基本規則如下:

      1、%20基本類型

         如果變量是基本很類型,則拷貝其值,比如int、float等。

      2、%20對象

          如果變量是一個實例對象,則拷貝其地址引用,也就是說此時新對象與原來對象是公用該實例變量。

      3、%20String字符串

     %20 %20 若變量為String字符串,則拷貝其地址引用。但是在修改時,它會從字符串池中重新生成一個新的字符串,原有紫都城對象保持不變。

      基于上面上面的規則,我們很容易發現問題的所在,他們三者公用一個對象,張三修改了該郵件內容,則李四和王五也會修改,所以才會出現上面的情況。對于這種情況我們還是可以解決的,只需要在clone()方法里面新建一個對象,然后張三引用該對象即可:

[java] view%20plain copy protected Person clone() {          Person person = null;          try {              person = (Person) super.clone();              person.setEmail(new Email(person.getEmail().getObject(),person.getEmail().getContent()));          } catch (CloneNotSupportedException e) {              e.printStackTrace();          }                    return person;      }  

      所以:淺拷貝只是Java提供的一種簡單的拷貝機制,不便于直接使用。

      對于上面的解決方案還是存在一個問題,若我們系統中存在大量的對象是通過拷貝生成的,如果我們每一個類都寫一個clone()方法,并將還需要進行深拷貝,新建大量的對象,這個工程是非常大的,這里我們可以利用序列化來實現對象的拷貝。

       二、利用序列化實現對象的拷貝      如何利用序列化來完成對象的拷貝呢?在內存中通過字節流的拷貝是比較容易實現的。把母對象寫入到一個字節流中,再從字節流中將其讀出來,這樣就可以創建一個新的對象了,并且該新對象與母對象之間并不存在引用共享的問題,真正實現對象的深拷貝。

[java] view%20plain copy public class CloneUtils {      @SuppressWarnings("unchecked")      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;      }  }  

      使用該工具類的對象必須要實現Serializable接口,否則是沒有辦法實現克隆的。

[html] view%20plain copy public class Person implements Serializable{      private static final long serialVersionUID = 2631590509760908280L;        ..................      //去除clone()方法    }    public class Email implements Serializable{      private static final long serialVersionUID = 1267293988171991494L;            ....................  }  

      所以使用該工具類的對象只要實現Serializable接口就可實現對象的克隆,無須繼承Cloneable接口實現clone()方法。

[java] view%20plain copy 派生到我的代碼片public class Client {      public static void main(String[] args) {          //寫封郵件          Email email = new Email("請參加會議","請與今天12:30到二會議室參加會議...");                    Person person1 =  new Person("張三",email);                    Person person2 =  CloneUtils.clone(person1);          person2.setName("李四");          Person person3 =  CloneUtils.clone(person1);          person3.setName("王五");          person1.getEmail().setContent("請與今天12:00到二會議室參加會議...");                    System.out.println(person1.getName() + "的郵件內容是:" + person1.getEmail().getContent());          System.out.println(person2.getName() + "的郵件內容是:" + person2.getEmail().getContent());          System.out.println(person3.getName() + "的郵件內容是:" + person3.getEmail().getContent());      }  }  -------------------  Output:  張三的郵件內容是:請與今天12:00到二會議室參加會議...  李四的郵件內容是:請與今天12:30到二會議室參加會議...  王五的郵件內容是:請與今天12:30到二會議室參加會議...  
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 湘乡市| 绥中县| 蒙城县| 璧山县| 朝阳市| 康乐县| 朝阳区| 县级市| 原平市| 阳山县| 牙克石市| 工布江达县| 黄平县| 乌苏市| 逊克县| 房产| 壤塘县| 正宁县| 贺州市| 花莲县| 科尔| 仪征市| 西青区| 吉林省| 曲阳县| 两当县| 墨江| 石柱| 南雄市| 泾阳县| 措美县| 梅河口市| 隆德县| 武义县| 台州市| 台山市| 武穴市| 大邑县| 水富县| 岳普湖县| 太仆寺旗|