程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> java使用序列化實現對象的拷貝

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

編輯:關於JAVA
 

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

一、淺拷貝問題

我們先看如下代碼:

public class Person implements Cloneable{
/** 姓名 **/
private String name;

/** 電子郵件 **/
private Email email;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Email getEmail() {
return email;
}

public void setEmail(Email email) {
this.email = email;
}

public Person(String name,Email email){
this.name = name;
this.email = email;
}

public Person(String name){
this.name = name;
}

protected Person clone() {
Person person = null;
try {
person = (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}

return person;
}
}

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("王五");

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:30到二會議室參加會議...
李四的郵件內容是:請與今天12:30到二會議室參加會議...
王五的郵件內容是:請與今天12:30到二會議室參加會議...

在該應用程序中,首先定義一封郵件,然後將該郵件發給張三、李四、王五三個人,由於他們是使用相同的郵件,並且僅有名字不同,所以使用張三該對象類拷貝李四、王五對象然後更改下名字即可。程序一直到這裡都沒有錯,但是如果我們需要張三提前30分鐘到,即把郵件的內容修改下:

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到二會議室參加會議…。但是結果是:

張三的郵件內容是:請與今天12:00到二會議室參加會議...
李四的郵件內容是:請與今天12:00到二會議室參加會議...
王五的郵件內容是:請與今天12:00到二會議室參加會議...

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

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

1、 基本類型

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

2、 對象

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

3、 String字符串

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

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

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()方法,並將還需要進行深拷貝,新建大量的對象,這個工程是非常大的,這裡我們可以利用序列化來實現對象的拷貝。  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved