日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java基础篇:对象拷贝:clone方法 以及 序列化

發布時間:2024/9/30 java 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java基础篇:对象拷贝:clone方法 以及 序列化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

A:淺拷貝(淺克隆):?淺拷貝僅僅復制所考慮的對象,而不復制它所引用的對象。?
b:深拷貝(深克隆):深拷貝把要復制的對象所引用的對象都復制了一遍。

?

一、clone方法淺拷貝問題:

Java中對象的克隆,為了獲取對象的一份拷貝,我們可以利用Object類的clone()方法。Object類里的clone方法是淺拷貝。

必須要遵循下面三點:?
1.在派生類中覆蓋基類的clone()方法,并聲明為public【Object類中的clone()方法為protected的】。?
2.在派生類的clone()方法中,調用super.clone()。?
3.在派生類中實現Cloneable接口。?

先看以下代碼:

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 Email {private Object name;private String content;public Email(Object name, String content) {this.name = name;this.content = content;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public Object getName() {return name;}public void setName(Object name) {this.name = name;} }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到二會議室參加會議...

這里我們就有疑惑為什么李四和王五的郵件內容也發生改變了呢?其實出現問題的關鍵就在于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()方法,并將還需要進行深拷貝,新建大量的對象,這個工程是非常大的,這里我們可以利用序列化來實現對象的拷貝。

?

二、利用序列化實現對象的拷貝:

利用序列化來做深復制,把對象寫到流里的過程是序列化(Serilization)過程,而把對象從流中讀出來的過程則叫做反序列化(Deserialization)過程。應當指出的是,寫在流里的是對象的一個拷貝,而原對象仍然存在于JVM里面。利用這個特性,可以做深拷貝 。并且該新對象與母對象之間并不存在引用共享的問題,真正實現對象的深拷貝。

public class CloneUtils {@SuppressWarnings("unchecked")public static <T extends Serializable> T clone(T obj){T cloneObj = null;try {//寫入字節流,將該對象序列化成流,因為寫在流里的是對象的一個拷貝,而原對象仍然存在于JVM里面。所以利用這個特性可以實現對象的深拷貝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接口,否則是沒有辦法實現克隆的。

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()方法。

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到二會議室參加會議...

?

文章轉自:https://blog.csdn.net/chenssy/article/details/12952063

總結

以上是生活随笔為你收集整理的Java基础篇:对象拷贝:clone方法 以及 序列化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。