Java中淺拷貝和深拷貝詳解
Java淺拷貝深拷貝
淺拷貝和深拷貝涉及到了Object類中的clone()方法

實(shí)現(xiàn)淺拷貝
淺拷貝的實(shí)現(xiàn)需要類重寫clone()方法
淺拷貝會(huì)創(chuàng)建一個(gè)新對(duì)象,這個(gè)對(duì)象有著原始對(duì)象屬性值的一份精確拷貝
如果屬性是基本類型,拷貝的就是基本類型的值;
如果屬性是內(nèi)存地址(引用類型),拷貝的就是內(nèi)存地址 ,因此如果其中一個(gè)對(duì)象改變了這個(gè)地址,就會(huì)影響到另一個(gè)對(duì)象,導(dǎo)致兩個(gè)對(duì)象的引用不等。
實(shí)現(xiàn)淺拷貝很簡(jiǎn)單只需要將類實(shí)現(xiàn)Cloneable接口然后重寫clone方法即可
class Person implements Cloneable {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* 重寫clone()方法
*
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
測(cè)試淺拷貝特性
public void testClone() throws CloneNotSupportedException {
Person person1 = new Person();
person1.setName("ccy");
person1.setAge(20);
Person person2 = (Person) person1.clone();
//查看淺拷貝效果
System.out.println(person1);
System.out.println(person2);
System.out.println(person1.getName() == person2.getName());
//驗(yàn)證clone()的特性
System.out.println(person1.clone() != person1);
System.out.println(person1.clone().getClass() == person1.getClass());
//如果是基本類型淺拷貝直接賦值值,如果是引用類型淺拷貝指向其內(nèi)存地址即共享內(nèi)存地址
//改變person1的引用類型String屬性的值,引用發(fā)生改變
person1.setName("zfs");
System.out.println(person2.getName());
}

實(shí)現(xiàn)深拷貝
對(duì)于上述的問題雖然拷貝的兩個(gè)對(duì)象不同,但其內(nèi)部的一些引用還是相同的,怎么樣絕對(duì)的拷貝這個(gè)對(duì)象,使這個(gè)對(duì)象完全獨(dú)立于原對(duì)象呢?就使用我們的深拷貝了。深拷貝:在對(duì)引用數(shù)據(jù)類型進(jìn)行拷貝的時(shí)候,創(chuàng)建了一個(gè)新的對(duì)象,并且復(fù)制其內(nèi)的成員變量。
在具體實(shí)現(xiàn)深拷貝上,這里提供兩個(gè)方式,重寫clone()方法和序列法。
重寫clone()方法
如果使用重寫clone()方法實(shí)現(xiàn)深拷貝,那么要將類中所有自定義引用變量的類也去實(shí)現(xiàn)Cloneable接口實(shí)現(xiàn)clone()方法。對(duì)于字符類可以創(chuàng)建一個(gè)新的字符串實(shí)現(xiàn)拷貝。但是對(duì)于自定義類需要實(shí)現(xiàn)cloneable重寫clone,這樣做就太麻煩了所以我們使用序列化
序列化
序列化后將二進(jìn)制字節(jié)流內(nèi)容寫到一個(gè)媒介(文本或字節(jié)數(shù)組),然后是從這個(gè)媒介讀取數(shù)據(jù),原對(duì)象寫入這個(gè)媒介后拷貝給clone對(duì)象,原對(duì)象的修改不會(huì)影響clone對(duì)象,因?yàn)閏lone對(duì)象是從這個(gè)媒介讀取。
熟悉對(duì)象緩存的知道我們經(jīng)常將Java對(duì)象緩存到Redis中,然后還可能從Redis中讀取生成Java對(duì)象,這就用到序列化和反序列化。一般可以將Java對(duì)象存儲(chǔ)為字節(jié)流或者json串然后反序列化成Java對(duì)象。因?yàn)樾蛄谢瘯?huì)儲(chǔ)存對(duì)象的屬性但是不會(huì)也無法存儲(chǔ)對(duì)象在內(nèi)存中地址相關(guān)信息。所以在反序列化成Java對(duì)象時(shí)候會(huì)重新創(chuàng)建所有的引用對(duì)象。
在具體實(shí)現(xiàn)上,自定義的類需要實(shí)現(xiàn)Serializable接口
class Person implements Serializable {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
protected Person deepClone() throws Exception {
//序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Person) ois.readObject();
}
}
測(cè)試方法
public void testClone() throws Exception {
Person person1 = new Person();
person1.setName("ccy");
person1.setAge(20);
Person person2 = person1.deepClone();
System.out.println(person1.getName() == person2.getName());
}

可以看到兩個(gè)引用對(duì)象的地址并不同,成功實(shí)現(xiàn)了深拷貝
到此這篇關(guān)于Java中淺拷貝和深拷貝詳解的文章就介紹到這了,更多相關(guān)Java淺拷貝深拷貝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mybatis plus使用redis作為二級(jí)緩存的方法
這篇文章主要介紹了mybatis plus使用redis作為二級(jí)緩存的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
深入了解Java設(shè)計(jì)模式之職責(zé)鏈模式
Java設(shè)計(jì)模式中有很多種類別,例如單例模式、裝飾模式、觀察者模式等。本文將為大家詳細(xì)介紹其中的職責(zé)鏈模式,感興趣的可以了解一下2022-09-09
Mybatis查詢返回兩個(gè)或多個(gè)參數(shù)問題
這篇文章主要介紹了Mybatis查詢返回兩個(gè)或多個(gè)參數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
SpringBoot同時(shí)啟動(dòng)不同端口圖示解析
這篇文章主要介紹了SpringBoot同時(shí)啟動(dòng)不同端口圖示解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
Springcloud中Feign傳遞參數(shù)的過程解析
這篇文章主要介紹了Springcloud中Feign傳遞參數(shù)的過程,單個(gè)參數(shù)的傳值有兩種方式,第一種使用@RequestParam/@PathVariable進(jìn)行傳值,傳遞多個(gè)參數(shù):多個(gè)參數(shù)的傳值可以使用多個(gè)@RequestParam來進(jìn)行傳參,需要的朋友可以參考下2023-09-09
Caused by: java.lang.ClassNotFoundException: org.objectweb.a
這篇文章主要介紹了Caused by: java.lang.ClassNotFoundException: org.objectweb.asm.Type異常,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
SpringBoot生成License的實(shí)現(xiàn)示例
License指的是版權(quán)許可證,那么對(duì)于SpringBoot項(xiàng)目,如何增加License呢?本文就來介紹一下,感興趣的可以了解一下2021-06-06
解讀為什么@Autowired在屬性上被警告,在setter方法上不被警告問題
在Spring開發(fā)中,@Autowired注解常用于實(shí)現(xiàn)依賴注入,它可以應(yīng)用于類的屬性、構(gòu)造器或setter方法上,然而,當(dāng)@Autowired注解在屬性上使用時(shí),IntelliJIDEA等IDE會(huì)給出Fieldinjectionisnotrecommended的警告,而在setter方法上使用@Autowired時(shí)卻不會(huì)出現(xiàn)這個(gè)警告2025-02-02

