成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Java】淺拷貝和深拷貝簡述

BenCHou / 1416人閱讀

摘要:前言在中關(guān)于對象的拷貝我們大致可以分為兩種,一種是淺拷貝也叫引用拷貝,另外一種是深拷貝也稱值拷貝。深拷貝根據(jù)上面的分析,淺拷貝是無法去完成含有除基本數(shù)據(jù)類型之外對象的拷貝的。擴(kuò)展深拷貝除了上述實現(xiàn)方式外,也可以用序列化來實現(xiàn)。

前言

  在Java中關(guān)于對象的拷貝我們大致可以分為兩種,一種是淺拷貝(也叫引用拷貝),另外一種是深拷貝(也稱值拷貝)。

示例

  我相信絕大多數(shù)程序員Ctrl+C、Ctrl+V都玩的很溜,我也一樣哈。工作周報我覺得大家在熟悉不過了吧。以我自身寫周報為例子,為了節(jié)省自己的時間(主要還是自己懶),我基本都是Ctrl+C、Ctrl+V別人寫好的周報格式進(jìn)行現(xiàn)改。一人一份工作周報,總不能有兩個人的周報一字不差、一模一樣的吧。或多或少還是有點出入的,比如改下標(biāo)題,發(fā)件人,工作內(nèi)容等等。

淺拷貝

  定義:被復(fù)制的對象所有的變量都含有與原來對象相同的值,所有的對其他對象的引用都仍然指向原來的對象(即原始的對象和其副本引用同一個對象)。
  
  先來看下程序代碼

/**
 * 工作周報類
 * @author zhh
 * @date 2017-08-23 上午11:03:47
 */
class Report implements Cloneable {
    
    private String title;        // 標(biāo)題
    private String sender;        // 發(fā)送者
    private String receiver;    // 接收者
    private ArrayList content; //內(nèi)容
    
    public Report(String title, String sender, String receiver) {
        this.title = title;
        this.sender = sender;
        this.receiver = receiver;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getSender() {
        return sender;
    }
    public void setSender(String sender) {
        this.sender = sender;
    }
    public String getReceiver() {
        return receiver;
    }
    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }
    public ArrayList getContent() {
        return content;
    }
    public void setContent(ArrayList content) {
        this.content = content;
    }
    
    public void print() {
        System.out.println(this);
    }
    
    @Override
    public Report clone() {
        Report msg = null;
        try {
            msg = (Report) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return msg;
    }
    
    @Override
    public String toString() {
        return "Report [title=" + title + ", sender=" + sender + ", receiver=" + receiver + ", content=" + content
                + "]";
    }
    
}

  舉個例子,我這里拷貝下公司UI小姐姐的周報模板現(xiàn)改現(xiàn)賣,像標(biāo)題,發(fā)送者,內(nèi)容什么的大致還是得改改。寫個主方法測試下。

    public static void main(String[] args) {
        Report report = new Report("yg工作周報", "yg", "boss");
        ArrayList content = new ArrayList<>();
        content.add("1.參加研討會議, 確定需求");
        content.add("2.設(shè)計首頁的icon以及界面");
        report.setContent(content);
        
        Report report1 = report.clone();
        report1.setTitle("zhh工作周報");
        report1.setSender("zhh");
        ArrayList content1 = report1.getContent();
        content1.set(1, "2.搭建基礎(chǔ)的后臺框架");
        report1.setContent(content1);
        
        System.out.println("----------UI小姐姐工作周報--------------");
        report.print();
        System.out.println("----------我的工作周報--------------");
        report1.print();
        
    }

  程序運行的結(jié)果如下:

----------UI小姐姐工作周報--------------
Report [title=yg工作周報, sender=yg, receiver=boss, content=[1.參加研討會議, 確定需求, 2.搭建基礎(chǔ)的后臺框架]]
----------我的工作周報--------------
Report [title=zhh工作周報, sender=zhh, receiver=boss, content=[1.參加研討會議, 確定需求, 2.搭建基礎(chǔ)的后臺框架]]

  雖然執(zhí)行沒有發(fā)生什么異常,但其結(jié)果顯然是不對的。UI小姐姐跟我干的活一樣啦?老板看了顯然也是一臉懵逼的。搞不好我也就被UI小姐姐給頂替掉了(開個玩笑哈)。

  但為什么會這樣呢?克隆以后為什么我的工作內(nèi)容把UI的工作內(nèi)容替換了呢?而其他標(biāo)題、發(fā)送者卻沒有這種情況。
  我們知道在Java當(dāng)中Object類是所有類的頂級父類,而其clone方法只會拷貝對象中的基本數(shù)據(jù)類型,對于數(shù)組、容器對象、引用對象等都不會拷貝。程序Report類自寫的clone方法中 msg = (Report) super.clone(); 就是調(diào)用了Object類的clone方法。String類雖然也是引用類型,但由于其的特殊性(final 類),雖然復(fù)制的引用,但是修改值的時候并沒有改變被復(fù)制對象的值;而ArrayList復(fù)制的僅僅是引用,導(dǎo)致原本引用和副本引用指向同一對象,所以上述代碼修改任意一個對象的content都會影響另外一個。

深拷貝

  根據(jù)上面的分析,淺拷貝是無法去完成含有除基本數(shù)據(jù)類型之外對象的拷貝的。
  定義:被復(fù)制的對象所有的變量都含有與原來對象相同的值,所有的對其他對象的引用也都指向復(fù)制過的新的對象(即原始的對象和其副本引用不同對象)。
  
  這里我們自己實現(xiàn)深拷貝,讓原始對象和其副本對象指向不同對象。
  其實代碼和淺拷貝大致相同,差別只是在Report類重寫的clone方法,這里我就多帶帶拿出來寫下了。

...

    @Override
    public Report clone() {
        Report msg = null;
        try {
            msg = (Report) super.clone();
            // 將引用對象 content 也 clone下
            msg.content = (ArrayList) this.content.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return msg;
    }
...

  測試的主方法同淺拷貝,不做修改直接運行,運行的結(jié)果如下:

----------UI小姐姐工作周報--------------
Report [title=yg工作周報, sender=yg, receiver=boss, content=[1.參加研討會議, 確定需求, 2.設(shè)計首頁的icon以及界面]]
----------我的工作周報--------------
Report [title=zhh工作周報, sender=zhh, receiver=boss, content=[1.參加研討會議, 確定需求, 2.搭建基礎(chǔ)的后臺框架]]

  這里你可以看到,拷貝后兩者的內(nèi)容之間并沒有相互的影響。

擴(kuò)展

  深拷貝除了上述實現(xiàn)方式外,也可以用序列化來實現(xiàn)。

/**
 * 序列化實現(xiàn)深拷貝
 * @author zhh
 * @date 2017-08-23 下午1:04:44
 */
class Report implements Serializable {
    
    private static final long serialVersionUID = -760030405417987698L;
    
    private String title;        // 標(biāo)題
    private String sender;        // 發(fā)送者
    private String receiver;    // 接收者
    private ArrayList content; //內(nèi)容
    
    public Report(String title, String sender, String receiver) {
        this.title = title;
        this.sender = sender;
        this.receiver = receiver;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getSender() {
        return sender;
    }
    public void setSender(String sender) {
        this.sender = sender;
    }
    public String getReceiver() {
        return receiver;
    }
    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }
    public ArrayList getContent() {
        return content;
    }
    public void setContent(ArrayList content) {
        this.content = content;
    }
    
    public void print() {
        System.out.println(this);
    }
    
    @Override
    public Report clone() {
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            // 1.將對象序列化成流
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            
            // 2.將流序列化成對象
            bis = new ByteArrayInputStream(bos.toByteArray());;
            ois = new ObjectInputStream(bis);
            return (Report) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        
    }
    
    @Override
    public String toString() {
        return "Report [title=" + title + ", sender=" + sender + ", receiver=" + receiver + ", content=" + content
                + "]";
    }
    
}

  測試的主方法同淺拷貝,不做修改直接運行,運行的結(jié)果如下:

----------UI小姐姐工作周報--------------
Report [title=yg工作周報, sender=yg, receiver=boss, content=[1.參加研討會議, 確定需求, 2.設(shè)計首頁的icon以及界面]]
----------我的工作周報--------------
Report [title=zhh工作周報, sender=zhh, receiver=boss, content=[1.參加研討會議, 確定需求, 2.搭建基礎(chǔ)的后臺框架]]

  事實證明,用序列化來實現(xiàn)對象的深拷貝也是可行的。主要原因是在對象序列化流的過程當(dāng)中,寫在流里面的是對象的一個拷貝,而原本的對象仍然存在堆內(nèi)。

序列化實現(xiàn)深拷貝過程中,我們實現(xiàn)了Serializable這個空接口,來標(biāo)明Report類可序列化。
這里要說一下 為什么要給 serialVersionUID 賦值
舉個例子,當(dāng)對象序列化存到硬盤上后,比方我修改了這個對象的屬性,那么在反序列化的過程就會出現(xiàn)異常。
一旦我們給 serialVersionUID 賦值,當(dāng)序列化和反序列化的 serialVersionUID 相同的時候,中間過程修改對象屬性就不會像上面拋出異常,而是以屬性的對應(yīng)類型賦默認(rèn)值(如String類型默認(rèn)為null,int類型默認(rèn)為0等等)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/67832.html

相關(guān)文章

  • 【進(jìn)階4-1期】詳細(xì)解析賦值、拷貝和深拷貝的區(qū)別

    摘要:展開語法木易楊通過代碼可以看出實際效果和是一樣的。木易楊可以看出,改變之后的值并沒有發(fā)生變化,但改變之后,相應(yīng)的的值也發(fā)生變化。深拷貝使用場景木易楊完全改變變量之后對沒有任何影響,這就是深拷貝的魔力。木易楊情況下,轉(zhuǎn)換結(jié)果不正確。 一、賦值(Copy) 賦值是將某一數(shù)值或?qū)ο筚x給某個變量的過程,分為下面 2 部分 基本數(shù)據(jù)類型:賦值,賦值之后兩個變量互不影響 引用數(shù)據(jù)類型:賦址,兩個...

    silvertheo 評論0 收藏0
  • JS中的拷貝和深拷貝

    摘要:說明外層數(shù)組拷貝的是實例說明元素拷貝是引用深拷貝在堆中重新分配內(nèi)存,并且把源對象所有屬性都進(jìn)行新建拷貝,拷貝后的對象與原來的對象完全隔離,互不影響。中的方法可以實現(xiàn)深拷貝,源碼原理也是遞歸使用淺拷貝。 1.淺拷貝 當(dāng)把數(shù)組或?qū)ο蠛唵钨x值給其他變量的時候,實際上進(jìn)行的是淺拷貝,淺拷貝是拷貝引用,只是將拷貝后的引用指向同一個對象實例,彼此間的操作還會互相影響。 分為兩種情況:直接拷貝源對象...

    xeblog 評論0 收藏0
  • js的拷貝和深拷貝和應(yīng)用場景

    摘要:而大多數(shù)實際項目中,我們想要的結(jié)果是兩個變量初始值相同互不影響。所以就要使用到拷貝分為深淺兩種深淺拷貝的區(qū)別淺拷貝只復(fù)制一層對象的屬性,而深拷貝則遞歸復(fù)制了所有層級。 為什么會用到淺拷貝和深拷貝 首先來看一下如下代碼 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e = f = {a:...

    MartinDai 評論0 收藏0
  • js的拷貝和深拷貝和應(yīng)用場景

    摘要:而大多數(shù)實際項目中,我們想要的結(jié)果是兩個變量初始值相同互不影響。所以就要使用到拷貝分為深淺兩種深淺拷貝的區(qū)別淺拷貝只復(fù)制一層對象的屬性,而深拷貝則遞歸復(fù)制了所有層級。 為什么會用到淺拷貝和深拷貝 首先來看一下如下代碼 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e = f = {a:...

    nemo 評論0 收藏0
  • js的拷貝和深拷貝和應(yīng)用場景

    摘要:而大多數(shù)實際項目中,我們想要的結(jié)果是兩個變量初始值相同互不影響。所以就要使用到拷貝分為深淺兩種深淺拷貝的區(qū)別淺拷貝只復(fù)制一層對象的屬性,而深拷貝則遞歸復(fù)制了所有層級。 為什么會用到淺拷貝和深拷貝 首先來看一下如下代碼 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e = f = {a:...

    lavor 評論0 收藏0

發(fā)表評論

0條評論

BenCHou

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<