欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中深拷貝,淺拷貝與引用拷貝的區(qū)別詳解

 更新時(shí)間:2022年08月23日 11:11:54   作者:小牛呼嚕嚕  
這篇文章主要為大家詳細(xì)介紹了Java面試中常遇見(jiàn)的問(wèn)題:深拷貝、淺拷貝與引用拷貝的區(qū)別,文中通過(guò)示例進(jìn)行了詳細(xì)講解,需要的可以參考一下

引用拷貝

引用拷貝: 引用拷貝不會(huì)在堆上創(chuàng)建一個(gè)新的對(duì)象,只 會(huì)在棧上生成一個(gè)新的引用地址,最終指向依然是堆上的同一個(gè)對(duì)象。

//實(shí)體類(lèi)
public class Person{
    public String name;//姓名
    public int height;//身高
    public StringBuilder something;

    public String getName() {
        return name;
    }

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

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public StringBuilder getSomething() {
        return something;
    }

    public void setSomething(StringBuilder something) {
        this.something = something;
    }

    public Person(String name, int height, StringBuilder something) {
        this.name = name;
        this.height = height;
        this.something = something;
    }

}

//測(cè)試類(lèi)
public class copyTest {
    public static void main(String[] args) {
        Person p1 = new Person("小張", 180, new StringBuilder("今天天氣很好"));
        Person p2 = p1;

        System.out.println("對(duì)象是否相等:"+ (p1 == p2));
        System.out.println("p1 屬性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 屬性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());


        // change
        p1.name="小王";
        p1.height = 200;
        p1.something.append(",適合出去玩");
        System.out.println("...after p1 change....");

        System.out.println("p1 屬性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 屬性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());

    }
}

結(jié)果:

對(duì)象是否相等:true
p1 屬性值=小張,180,今天天氣很好
p2 屬性值=小張,180,今天天氣很好
...after p1 change....
p1 屬性值=小王,200,今天天氣很好,適合出去玩
p2 屬性值=小王,200,今天天氣很好,適合出去玩

before change:

after change:

我們可以看出 由于2個(gè)引用p1,p2 都是指向堆中同一個(gè)對(duì)象,所以2個(gè)對(duì)象是相等的,修改了對(duì)象p1,會(huì)影響到對(duì)象p2
需要注意的

  • name屬性,雖然她是引用類(lèi)型,但她同時(shí)也是String類(lèi)型,不可變,對(duì)其修改,JVM會(huì)默認(rèn)在堆上創(chuàng)建新的內(nèi)存空間,再重新賦值
  • int weight=180; 是成員變量,存放在堆中,不是所有的基本類(lèi)型變量 都存放在JVM棧中

注意與這篇文章得區(qū)分開(kāi)來(lái), int num1 = 10;是基本類(lèi)型的局部變量,存放在棧中

淺拷貝

淺拷貝 :淺拷貝會(huì)在堆上創(chuàng)建一個(gè)新的對(duì)象,新對(duì)象和原對(duì)象不等,但是新對(duì)象的屬性和老對(duì)象相同。

其中:

  • 如果屬性是基本類(lèi)型(int,double,long,boolean等),拷貝的就是基本類(lèi)型的值。
  • 如果屬性是引用類(lèi)型(除了基本類(lèi)型都是引用類(lèi)型),拷貝的就是引?數(shù)據(jù)類(lèi)型變量的地址值,?對(duì)于引?類(lèi)型變量指向的堆中的對(duì)象不會(huì)拷貝。

如何實(shí)現(xiàn)淺拷貝呢?也很簡(jiǎn)單,就是在需要拷貝的類(lèi)上實(shí)現(xiàn)Cloneable接口并重寫(xiě)其clone()方法。

@Override protected Object clone() throws CloneNotSupportedException {   
    return super.clone(); 
} 

在使用的時(shí)候直接調(diào)用類(lèi)的clone()方法即可

//實(shí)體類(lèi) 繼承Cloneable
public class Person implements Cloneable{
    public String name;//姓名
    public int height;//身高
    public StringBuilder something;

    public String getName() {
        return name;
    }

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

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public StringBuilder getSomething() {
        return something;
    }

    public void setSomething(StringBuilder something) {
        this.something = something;
    }

    public Person(String name, int height, StringBuilder something) {
        this.name = name;
        this.height = height;
        this.something = something;
    }



    @Override
    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }

}

//測(cè)試類(lèi)
public class shallowCopyTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person("小張", 180, new StringBuilder("今天天氣很好"));
        Person p2 = p1.clone();

        System.out.println("對(duì)象是否相等:"+ (p1 == p2));
        System.out.println("p1 屬性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 屬性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());


        // change
        p1.setName("小王");
        p1.setHeight(200);
        p1.getSomething().append(",適合出去玩");
        System.out.println("...after p1 change....");

        System.out.println("p1 屬性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 屬性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());

    }
}

結(jié)果:

對(duì)象是否相等:false
p1 屬性值=小張,180,今天天氣很好
p2 屬性值=小張,180,今天天氣很好
...after p1 change....
p1 屬性值=小王,200,今天天氣很好,適合出去玩
p2 屬性值=小張,180,今天天氣很好,適合出去玩

before change:

after change:

我們可以看出:

  • 當(dāng)我們修改對(duì)象p1的weight屬性時(shí),由于p2的height屬性 是直接復(fù)制修改前的p1的height屬性,所以還是180。
  • 當(dāng)我們修改對(duì)象p1的name屬性 時(shí),String name指向一個(gè)新的內(nèi)存空間,但對(duì)象p2的name還是指向舊的內(nèi)存空間,所以對(duì)象p2的name屬性還是"小張"。
  • 由于對(duì)象p1的something屬性和對(duì)象p2的something屬性指向是同一個(gè)內(nèi)存空間,當(dāng)我們修改對(duì)象p1的something屬性,會(huì)影響到對(duì)象p2的something屬性,所以對(duì)象p2的something屬性變?yōu)?quot;今天天氣很好,適合出去玩"。

深拷貝

深拷貝 :完全拷貝?個(gè)對(duì)象,在堆上創(chuàng)建一個(gè)新的對(duì)象,拷貝被拷貝對(duì)象的成員變量的值,同時(shí)堆中的對(duì)象也會(huì)拷貝。
需要重寫(xiě)clone方法

    @Override
    public Person clone() throws CloneNotSupportedException {
        //return (Person) super.clone();
        Person person = (Person) super.clone();
        person.setSomething( new StringBuilder(person.getSomething()));//單獨(dú)為引用類(lèi)型clone
        return person;
    }

shallowCopyTest測(cè)試類(lèi)的結(jié)果:

對(duì)象是否相等:false
p1 屬性值=小張,180,今天天氣很好
p2 屬性值=小張,180,今天天氣很好
...after p1 change....
p1 屬性值=小王,200,今天天氣很好,適合出去玩
p2 屬性值=小張,180,今天天氣很好

這時(shí)候?qū)ο髉1和對(duì)象p2互不干擾了

before change:

after change:

但這樣也有個(gè)小問(wèn)題,對(duì)象每有一個(gè)引用類(lèi)型,我們都得重寫(xiě)其clone方法,這樣會(huì)非常麻煩,因此我們還可以借助序列化來(lái)實(shí)現(xiàn)對(duì)象的深拷貝

//實(shí)體類(lèi) 繼承Cloneable
public class Person implements Serializable{
    public String name;//姓名
    public int height;//身高
    public StringBuilder something;

...//省略 getter setter


    public Object 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 ois.readObject();
    }

}

//測(cè)試類(lèi),這邊類(lèi)名筆者就不換了,在之前的基礎(chǔ)上改改
public class shallowCopyTest {

    public static void main(String[] args) throws Exception {
        Person p1 = new Person("小張", 180, new StringBuilder("今天天氣很好"));
        Person p2 = (Person)p1.deepClone();

        System.out.println("對(duì)象是否相等:"+ (p1 == p2));
        System.out.println("p1 屬性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 屬性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());


        // change
        p1.setName("小王");
        p1.setHeight(200);
        p1.getSomething().append(",適合出去玩");
        System.out.println("...after p1 change....");

        System.out.println("p1 屬性值=" + p1.getName()+ ","+ p1.getHeight() + ","+ p1.getSomething());
        System.out.println("p2 屬性值=" + p2.getName()+ ","+ p2.getHeight() + ","+ p2.getSomething());

    }
}

這樣也會(huì)得到深拷貝的結(jié)果

小結(jié)

引用拷貝: 引用拷貝不會(huì)在堆上創(chuàng)建一個(gè)新的對(duì)象,只 會(huì)在棧上生成一個(gè)新的引用地址,最終指向依然是堆上的同一個(gè)對(duì)象。

淺拷貝 :淺拷貝會(huì)在堆上創(chuàng)建一個(gè)新的對(duì)象,新對(duì)象和原對(duì)象不等,但是新對(duì)象的屬性和老對(duì)象相同。

其中:

如果屬性是基本類(lèi)型(int,double,long,boolean等),拷貝的就是基本類(lèi)型的值。

如果屬性是引用類(lèi)型(除了基本類(lèi)型都是引用類(lèi)型),拷貝的就是引?數(shù)據(jù)類(lèi)型變量的地址值,?對(duì)于引?類(lèi)型變量指向的堆中的對(duì)象不會(huì)拷貝。

深拷貝 :完全拷貝?個(gè)對(duì)象,在堆上創(chuàng)建一個(gè)新的對(duì)象,拷貝被拷貝對(duì)象的成員變量的值,同時(shí)堆中的對(duì)象也會(huì)拷貝。

以上就是Java中深拷貝,淺拷貝與引用拷貝的區(qū)別詳解的詳細(xì)內(nèi)容,更多關(guān)于Java拷貝的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java詳細(xì)講解包的作用以及修飾符的介紹

    Java詳細(xì)講解包的作用以及修飾符的介紹

    本文主要講述的是包的使用和注意事項(xiàng)和四種訪問(wèn)修飾符public,protected,默認(rèn)的,private的訪問(wèn)范圍及實(shí)例,感興趣的朋友一起來(lái)看看
    2022-05-05
  • 基于Springboot+Junit+Mockito做單元測(cè)試的示例

    基于Springboot+Junit+Mockito做單元測(cè)試的示例

    本篇文章主要介紹了基于Springboot+Junit+Mockito做單元測(cè)試的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • SpringBoot項(xiàng)目實(shí)現(xiàn)短信發(fā)送接口開(kāi)發(fā)的實(shí)踐

    SpringBoot項(xiàng)目實(shí)現(xiàn)短信發(fā)送接口開(kāi)發(fā)的實(shí)踐

    本文主要介紹了SpringBoot項(xiàng)目實(shí)現(xiàn)短信發(fā)送接口開(kāi)發(fā)的實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Java8中常用的日期時(shí)間工具類(lèi)總結(jié)

    Java8中常用的日期時(shí)間工具類(lèi)總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Java8中常用的三個(gè)日期時(shí)間工具類(lèi),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下
    2023-07-07
  • SpringBoot3集成Quartz的示例代碼

    SpringBoot3集成Quartz的示例代碼

    Quartz由Java編寫(xiě)的功能豐富的開(kāi)源作業(yè)調(diào)度框架,可以集成到幾乎任何Java應(yīng)用程序中,并且能夠創(chuàng)建多個(gè)作業(yè)調(diào)度,在實(shí)際的業(yè)務(wù)中,有很多場(chǎng)景依賴(lài)定時(shí)任務(wù),比如常見(jiàn)的:訂單超時(shí)處理,業(yè)務(wù)識(shí)別和預(yù)警通知等,本文介紹了SpringBoot3如何集成Quartz
    2023-08-08
  • SpringBoot整合騰訊云COS對(duì)象存儲(chǔ)實(shí)現(xiàn)文件上傳的示例代碼

    SpringBoot整合騰訊云COS對(duì)象存儲(chǔ)實(shí)現(xiàn)文件上傳的示例代碼

    本文主要介紹了SpringBoot整合騰訊云COS對(duì)象存儲(chǔ)實(shí)現(xiàn)文件上傳的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • mybatis中的延遲加載類(lèi)型及設(shè)定詳解

    mybatis中的延遲加載類(lèi)型及設(shè)定詳解

    這篇文章主要介紹了mybatis中的延遲加載類(lèi)型及設(shè)定詳解,MyBatis中的延遲加載,也稱(chēng)為懶加載,是指在進(jìn)行關(guān)聯(lián)查詢(xún)時(shí),按照設(shè)置延遲規(guī)則推遲對(duì)關(guān)聯(lián)對(duì)象的select查詢(xún),延遲加載可以有效的減少數(shù)據(jù)庫(kù)壓力,需要的朋友可以參考下
    2023-10-10
  • 一篇文章帶你入門(mén)java模板模式

    一篇文章帶你入門(mén)java模板模式

    這篇文章主要為大家詳細(xì)介紹了java模板模式的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 淺析Java 常用的 4 種加密方式(MD5+Base64+SHA+BCrypt)

    淺析Java 常用的 4 種加密方式(MD5+Base64+SHA+BCrypt)

    這篇文章主要介紹了Java 常用的 4 種加密方式(MD5+Base64+SHA+BCrypt),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-10-10
  • java對(duì)象對(duì)比之comparable和comparator的區(qū)別

    java對(duì)象對(duì)比之comparable和comparator的區(qū)別

    今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著comparable和comparator的區(qū)別展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06

最新評(píng)論