1.前言
首先,明確一點深拷貝和淺拷貝是針對對象屬性為對象的,因為基本數(shù)據(jù)類型在進行賦值操作時(也就是拷貝)是直接將值賦給了新的變量,也就是該變量是原變量的一個副本,這個時候你修改兩者中的任何一個的值都不會影響另一個,而對象或者引用數(shù)據(jù)來說在進行淺拷貝時,只是將對象的引用復(fù)制了一份,也就內(nèi)存地址;即兩個不同的變量指向了同一個內(nèi)存地址,那么在改變?nèi)我粋€變量的值都是改變這個內(nèi)存地址所指向的值,所以兩個變量的值都會改變。
上方這句話不太好理解,這樣,我把他們區(qū)別出來,做兩個講解,一個是關(guān)于基本類型的拷貝
;一個關(guān)于引用數(shù)據(jù)類型的拷貝
,分開理解,會大大降低學(xué)習(xí)成本~
2.基本類型的拷貝
在基本類型的拷貝中,深拷貝
和淺拷貝
的作用就沒什么區(qū)別了,拷貝出來的對象都是擁有相同的數(shù)值,這里用語言文字很難描述,可以看下面的代碼和圖來幫助理解。
public static void main(String[] args) throws CloneNotSupportedException {
//原來的對象
Person person1=new Person("張三",15);
//克隆出來的對象
Person person2=(Person) person1.clone();
}
我們打印這兩個對象的地址:
觀察可以看出,他兩個的地址是不相同的,也就是說,他兩個現(xiàn)在是不同的對象。
他兩個在堆、棧圖中是如何表示的呢?看下方的圖:
我們可以看出,p2
把p1
中的所有數(shù)據(jù)都重新生成了一份,讓給讓p2
指向新生成的那份數(shù)據(jù)。
3.引用類型的拷貝
這個就很有引用類型拷貝就會在深拷貝
和淺拷貝
上區(qū)別很大了!
我們?nèi)匀灰匀藖砼e例子,人身上一般都會帶著money,我們給人添加一個新的成員變量(錢),并且我們讓錢這個成員變量改為引用變量。
3.1 關(guān)于引用類型的淺拷貝
class Money {
public double value=99.99;
}
class Person implements Cloneable{
public String name;
public int age;
public Money money=new Money();
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class testDemo2 {
public static void main(String[] args) throws CloneNotSupportedException {
//原來的對象
Person person1=new Person("張三",15);
//克隆出來的對象
Person person2=(Person) person1.clone();
System.out.print("p1的錢錢數(shù):");
System.out.println(person1.money.value);
System.out.print("p2的錢錢數(shù):");
System.out.println(person2.money.value);
}
}
打印出來的結(jié)果:
p1的錢錢數(shù):99.99
p2的錢錢數(shù):99.99
我們可以觀察結(jié)果得出,p1的錢錢和p2的錢錢我們設(shè)置好的99.99。
當我們?nèi)L試修改p1錢錢的數(shù)時:
public static void main(String[] args) throws CloneNotSupportedException {
//原來的對象
Person person1=new Person("張三",15);
//克隆出來的對象
Person person2=(Person) person1.clone();
System.out.println("修改p1的錢錢數(shù)");
person1.money.value=50;
System.out.print("p1的錢錢數(shù):");
System.out.println(person1.money.value);
System.out.print("p2的錢錢數(shù):");
System.out.println(person2.money.value);
}
代碼打印結(jié)果:
我去,你修改p1
的錢錢數(shù),為啥我p2
的錢錢數(shù)也發(fā)送了改變,這不就相當于別人花的錢扣在了我身上?這可不是我想要的結(jié)果!
這到底怎能回事?其實很好理解,當我們在進行拷貝時,我們拷貝money這個成員變量時,我們拷貝的數(shù)值是一個引用變量,這個引用變量又指向一個對象。因此當我們修改p1
的錢的數(shù)值時,我們時順著引用變量找所指向的值將其修改了,又因為兩個引用對象指向同一個值,因此修改后,再通過引用變量查看值,就是修改后的值了;上述過程就是淺拷貝
了,它的結(jié)構(gòu)圖如下:
3.2 關(guān)于引用類型的深拷貝
如何解決這樣的問題呢?其實很簡單,當我們進行拷貝時,我們讓引用變量引用的對象重新創(chuàng)建一個新的對象,并且讓拷貝的那一份的引用變量指向創(chuàng)建的對象。
我們主要修改的就算Person
類中的clone
方法,我們先讓Money
類實現(xiàn)Cloneable
接口,然后在Person
類中的clone
方法調(diào)用Money
類中的clone
方法。(這里比較繞,看不懂沒關(guān)系,下面有畫的結(jié)構(gòu)圖,圖看起來會很好理解!)文章來源:http://www.zghlxwxcb.cn/news/detail-468626.html
class Money implements Cloneable{
public double value=99.99;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public String name;
public int age;
public Money money=new Money();
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person person=(Person) super.clone();
person.money=(Money) person.money.clone();
return person;
}
}
public class testDemo2 {
public static void main(String[] args) throws CloneNotSupportedException {
//原來的對象
Person person1=new Person("張三",15);
//克隆出來的對象
Person person2=(Person) person1.clone();
System.out.println("修改p1的錢錢數(shù)");
person1.money.value=50;
System.out.print("p1的錢錢數(shù):");
System.out.println(person1.money.value);
System.out.print("p2的錢錢數(shù):");
System.out.println(person2.money.value);
}
}
代碼運行出來的結(jié)果:
可以看出,修改p1的錢數(shù),不在應(yīng)用p2的錢數(shù)了。
上方這個過程就是深拷貝,深拷貝的結(jié)構(gòu)圖如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-468626.html
到了這里,關(guān)于面試官:深拷貝與淺拷貝有啥區(qū)別?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!