浅谈 Java 浅拷贝&深拷贝

深拷贝和浅拷贝的概念,我自己在学习Java的时候也没注意,虽然Java中对象回收工作由GC帮我们做了,但在码代码时如果不注意也会埋下隐藏的BUG,今天我们深入探究一下深拷贝和浅拷贝。

我们在写代码时经常会需要将一个对象传递给另一个对象,Java语言中对于基本型变量采用的是值传递,而对于非基本类型对象传递时采用的引用传递也就是地址传递,而很多时候对于非基本类型对象传递我们也希望能够象值传递一样,使得传递之前和之后有不同的内存地址。在两种情况就是我们今天要讨论的 浅拷贝深拷贝

有Java基础的同学可能发现上面论述有些不严谨,String 类型在传递时其实也是值传递,因为 String 类型是不可变对象。

浅拷贝

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

下面我们看一个例子:

public class Book implements Cloneable {
    String bookName;
    double price;
    Person author;

    public Book(String bn, double price, Person author) {
        bookName = bn;
        this.price = price;
        this.author = author;
    }

    public Object clone() {
        Book b = null;
        try {
            b = (Book) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return b;
    }

    public static void main(String args[]) {
        Person p = new Person("Dream", 34);
        Book book1 = new Book("Java开发", 30.00, p);
        Book book2 = (Book) b1.clone();
        book2.price = 44.00;
        book2.author.setAge(45);
        book2.author.setName("Fish");
        book2.bookName = "Android开发";
        System.out.print("age = " + book1.author.getAge() + "  name = " 
        + book1.bookName + "     price = " + book1.price);
        System.out.println();
        System.out.print("age = " + book2.author.getAge() + "  name = " 
        + book2.bookName + "     price = " + book2.price);
    }
}

结果:

age = 45 name = Java开发 price = 30.0

age = 45 name = Android开发 price = 44.0

从结果中发现在改变 book2 对象的 name 和 price 属性时 book1 的属性并不会跟随改变,当改变 book2 对象的 author 属性时 book1 的 author 对象的属性也改变了,说明 author 是浅拷贝,和 book1 的 author 是使用同一引用。这时我们就需要使用深拷贝了。

深拷贝

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

为了解决上面 Person 对象未完全拷贝问题,我们需要用到深拷贝,其实很简单在拷贝book对象的时候加入如下语句:

b.author =(Person)author.clone(); //将Person对象进行拷贝,Person对象需进行了拷贝

结果

age = 34 name = Java开发 price = 30.0

age = 45 name = Android开发 price = 44.0

上面是用 clone() 方法实现深拷贝,传统重载clone()方法,但当类中有很多引用时,比较麻烦。 当然我们还有一种深拷贝方法,就是将对象 序列化

把对象写到流里的过程是序列化(Serilization)过程;而把对象从流中读出来的反序列化(Deserialization)过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。

在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。

还是上面的例子,我们重写 clone() 方法:

public Object deepClone() throws IOException, OptionalDataException, ClassNotFoundException {
    // 将对象写到流里
    OutputStream bo = new ByteArrayOutputStream();
    //OutputStream op = new ObjectOutputStream();
    ObjectOutputStream oo = new ObjectOutputStream(bo);
    oo.writeObject(this);

    // 从流里读出来
    InputStream bi = new ByteArrayInputStream(((ByteArrayOutputStream) bo).toByteArray());
    ObjectInputStream oi = new ObjectInputStream(bi);
    return (oi.readObject());
}

然后在拷贝对象时调用重写的 deepClone() 方法

Book book2 = (Book) b1.deepClone();

结果

age = 34 name = Java开发 price = 30.0

age = 45 name = Android开发 price = 44.0

PS:这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象可否设成transient(自行了解)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 307、setValue:forKey和setObject:forKey的区别是什么? 答:1, setObjec...
    AlanGe阅读 1,525评论 0 1
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,121评论 29 470
  • 是谁在我脑子里种下这些观念:金钱如粪土、为富不仁、金钱是万恶之源……从古到今,很多人参与了,很多还是圣贤。 我不想...
    听见震撼阅读 729评论 0 0
  • 愿得一人心 白首不相离 一直在路上,难得有这样,一个人,悠闲醒来的清晨。思绪,在心灵深处随意涂鸦,感觉好极了,特别...
    孟婷阅读 266评论 0 0
  • 2015年10月,你说要请我喝咖啡,我说好啊,其实我一点也不爱喝咖啡。后来我问你为什么会是我呢?大半夜的,你发了一...
    陈清诚阅读 301评论 0 0