色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

什么是深拷貝和淺拷貝

科技綠洲 ? 來源:Java技術指北 ? 作者:Java技術指北 ? 2023-10-13 11:29 ? 次閱讀

1、創建對象的5種方式

①、通過 new 關鍵字

這是最常用的一種方式,通過 new 關鍵字調用類的有參或無參構造方法來創建對象。比如 Object obj = new Object();

②、通過 Class 類的 newInstance() 方法

這種默認是調用類的無參構造方法創建對象。比如 Person p2 = (Person) Class.forName("com.ys.test.Person").newInstance();

③、通過 Constructor 類的 newInstance 方法

這和第二種方法類都是通過反射來實現。通過 java.lang.relect.Constructor 類的 newInstance() 方法指定某個構造器來創建對象。

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

實際上第二種方法利用 Class 的 newInstance() 方法創建對象,其內部調用還是 Constructor 的 newInstance() 方法。

④、利用 Clone 方法

Clone 是 Object 類中的一個方法,通過 對象A.clone() 方法會創建一個內容和對象 A 一模一樣的對象 B,clone 克隆,顧名思義就是創建一個一模一樣的對象出來。

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

⑤、反序列化

序列化是把堆內存中的 Java 對象數據,通過某種方式把對象存儲到磁盤文件中或者傳遞給其他網絡節點(在網絡上傳輸)。而反序列化則是把磁盤文件中的對象數據或者把網絡節點上的對象數據,恢復成Java對象模型的過程。

2、Clone 方法

本篇博客我們講解的是 Java 的深拷貝和淺拷貝,其實現方式正是通過調用 Object 類的 clone() 方法來完成。在 Object.class 類中,源碼為:

protected native Object clone() throws CloneNotSupportedException;

這是一個用 native 關鍵字修飾的方法,關于native關鍵字有一篇博客專門有介紹,不理解也沒關系,只需要知道用 native 修飾的方法就是告訴操作系統,這個方法我不實現了,讓操作系統去實現。具體怎么實現我們不需要了解,只需要知道 clone方法的作用就是復制對象,產生一個新的對象。那么這個新的對象和原對象是什么關系呢?

3、基本類型和引用類型

這里再給大家普及一個概念,在 Java 中基本類型和引用類型的區別。

在 Java 中數據類型可以分為兩大類:基本類型和引用類型。

基本類型也稱為值類型,分別是字符類型 char,布爾類型 boolean以及數值類型 byte、short、int、long、float、double。

引用類型則包括類、接口、數組、枚舉等。

Java 將內存空間分為堆和棧。基本類型直接在棧中存儲數值,而引用類型是將引用放在棧中,實際存儲的值是放在堆中,通過棧中的引用指向堆中存放的數據。圖片 上圖定義的 a 和 b 都是基本類型,其值是直接存放在棧中的;而 c 和 d 是 String 聲明的,這是一個引用類型,引用地址是存放在 棧中,然后指向堆的內存空間。

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

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;
    }
    
}

這是一個我們要進行賦值的原始類 Person。下面我們產生一個 Person 對象,并調用其 clone 方法復制一個新的對象。

注意:調用對象的 clone 方法,必須要讓類實現 Cloneable 接口,并且覆寫 clone 方法。

測試:

@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("將復制之后的對象地址修改:");
    p1.display("p1");
    p2.display("p2");
}

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

接著看測試內容,首先我們創建一個Person 類的對象 p1,其pname 為zhangsan,page為21,地址類 Address 兩個屬性為 湖北省和武漢市。接著我們調用 clone() 方法復制另一個對象 p2,接著打印這兩個對象的內容。

從第 1 行和第 3 行打印結果:

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

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

可以看出這是兩個不同的對象。

從第 5 行和第 6 行打印的對象內容看,原對象 p1 和克隆出來的對象 p2 內容完全相同。

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

也就是說對象 Person 的屬性 Address,經過 clone 之后,其實只是復制了其引用,他們指向的還是同一塊堆內存空間,當修改其中一個對象的屬性 Address,另一個也會跟著變化。圖片

淺拷貝:創建一個新對象,然后將當前對象的非靜態字段復制到該新對象,如果字段是值類型的,那么對該字段執行復制;如果該字段是引用類型的話,則復制引用但不復制引用的對象。因此,原始對象及其副本引用同一個對象。

5、深拷貝

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

深拷貝:創建一個新對象,然后將當前對象的非靜態字段復制到該新對象,無論該字段是值類型的還是引用類型,都復制獨立的一份。當你修改其中一個對象的任何內容時,都不會影響另一個對象的內容。圖片 那么該如何實現深拷貝呢?Object 類提供的 clone 是只能實現 淺拷貝的。

6、如何實現深拷貝?

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

①、讓每個引用類型屬性內部都重寫clone() 方法

既然引用類型不能實現深拷貝,那么我們將每個引用類型都拆分為基本類型,分別進行淺拷貝。比如上面的例子,Person 類有一個引用類型 Address(其實String 也是引用類型,但是String類型有點特殊,后面會詳細講解),我們在 Address 類內部也重寫 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;
    }

測試還是和上面一樣,我們會發現更改了p2對象的Address屬性,p1 對象的 Address 屬性并沒有變化。

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

②、利用序列化

序列化是將對象寫到流中便于傳輸,而反序列化則是把對象從流中讀取出來。這里寫到流中的對象則是原始對象的一個拷貝,因為原始對象還存在 JVM 中,所以我們可以利用對象的序列化產生克隆對象,然后通過反序列化獲取這個對象。

注意每個需要序列化的類都要實現 Serializable 接口,如果有某個屬性不需要序列化,可以將其聲明為 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();
}

因為序列化產生的是兩個完全獨立的對象,所有無論嵌套多少個引用類型,序列化都是能實現深拷貝的。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 數據
    +關注

    關注

    8

    文章

    7079

    瀏覽量

    89166
  • JAVA
    +關注

    關注

    19

    文章

    2971

    瀏覽量

    104850
  • 源碼
    +關注

    關注

    8

    文章

    645

    瀏覽量

    29273
收藏 人收藏

    評論

    相關推薦

    #硬聲創作季 4-9 Mat的拷貝拷貝

    數據庫
    Mr_haohao
    發布于 :2022年08月30日 15:32:51

    C++零基礎教程之C++拷貝拷貝,輕松上手C++拷貝拷貝

    編程語言C++語言
    電子學習
    發布于 :2023年01月14日 11:37:32

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

    程序代碼
    充八萬
    發布于 :2023年07月20日 02:25:58

    拷貝拷貝的實現方法概述

    拷貝拷貝的實現
    發表于 07-19 13:35

    python深淺拷貝是什么?

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

    請問哪位大神可以詳細介紹JavaScript拷貝拷貝

    JavaScript數據類型JavaScript拷貝拷貝
    發表于 11-05 07:16

    光盤拷貝機的使用端口

    光盤拷貝機的使用端口              使用端口指的是:光盤拷貝機內部控制器與刻錄機相連的接口。目前光盤拷貝
    發表于 12-30 10:04 ?1001次閱讀

    C#拷貝拷貝區別解析

     所謂拷貝就是將對象中的所有字段復制到新的副本對象中;拷貝對于值類型與引用類型的方式有區別,值類型字段的值被復制到副本中后,在副本中的修改不會影響源對象對應的值;然而對于引用類型的
    發表于 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>區別解析

    Python如何防止數據被修改Python中的拷貝拷貝的問題說明

    在平時工作中,經常涉及到數據的傳遞。在數據傳遞使用過程中,可能會發生數據被修改的問題。為了防止數據被修改,就需要再傳遞一個副本,即使副本被修改,也不會影響原數據的使用。為了生成這個副本,就產生了拷貝——今天就說一下Python中的拷貝
    的頭像 發表于 03-30 09:54 ?3069次閱讀
    Python如何防止數據被修改Python中的<b class='flag-5'>深</b><b class='flag-5'>拷貝</b>與<b class='flag-5'>淺</b><b class='flag-5'>拷貝</b>的問題說明

    C++之拷貝構造函數的copy及copy

    C++編譯器會默認提供構造函數;無參構造函數用于定義對象的默認初始化狀態;拷貝構造函數在創建對象時拷貝對象的狀態;對象的拷貝拷貝
    的頭像 發表于 12-24 15:31 ?761次閱讀

    為什么有時候會寫出爛代碼

    就寫出來了呢?其實還是因為有些知識沒那么扎實了~就容易被忽略了,于是我在團隊群里面強調了一下這個問題: 所以,本文主要是關于BeanUtils工具的屬性拷貝以及拷貝
    的頭像 發表于 08-27 10:23 ?1367次閱讀
    為什么有時候會寫出爛代碼

    C++面向對象編程中的拷貝拷貝

    可能對于Java程序員來說,很少遇到深淺拷貝問題,但是對于C++程序員來說可謂是又愛又恨。。
    的頭像 發表于 03-30 12:53 ?792次閱讀
    C++面向對象編程中的<b class='flag-5'>深</b><b class='flag-5'>拷貝</b>和<b class='flag-5'>淺</b><b class='flag-5'>拷貝</b>

    C++拷貝拷貝詳解

    當類的函數成員存在指針成員時會產生拷貝拷貝和問題。
    發表于 08-21 15:05 ?340次閱讀
    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) #
    的頭像 發表于 11-02 10:58 ?412次閱讀

    磁盤拷貝機會拷貝刪除的內容嗎

    磁盤拷貝機,也稱為硬盤克隆器或磁盤復制器,是一種用于復制硬盤驅動器內容的設備。它可以將一個硬盤上的所有數據,包括操作系統、程序、文件和設置,復制到另一個硬盤上。這種設備在數據備份、系統遷移、硬盤
    的頭像 發表于 10-14 15:38 ?503次閱讀
    主站蜘蛛池模板: 国产午夜在线观看视频| 亚州视频一区| 亚洲日本在线不卡二区| 果冻传媒视频在线观看完整版免费| 亚洲VA天堂VA欧美VA在线| 寂寞夜晚在线视频观看| 3dbdsm变态videos高清| 国偷自产AV一区二区三区健身房| 亚洲综合视频| 男人插曲视频大全免费网站| 俄罗斯一级毛片aaaa| 欧美精品久久久久性色AV苍井| 阿v天堂2017在无码| 甜性涩爱在线播放| 久久九九亚洲精品| xxxxx俄罗斯| 亚洲精品无码一区二区三区四虎| 国产美女又黄又爽又色视频网站| 一个人的视频全免费在线观看www 一个人的免费完整在线观看HD | 和姐姐做插得很深| 97在线免费观看| 麻豆精品传媒2021网站入口| 夜月视频直播免费观看| 欧美乱码伦视频免费66网 | 99影视久久电影网久久看影院| 可以看的黄页的网站| 中文字幕一区久久久久| 九九热这里只有精品视频免费| 亚洲精品tv久久久久久久久久| 果冻传媒在线看免费高清| 538久久视频在线| 午夜影院视费x看| 男人到天堂a线牛叉在线| 国产性色AV内射白浆肛交后入| 99精彩免费观看| 亚洲免费观看| 色综合伊人色综合网站中国| 国产午夜不卡在线观看视频666| 2012中文字幕在线动漫电影| 媚药调教被撑到合不拢h| 国产精品人成在线播放新网站|