哈哈哈哈哈操欧洲电影,久草网在线,亚洲久久熟女熟妇视频,麻豆精品色,久久福利在线视频,日韩中文字幕的,淫乱毛视频一区,亚洲成人一二三,中文人妻日韩精品电影

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

什么是深拷貝和淺拷貝

科技綠洲 ? 來(lái)源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-13 11:29 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1、創(chuàng)建對(duì)象的5種方式

①、通過(guò) new 關(guān)鍵字

這是最常用的一種方式,通過(guò) new 關(guān)鍵字調(diào)用類(lèi)的有參或無(wú)參構(gòu)造方法來(lái)創(chuàng)建對(duì)象。比如 Object obj = new Object();

②、通過(guò) Class 類(lèi)的 newInstance() 方法

這種默認(rèn)是調(diào)用類(lèi)的無(wú)參構(gòu)造方法創(chuàng)建對(duì)象。比如 Person p2 = (Person) Class.forName("com.ys.test.Person").newInstance();

③、通過(guò) Constructor 類(lèi)的 newInstance 方法

這和第二種方法類(lèi)都是通過(guò)反射來(lái)實(shí)現(xiàn)。通過(guò) java.lang.relect.Constructor 類(lèi)的 newInstance() 方法指定某個(gè)構(gòu)造器來(lái)創(chuàng)建對(duì)象。

Person p3 = (Person) Person.class.getConstructors()[0].newInstance();

實(shí)際上第二種方法利用 Class 的 newInstance() 方法創(chuàng)建對(duì)象,其內(nèi)部調(diào)用還是 Constructor 的 newInstance() 方法。

④、利用 Clone 方法

Clone 是 Object 類(lèi)中的一個(gè)方法,通過(guò) 對(duì)象A.clone() 方法會(huì)創(chuàng)建一個(gè)內(nèi)容和對(duì)象 A 一模一樣的對(duì)象 B,clone 克隆,顧名思義就是創(chuàng)建一個(gè)一模一樣的對(duì)象出來(lái)。

Person p4 = (Person) p3.clone();

⑤、反序列化

序列化是把堆內(nèi)存中的 Java 對(duì)象數(shù)據(jù),通過(guò)某種方式把對(duì)象存儲(chǔ)到磁盤(pán)文件中或者傳遞給其他網(wǎng)絡(luò)節(jié)點(diǎn)(在網(wǎng)絡(luò)上傳輸)。而反序列化則是把磁盤(pán)文件中的對(duì)象數(shù)據(jù)或者把網(wǎng)絡(luò)節(jié)點(diǎn)上的對(duì)象數(shù)據(jù),恢復(fù)成Java對(duì)象模型的過(guò)程。

2、Clone 方法

本篇博客我們講解的是 Java 的深拷貝和淺拷貝,其實(shí)現(xiàn)方式正是通過(guò)調(diào)用 Object 類(lèi)的 clone() 方法來(lái)完成。在 Object.class 類(lèi)中,源碼為:

protected native Object clone() throws CloneNotSupportedException;

這是一個(gè)用 native 關(guān)鍵字修飾的方法,關(guān)于native關(guān)鍵字有一篇博客專(zhuān)門(mén)有介紹,不理解也沒(méi)關(guān)系,只需要知道用 native 修飾的方法就是告訴操作系統(tǒng),這個(gè)方法我不實(shí)現(xiàn)了,讓操作系統(tǒng)去實(shí)現(xiàn)。具體怎么實(shí)現(xiàn)我們不需要了解,只需要知道 clone方法的作用就是復(fù)制對(duì)象,產(chǎn)生一個(gè)新的對(duì)象。那么這個(gè)新的對(duì)象和原對(duì)象是什么關(guān)系呢?

3、基本類(lèi)型和引用類(lèi)型

這里再給大家普及一個(gè)概念,在 Java 中基本類(lèi)型和引用類(lèi)型的區(qū)別。

在 Java 中數(shù)據(jù)類(lèi)型可以分為兩大類(lèi):基本類(lèi)型和引用類(lèi)型。

基本類(lèi)型也稱(chēng)為值類(lèi)型,分別是字符類(lèi)型 char,布爾類(lèi)型 boolean以及數(shù)值類(lèi)型 byte、short、int、long、float、double。

引用類(lèi)型則包括類(lèi)、接口、數(shù)組、枚舉等。

Java 將內(nèi)存空間分為堆和棧?;绢?lèi)型直接在棧中存儲(chǔ)數(shù)值,而引用類(lèi)型是將引用放在棧中,實(shí)際存儲(chǔ)的值是放在堆中,通過(guò)棧中的引用指向堆中存放的數(shù)據(jù)。圖片 上圖定義的 a 和 b 都是基本類(lèi)型,其值是直接存放在棧中的;而 c 和 d 是 String 聲明的,這是一個(gè)引用類(lèi)型,引用地址是存放在 棧中,然后指向堆的內(nèi)存空間。

下面 d = c;這條語(yǔ)句表示將 c 的引用賦值給 d,那么 c 和 d 將指向同一塊堆內(nèi)存空間。

4、淺拷貝

我們看如下這段代碼:

package com.ys.test;

public class Person implements Cloneable{
    public String pname;
    public int page;
    public Address address;
    public Person() {}
    
    public Person(String pname,int page){
        this.pname = pname;
        this.page = page;
        this.address = new Address();
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    
    public void setAddress(String provices,String city ){
        address.setAddress(provices, city);
    }
    public void display(String name){
        System.out.println(name+":"+"pname=" + pname + ", page=" + page +","+ address);
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }
    
}

這是一個(gè)我們要進(jìn)行賦值的原始類(lèi) Person。下面我們產(chǎn)生一個(gè) Person 對(duì)象,并調(diào)用其 clone 方法復(fù)制一個(gè)新的對(duì)象。

注意:調(diào)用對(duì)象的 clone 方法,必須要讓類(lèi)實(shí)現(xiàn) Cloneable 接口,并且覆寫(xiě) clone 方法。

測(cè)試:

@Test
public void testShallowClone() throws Exception{
    Person p1 = new Person("zhangsan",21);
    p1.setAddress("湖北省", "武漢市");
    Person p2 = (Person) p1.clone();
    System.out.println("p1:"+p1);
    System.out.println("p1.getPname:"+p1.getPname().hashCode());
    
    System.out.println("p2:"+p2);
    System.out.println("p2.getPname:"+p2.getPname().hashCode());
    
    p1.display("p1");
    p2.display("p2");
    p2.setAddress("湖北省", "荊州市");
    System.out.println("將復(fù)制之后的對(duì)象地址修改:");
    p1.display("p1");
    p2.display("p2");
}

打印結(jié)果為:圖片 首先看原始類(lèi) Person 實(shí)現(xiàn) Cloneable 接口,并且覆寫(xiě) clone 方法,它還有三個(gè)屬性,一個(gè)引用類(lèi)型 String定義的 pname,一個(gè)基本類(lèi)型 int定義的 page,還有一個(gè)引用類(lèi)型 Address ,這是一個(gè)自定義類(lèi),這個(gè)類(lèi)也包含兩個(gè)屬性 pprovices 和 city 。

接著看測(cè)試內(nèi)容,首先我們創(chuàng)建一個(gè)Person 類(lèi)的對(duì)象 p1,其pname 為zhangsan,page為21,地址類(lèi) Address 兩個(gè)屬性為 湖北省和武漢市。接著我們調(diào)用 clone() 方法復(fù)制另一個(gè)對(duì)象 p2,接著打印這兩個(gè)對(duì)象的內(nèi)容。

從第 1 行和第 3 行打印結(jié)果:

p1:com.ys.test.Person@349319f9

p2:com.ys.test.Person@258e4566

可以看出這是兩個(gè)不同的對(duì)象。

從第 5 行和第 6 行打印的對(duì)象內(nèi)容看,原對(duì)象 p1 和克隆出來(lái)的對(duì)象 p2 內(nèi)容完全相同。

代碼中我們只是更改了克隆對(duì)象 p2 的屬性 Address 為湖北省荊州市(原對(duì)象 p1 是湖北省武漢市) ,但是從第 7 行和第 8 行打印結(jié)果來(lái)看,原對(duì)象 p1 和克隆對(duì)象 p2 的 Address 屬性都被修改了。

也就是說(shuō)對(duì)象 Person 的屬性 Address,經(jīng)過(guò) clone 之后,其實(shí)只是復(fù)制了其引用,他們指向的還是同一塊堆內(nèi)存空間,當(dāng)修改其中一個(gè)對(duì)象的屬性 Address,另一個(gè)也會(huì)跟著變化。圖片

淺拷貝:創(chuàng)建一個(gè)新對(duì)象,然后將當(dāng)前對(duì)象的非靜態(tài)字段復(fù)制到該新對(duì)象,如果字段是值類(lèi)型的,那么對(duì)該字段執(zhí)行復(fù)制;如果該字段是引用類(lèi)型的話,則復(fù)制引用但不復(fù)制引用的對(duì)象。因此,原始對(duì)象及其副本引用同一個(gè)對(duì)象。

5、深拷貝

弄清楚了淺拷貝,那么深拷貝就很容易理解了。

深拷貝:創(chuàng)建一個(gè)新對(duì)象,然后將當(dāng)前對(duì)象的非靜態(tài)字段復(fù)制到該新對(duì)象,無(wú)論該字段是值類(lèi)型的還是引用類(lèi)型,都復(fù)制獨(dú)立的一份。當(dāng)你修改其中一個(gè)對(duì)象的任何內(nèi)容時(shí),都不會(huì)影響另一個(gè)對(duì)象的內(nèi)容。圖片 那么該如何實(shí)現(xiàn)深拷貝呢?Object 類(lèi)提供的 clone 是只能實(shí)現(xiàn) 淺拷貝的。

6、如何實(shí)現(xiàn)深拷貝?

深拷貝的原理我們知道了,就是要讓原始對(duì)象和克隆之后的對(duì)象所具有的引用類(lèi)型屬性不是指向同一塊堆內(nèi)存,這里有兩種實(shí)現(xiàn)思路。

①、讓每個(gè)引用類(lèi)型屬性?xún)?nèi)部都重寫(xiě)clone() 方法

既然引用類(lèi)型不能實(shí)現(xiàn)深拷貝,那么我們將每個(gè)引用類(lèi)型都拆分為基本類(lèi)型,分別進(jìn)行淺拷貝。比如上面的例子,Person 類(lèi)有一個(gè)引用類(lèi)型 Address(其實(shí)String 也是引用類(lèi)型,但是String類(lèi)型有點(diǎn)特殊,后面會(huì)詳細(xì)講解),我們?cè)?Address 類(lèi)內(nèi)部也重寫(xiě) clone 方法。如下:

Address.class:

package com.ys.test;

public class Address implements Cloneable{
    private String provices;
    private String city;
    public void setAddress(String provices,String city){
        this.provices = provices;
        this.city = city;
    }
    @Override
    public String toString() {
        return "Address [provices=" + provices + ", city=" + city + "]";
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

Person.class 的 clone() 方法:

@Override
    protected Object clone() throws CloneNotSupportedException {
        Person p = (Person) super.clone();
        p.address = (Address) address.clone();
        return p;
    }

測(cè)試還是和上面一樣,我們會(huì)發(fā)現(xiàn)更改了p2對(duì)象的Address屬性,p1 對(duì)象的 Address 屬性并沒(méi)有變化。

但是這種做法有個(gè)弊端,這里我們Person 類(lèi)只有一個(gè) Address 引用類(lèi)型,而 Address 類(lèi)沒(méi)有,所以我們只用重寫(xiě) Address 類(lèi)的clone 方法,但是如果 Address 類(lèi)也存在一個(gè)引用類(lèi)型,那么我們也要重寫(xiě)其clone 方法,這樣下去,有多少個(gè)引用類(lèi)型,我們就要重寫(xiě)多少次,如果存在很多引用類(lèi)型,那么代碼量顯然會(huì)很大,所以這種方法不太合適。

②、利用序列化

序列化是將對(duì)象寫(xiě)到流中便于傳輸,而反序列化則是把對(duì)象從流中讀取出來(lái)。這里寫(xiě)到流中的對(duì)象則是原始對(duì)象的一個(gè)拷貝,因?yàn)樵紝?duì)象還存在 JVM 中,所以我們可以利用對(duì)象的序列化產(chǎn)生克隆對(duì)象,然后通過(guò)反序列化獲取這個(gè)對(duì)象。

注意每個(gè)需要序列化的類(lèi)都要實(shí)現(xiàn) Serializable 接口,如果有某個(gè)屬性不需要序列化,可以將其聲明為 transient,即將其排除在克隆屬性之外。

//深度拷貝
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();
}

因?yàn)樾蛄谢a(chǎn)生的是兩個(gè)完全獨(dú)立的對(duì)象,所有無(wú)論嵌套多少個(gè)引用類(lèi)型,序列化都是能實(shí)現(xiàn)深拷貝的。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7347

    瀏覽量

    94999
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    3005

    瀏覽量

    116801
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    689

    瀏覽量

    31454
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    #硬聲創(chuàng)作季 4-9 Mat的拷貝拷貝

    數(shù)據(jù)庫(kù)
    Mr_haohao
    發(fā)布于 :2022年08月30日 15:32:51

    C++零基礎(chǔ)教程之C++拷貝拷貝,輕松上手C++拷貝拷貝

    編程語(yǔ)言C++語(yǔ)言
    電子學(xué)習(xí)
    發(fā)布于 :2023年01月14日 11:37:32

    32.[程序員小飛]用最淺顯的語(yǔ)言,深入理解拷貝拷貝的區(qū)別

    程序代碼
    充八萬(wàn)
    發(fā)布于 :2023年07月20日 02:25:58

    拷貝拷貝的實(shí)現(xiàn)方法概述

    拷貝拷貝的實(shí)現(xiàn)
    發(fā)表于 07-19 13:35

    python深淺拷貝是什么?

    python的直接賦值python的拷貝python的拷貝
    發(fā)表于 11-04 08:33

    請(qǐng)問(wèn)哪位大神可以詳細(xì)介紹JavaScript拷貝拷貝

    JavaScript數(shù)據(jù)類(lèi)型JavaScript拷貝拷貝
    發(fā)表于 11-05 07:16

    光盤(pán)拷貝機(jī)的使用端口

    光盤(pán)拷貝機(jī)的使用端口              使用端口指的是:光盤(pán)拷貝機(jī)內(nèi)部控制器與刻錄機(jī)相連的接口。目前光盤(pán)拷貝
    發(fā)表于 12-30 10:04 ?1162次閱讀

    C#拷貝拷貝區(qū)別解析

     所謂拷貝就是將對(duì)象中的所有字段復(fù)制到新的副本對(duì)象中;拷貝對(duì)于值類(lèi)型與引用類(lèi)型的方式有區(qū)別,值類(lèi)型字段的值被復(fù)制到副本中后,在副本中的修改不會(huì)影響源對(duì)象對(duì)應(yīng)的值;然而對(duì)于引用類(lèi)型的
    發(fā)表于 11-29 08:32 ?2.6w次閱讀
    C#<b class='flag-5'>淺</b><b class='flag-5'>拷貝</b>與<b class='flag-5'>深</b><b class='flag-5'>拷貝</b>區(qū)別解析

    Python如何防止數(shù)據(jù)被修改Python中的拷貝拷貝的問(wèn)題說(shuō)明

    在平時(shí)工作中,經(jīng)常涉及到數(shù)據(jù)的傳遞。在數(shù)據(jù)傳遞使用過(guò)程中,可能會(huì)發(fā)生數(shù)據(jù)被修改的問(wèn)題。為了防止數(shù)據(jù)被修改,就需要再傳遞一個(gè)副本,即使副本被修改,也不會(huì)影響原數(shù)據(jù)的使用。為了生成這個(gè)副本,就產(chǎn)生了拷貝——今天就說(shuō)一下Python中的拷貝
    的頭像 發(fā)表于 03-30 09:54 ?3753次閱讀
    Python如何防止數(shù)據(jù)被修改Python中的<b class='flag-5'>深</b><b class='flag-5'>拷貝</b>與<b class='flag-5'>淺</b><b class='flag-5'>拷貝</b>的問(wèn)題說(shuō)明

    C++之拷貝構(gòu)造函數(shù)的copy及copy

    C++編譯器會(huì)默認(rèn)提供構(gòu)造函數(shù);無(wú)參構(gòu)造函數(shù)用于定義對(duì)象的默認(rèn)初始化狀態(tài);拷貝構(gòu)造函數(shù)在創(chuàng)建對(duì)象時(shí)拷貝對(duì)象的狀態(tài);對(duì)象的拷貝拷貝
    的頭像 發(fā)表于 12-24 15:31 ?1429次閱讀

    為什么有時(shí)候會(huì)寫(xiě)出爛代碼

    就寫(xiě)出來(lái)了呢?其實(shí)還是因?yàn)橛行┲R(shí)沒(méi)那么扎實(shí)了~就容易被忽略了,于是我在團(tuán)隊(duì)群里面強(qiáng)調(diào)了一下這個(gè)問(wèn)題: 所以,本文主要是關(guān)于BeanUtils工具的屬性拷貝以及拷貝
    的頭像 發(fā)表于 08-27 10:23 ?1942次閱讀
    為什么有時(shí)候會(huì)寫(xiě)出爛代碼

    C++面向?qū)ο缶幊讨械?b class='flag-5'>深拷貝拷貝

    可能對(duì)于Java程序員來(lái)說(shuō),很少遇到深淺拷貝問(wèn)題,但是對(duì)于C++程序員來(lái)說(shuō)可謂是又愛(ài)又恨。。
    的頭像 發(fā)表于 03-30 12:53 ?1491次閱讀
    C++面向?qū)ο缶幊讨械?b class='flag-5'>深</b><b class='flag-5'>拷貝</b>和<b class='flag-5'>淺</b><b class='flag-5'>拷貝</b>

    C++拷貝拷貝詳解

    當(dāng)類(lèi)的函數(shù)成員存在指針成員時(shí)會(huì)產(chǎn)生拷貝拷貝和問(wèn)題。
    發(fā)表于 08-21 15:05 ?836次閱讀
    C++<b class='flag-5'>深</b><b class='flag-5'>拷貝</b>和<b class='flag-5'>淺</b><b class='flag-5'>拷貝</b>詳解

    Python中拷貝拷貝的操作

    【例子】拷貝拷貝中 list1 = [ 123 , 456 , 789 , 213 ]list2 = list1list3 = list1[:] print (list2) #
    的頭像 發(fā)表于 11-02 10:58 ?958次閱讀

    磁盤(pán)拷貝機(jī)會(huì)拷貝刪除的內(nèi)容嗎

    磁盤(pán)拷貝機(jī),也稱(chēng)為硬盤(pán)克隆器或磁盤(pán)復(fù)制器,是一種用于復(fù)制硬盤(pán)驅(qū)動(dòng)器內(nèi)容的設(shè)備。它可以將一個(gè)硬盤(pán)上的所有數(shù)據(jù),包括操作系統(tǒng)、程序、文件和設(shè)置,復(fù)制到另一個(gè)硬盤(pán)上。這種設(shè)備在數(shù)據(jù)備份、系統(tǒng)遷移、硬盤(pán)
    的頭像 發(fā)表于 10-14 15:38 ?2548次閱讀
    怀宁县| 新巴尔虎左旗| 新和县| 临邑县| 泰安市| 津市市| 宜昌市| 新野县| 青冈县| 鄂伦春自治旗| 平邑县| 浙江省| 镶黄旗| 崇文区| 临夏县| 奉节县| 会昌县| 巴里| 安宁市| 谷城县| 朝阳县| 礼泉县| 郸城县| 滦南县| 班戈县| 杨浦区| 隆德县| 江门市| 伊金霍洛旗| 尉犁县| 南平市| 神木县| 连城县| 南木林县| 永城市| 霍城县| 肇源县| 广汉市| 灯塔市| 田阳县| 娱乐|