JAVA 中在對對象克隆的時候,可以在實體類中實作Cloneable 的接口來實作複制的功能,在實體類中重寫clone()的方法,但是這樣會出現一些問題,對于clone()的方法,基本資料類型是可以成功的copy的,但是對于引用資料類型,在copy的時候就會出現錯誤,我們用一個demo來看下到底是出現了什麼樣子的問題:
在這裡我們直接定義了兩個實體,針對批量發送郵件的時候,郵件内容可能是一樣,但是針對的客戶個人資訊是不一樣的,是以 我們進行了封裝
Email實體:
//實作Cloneable 的接口
public class Email implements Cloneable, Serializable{
private String conten;//郵件内容
private String title;//郵件主題
private Customer customer;//客戶實體資訊
public String getConten() {
return conten;
}
public void setConten(String conten) {
this.conten = conten;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
@Override
public String toString() {
return "Email{" +
"conten='" + conten + '\'' +
", title='" + title + '\'' +
", customer=" + customer +
'}';
}
//重寫clone()的方法
@Override
protected Email clone() throws CloneNotSupportedException {
return (Email) super.clone();
}
Customer實體:
public class Customer , Serializable{
private String name;//客戶姓名
private String address;//郵件位址
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
測試類:
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Email email =new Email();
email.setConten("客戶您好,我店在于7月27日有優惠活動。");
email.setTitle("優惠活動");
Customer customer=new Customer();
customer.setAddress("[email protected]");
customer.setName("zhangsan");
email.setCustomer(customer);
Email email1=email.clone();
email.getCustomer().setName("lisi");
email.getCustomer().setAddress("[email protected]");
System.out.println(email.getCustomer()==email1.getCustomer());
System.out.println(email);
System.out.println(email1);
}
}
這裡我們實作的效果應該是郵件的内容是一樣的,但是客戶的資訊是不一樣的,但是我們運作的時候發現以下的結果
true
Email{conten='客戶您好,我店在于7月27日有優惠活動。', title='優惠活動', customer=Customer{name='lisi', address='[email protected]'}}
Email{conten='客戶您好,我店在于7月27日有優惠活動。', title='優惠活動', customer=Customer{name='lisi', address='[email protected]'}}
我們可以看到 雖然對第二個Email的Customer進行了複制,但是發現第一個Email的資訊也發生了變化,并且,我們列印兩者的Customer的對象 發現了 為 true,這說明了,這個對象指向的位址 是用一個位址,是以列印的資訊也是一樣的。
是以在Clone接口針對引用類型的屬性,會指向用一個引用的位址,導緻資料的錯誤,是以我們針對這個現象,我們在實體中自己寫一個深複制的方法進行複制。
在Email的實體類中加入了一下的深克隆的方法
public Email deepClone() throws IOException, ClassNotFoundException {
//先寫入
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this);
//在讀取
ByteArrayInputStream byteArrayInputStream =new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
return (Email) objectInputStream.readObject();
}
在測試類中我們就變成了以下的,換了一下克隆的方法
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Email email =new Email();
email.setConten("客戶您好,我店在于7月27日有優惠活動。");
email.setTitle("優惠活動");
Customer customer=new Customer();
customer.setAddress("[email protected]");
customer.setName("zhangsan");
email.setCustomer(customer);
Email email1=email.deepClone();
email.getCustomer().setName("lisi");
email.getCustomer().setAddress("[email protected]");
System.out.println(email.getCustomer()==email1.getCustomer());
System.out.println(email);
System.out.println(email1);
}
}
測試列印結果:
false
Email{conten='客戶您好,我店在于7月27日有優惠活動。', title='優惠活動', customer=Customer{name='lisi', address='[email protected]'}}
Email{conten='客戶您好,我店在于7月27日有優惠活動。', title='優惠活動', customer=Customer{name='zhangsan', address='[email protected]'}}
這樣就得到了我們所預期的樣子了,
不過要注意的是,在這樣進行克隆的時候,實體類一定要實作 Serializable 的接口
不僅 Email要實作Serializable的接口,Customer 也需要實作Serializable的接口。
當遇到類似的場景,就不要納悶Cloneable的接口克隆的對象是不對的了。。。哈哈哈