最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的clone,sallow?copy和deep?copy的區(qū)別解析

 更新時間:2026年02月27日 09:10:29   作者:楊DaB  
本文給大家介紹了Java中的clone,sallow?copy和deep?copy的區(qū)別解析,介紹了克隆的概念和作用,以及淺克隆和深克隆的區(qū)別,感興趣的朋友跟隨小編一起看看吧

克隆的概念和作用

  1. 方法需要 return 引用類型,但又不希望自己本身 持有引用類型的對象被修改。
  2. 程序之間方法的調(diào)用時參數(shù)的傳遞。有些場景為了保證引用類型的參數(shù)不被其他方法修改,可以使用克隆后的值作為參數(shù)傳遞。

sallow copy和deep copy的區(qū)別

sallow copy(淺克隆)

  • 復(fù)制基本類型的屬性;
  • 引用類型的屬性復(fù)制,
    • 復(fù)制棧中的變量 和 變量指向堆內(nèi)存中的對象的指針,
    • 不復(fù)制堆內(nèi)存中的對象。

兩個對象使用的引用類型的屬性會互相影響

deep copy(深克?。?/h3>
  • 復(fù)制基本類型的屬性;
  • 引用類型的屬性復(fù)制,
    • 復(fù)制棧中的變量;
    • 賦值變量指向堆內(nèi)存中的對象的指針和堆內(nèi)存中的對象。
  • 等同于重新創(chuàng)建一個一模一樣的對象,并復(fù)制里面的屬性(數(shù)據(jù)內(nèi)容);
  • 測試的時候可以結(jié)合==equal進行學(xué)習(xí),== 比較的是基本數(shù)據(jù)類型,
    • A1=A1:true,0x006E != x006ER:false
    • A1.equals(A1):true,0x006E .equals(x006ER):true

如何實現(xiàn)deep copy

  1. 實現(xiàn) Cloneable 接口,重寫 clone() 方法。
  2. 不實現(xiàn) Cloneable 接口,會報 CloneNotSupportedException 異常。
  3. Objectclone() 方法是淺拷貝,即如果類中屬性有自定義引用類型,只拷貝引用,不拷貝引用指向的對象。

方法1、對象的屬性的Class 也實現(xiàn) Cloneable 接口,克隆對象的同時也克隆屬性。

@Override
public Object clone() throws CloneNotSupportedException {
    DPerson p = (DPerson)super.clone();
    p.setFood((DFood)p.getFood().clone());
    return p;
}

如下:

  1. DPerson 類實現(xiàn) Cloneable接口,重寫clone()方法,將對象 和屬性全部clone;
  2. DPerson 引用的對象Food類 實現(xiàn)Cloneable接口,重寫clone()方法;
  3. 在主程序中調(diào)用DPerson 中的clone()方法,更改克隆后的對象內(nèi)的屬性進行測試
/**
 * 測試克隆
 */
public class TestManalDeepClone {
    public static void main(String[] args) throws Exception {
        DPerson p1 = new DPerson(1, "AKA000", new DFood("米飯"));//創(chuàng)建Person 對象 p1
        DPerson p2 = (DPerson)p1.clone();//克隆p1
        p2.setName("AKA121");//修改p2的name屬性
        p2.getFood().setName("面條");//修改p2的自定義引用類型 food 屬性
        System.out.println(p1);//修改p2的自定義引用類型 food 屬性被改變,p1的自定義引用類型 food 屬性也隨之改變,說明p2的food屬性,只拷貝了引用,沒有拷貝food對象
        System.out.println(p2);
    }
}
class DPerson implements Cloneable {
    private int pid;
    private String name;
    private DFood food;
    public DPerson(int pid, String name, DFood food) {
        this.pid = pid;
        this.name = name;
        this.food = food;
        System.out.println("Person constructor call");
    }
    public int getPid() {
        return pid;
    }
    public void setPid(int pid) {
        this.pid = pid;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        DPerson p = (DPerson)super.clone();
        p.setFood((DFood)p.getFood().clone());
        return p;
    }
    @Override
    public String toString() {
        return "Person [pid:"+pid+", name:"+name+", food:"+food.getName()+"]";
    }
    public DFood getFood() {
        return food;
    }
    public void setFood(DFood food) {
        this.food = food;
    }
}
class DFood implements Cloneable{
    private String name;
    public DFood(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

方法2、結(jié)合序列化(JDK java.io.Serializable 接口、JSON格式、XML格式等),完成深拷貝

手寫一個方法 cloneBySerizalizable(),使用 ByteStream流和ObjectSteam流實現(xiàn);

    /**
     * 通過序列化完成克隆
     * @return
     */
    public Object cloneBySerializable() {
        Object obj = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            obj = ois.readObject();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return obj;
    }

如下:

  1. 整體思想:將數(shù)據(jù)序列化成為字節(jié)流,再反序列化為數(shù)據(jù)行程對象的clone,做出一個全新的、與原始對象完全獨立的對象。;
  2. 編寫cloneBySerializable()方法,創(chuàng)建一個Object對象,設(shè)置為成員變量初始化為null,做傳輸使用;
  3. 創(chuàng)建 ByteArrayOutputStream 容器,用于接收和存儲后續(xù)寫入的字節(jié)數(shù)據(jù)
  4. 創(chuàng)建一個對象輸出流 ObjectOutputStream oos = new ObjectOutputStream(baos); ,包裝在 ByteArrayOutputStream 之上,不能獨立存在,必須依賴一個底層的輸出流,指定數(shù)據(jù)最終的去向。
  5. 使用writeObject 方法,將當(dāng)前對象 (this) 序列化為字節(jié)流。這些字節(jié)數(shù)據(jù)被寫入到 ByteArrayOutputStream這個內(nèi)存容器中。
  6. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 將對象反序列化會bais中,在通過 ObjectInputStream 進行讀取, ObjectInputStream 必須包裝在 ByteArrayInputStream 之中;
  7. 通過readObject 方法,從字節(jié)流中讀取數(shù)據(jù)并反序列化,最終創(chuàng)建出一個全新的對象。
  8. 在主程序中調(diào)用DPerson 中的cloneBySerializable()方法,更改克隆后的對象內(nèi)的屬性進行測試
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class TestSeriazableClone {
    public static void main(String[] args) {
        SPerson p1 = new SPerson(1, "AKA000", new SFood("米飯"));//創(chuàng)建 SPerson 對象 p1
        SPerson p2 = (SPerson)p1.cloneBySerializable();//克隆 p1
        p2.setName("AKA001");//修改 p2 的 name 屬性
        p2.getFood().setName("面條");//修改 p2 的自定義引用類型 food 屬性
        System.out.println(p1);//修改 p2 的自定義引用類型 food 屬性被改變,p1的自定義引用類型 food 屬性未隨之改變,說明p2的food屬性,只拷貝了引用和 food 對象
        System.out.println(p2);
    }
}
class SPerson implements Cloneable, Serializable {
    private static final long serialVersionUID = -7710144514831611031L;
    private int pid;
    private String name;
    private SFood food;
    public SPerson(int pid, String name, SFood food) {
        this.pid = pid;
        this.name = name;
        this.food = food;
        System.out.println("Person constructor call");
    }
    public int getPid() {
        return pid;
    }
    public void setPid(int pid) {
        this.pid = pid;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 通過序列化完成克隆
     * @return
     */
    public Object cloneBySerializable() {
        Object obj = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            obj = ois.readObject();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return obj;
    }
    @Override
    public String toString() {
        return "Person [pid:"+pid+", name:"+name+", food:"+food.getName()+"]";
    }
    public SFood getFood() {
        return food;
    }
    public void setFood(SFood food) {
        this.food = food;
    }
}
class SFood implements Serializable {
    private static final long serialVersionUID = -3443815804346831432L;
    private String name;
    public SFood(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

到此這篇關(guān)于Java中的clone,sallow copy和deep copy的區(qū)別解析的文章就介紹到這了,更多相關(guān)java clone,sallow copy和deep copy區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解如何將JAR包發(fā)布到Maven中央倉庫

    詳解如何將JAR包發(fā)布到Maven中央倉庫

    這篇文章主要介紹了詳解如何將JAR包發(fā)布到Maven中央倉庫,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • spring-boot-maven-plugin引入出現(xiàn)爆紅(已解決)

    spring-boot-maven-plugin引入出現(xiàn)爆紅(已解決)

    這篇文章主要介紹了spring-boot-maven-plugin引入出現(xiàn)爆紅(已解決),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • java實現(xiàn)將結(jié)果集封裝到List中的方法

    java實現(xiàn)將結(jié)果集封裝到List中的方法

    這篇文章主要介紹了java實現(xiàn)將結(jié)果集封裝到List中的方法,涉及java數(shù)據(jù)庫查詢及結(jié)果集轉(zhuǎn)換的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-07-07
  • Spring Boot集成BCryptPasswordEncoder實現(xiàn)密碼加密與驗證的實現(xiàn)方案

    Spring Boot集成BCryptPasswordEncoder實現(xiàn)密碼加密與驗證的實現(xiàn)方案

    文章介紹了如何在SpringBoot中集成BCryptPasswordEncoder實現(xiàn)密碼的加密和驗證,包括添加依賴、配置BCryptPasswordEncoder、在用戶注冊和登錄時使用BCryptPasswordEncoder進行密碼處理,以及注意事項,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • Java線程在什么情況下可以終止

    Java線程在什么情況下可以終止

    Thread線程類自帶的stop方法,但是jdk不建議使用,因為stop方法終止線程只是強行終止,內(nèi)存中部分值可能已發(fā)生變化,并未保證數(shù)據(jù)的一致性,將會導(dǎo)致線程安全問題,那么在什么情況下可以終止線程呢,本篇帶你探究一下
    2022-04-04
  • SpringBoot實現(xiàn)短信驗證碼校驗方法思路詳解

    SpringBoot實現(xiàn)短信驗證碼校驗方法思路詳解

    最近做項目遇到這樣的需求,前端是基于BootStrap,html代碼中有BootStrap樣式實現(xiàn)的,具體后臺實現(xiàn)代碼大家通過本文一起學(xué)習(xí)吧
    2017-08-08
  • Spring如何通過@Lazy注解解決構(gòu)造方法循環(huán)依賴問題

    Spring如何通過@Lazy注解解決構(gòu)造方法循環(huán)依賴問題

    循環(huán)依賴其實就是循環(huán)引用,也就是兩個或則兩個以上的bean互相持有對方,最終形成閉環(huán),這篇文章主要給大家介紹了關(guān)于Spring如何通過@Lazy注解解決構(gòu)造方法循環(huán)依賴問題的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • Java 前臺加后臺精品圖書管理系統(tǒng)的實現(xiàn)

    Java 前臺加后臺精品圖書管理系統(tǒng)的實現(xiàn)

    相信每一個學(xué)生學(xué)編程的時候,應(yīng)該都會寫一個小項目——圖書管理系統(tǒng)。為什么這么說呢?我認為一個學(xué)校的氛圍很大一部分可以從圖書館的氛圍看出來,而圖書管理系統(tǒng)這個不大不小的項目,接觸的多,也比較熟悉,不會有陌生感,能夠練手,又有些難度,所以我的小項目也來了
    2021-11-11
  • SpringBoot 異常處理/自定義格式校驗的問題實例詳解

    SpringBoot 異常處理/自定義格式校驗的問題實例詳解

    文章探討Spring Boot中自定義注解校驗問題,區(qū)分參數(shù)級與類級約束觸發(fā)的異常類型,建議通過@RestControllerAdvice統(tǒng)一處理,并說明如何獲取不同錯誤類型(FieldError/ObjectError)的信息差異,感興趣的朋友一起看看吧
    2025-07-07
  • JAVA中簡單的for循環(huán)異常踩坑

    JAVA中簡單的for循環(huán)異常踩坑

    這篇文章主要為大家介紹了JAVA中簡單的for循環(huán)異常踩坑避雷詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07

最新評論

万安县| 高淳县| 苍溪县| 海原县| 定州市| 嘉兴市| 和顺县| 舒城县| 南陵县| 兴化市| 乌兰县| 两当县| 凌云县| 平原县| 黔南| 凤翔县| 隆子县| 邵阳市| 建昌县| 红桥区| 龙门县| 迁安市| 华容县| 江都市| 苍溪县| 宣武区| 昭平县| 馆陶县| 上饶市| 和平区| 湖州市| 商城县| 岗巴县| 财经| 城固县| 怀远县| 邛崃市| 纳雍县| 土默特右旗| 湘潭市| 昌宁县|