开发Java这么久还不知深浅?

实际开发场景中,你可能遇到过复制一个对象,而针对这个对象修改不应该影响被复制的对象,举个例子:

public Subject getStaticSubject(int subjectTempId, List<Subject> staticSubjects) {
        Subject staticSubject = null;
        for (Subject subject : staticSubjects) {
            if (subject.getId() == subjectTempId) {
                staticSubject = subject;
                break;
            }
        }

        return staticSubject;
    }

这段代码的意思是从静态Subject对象列表中取出一个匹配的Subject:

调用一下:

Subject subject = getStaticSubject(subjectTempId, staticSubjects);

但此时我不想直接用这个Subject,只想用copy它的属性值,看下Subject的定义:

image.png

我们这个时候来说说浅拷贝

浅拷贝:主要在于“浅”字,何为浅? 比如基本数据类型,int、double、byte、boolean、char等,直接复制没问题,因为它们不指向任何内存空间。

实现Java对象浅拷贝很简单:

  1. 实现Cloneable接口,复写clone方法
@Override
    public Object clone() {
        Subject subject = null;
        try {
            subject = (Subject) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return subject;
    }

实际使用:

Subject newSubject = subject.clone();

浅拷贝适用于只复制基本数据类型,修改新对象不影响被复制对象的属性值.

深拷贝

有浅必然也有深,前面说到复制基本数据类型没问题,但如果对象里面有包含了其他引用,直接复制会有什么结果? 没错,跟你想的一样:

修改复制的对象的引用会影响被复制对象的引用

比如Subject对象包含DynamicData引用,直接浅拷贝,新的Subject实例的DynamicData引用指向的是同一块内存空间,

怎么办? 同样的我也要为DynamicData对象也开辟一块新的内存空间,DynamicData也要实现同样的浅拷贝:

@Override
    public Object clone() {
        Subject subject = null;

        try {
            subject = (Subject) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        subject.dynamicData = (DynamicData) dynamicData.clone();
        return subject;
    }

这个时候懂了吗? 但这里又有一个问题,假如Subject里面包含了多个引用类型对象,clone方法岂不是要针对每个引用对象都要做一次浅拷贝?如果引用对象里面又包含了引用对象怎么办?

感觉很晕,这样实现深拷贝太麻烦了。有没有更通用的办法?

答案是:有的,通过序列化就能实现。可以解决多层拷贝的问题。

直接上代码:

/**
     * 深度复制方法,需要对象及对象所有的对象属性都实现序列化.
     */
    public Subject deepCloneSubject() {
        Subject subject = null;
        try {
            // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            // 将流序列化成对象
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            subject = (Subject) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return subject;
    }

实际使用只要这样:

Subject newSubject = subject.deepCloneSubject();

就这样我们低成本的实现了对象之间的深拷贝。

当然你不想写重复的代码,封装成工具类:

public class CloneUtils {
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj){
        T cloneObj = null;
        try {
            //写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            obs.writeObject(obj);
            obs.close();
            
            //分配内存,写入原始对象,生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);
            //返回生成的新对象
            cloneObj = (T) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cloneObj;
    }
}

perfect,再也不怕写一大堆set方法了。

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

推荐阅读更多精彩内容

  • 307、setValue:forKey和setObject:forKey的区别是什么? 答:1, setObjec...
    AlanGe阅读 1,540评论 0 1
  • 相关概念 面向对象的三个特征 封装,继承,多态.这个应该是人人皆知.有时候也会加上抽象. 多态的好处 允许不同类对...
    东经315度阅读 1,938评论 0 8
  • 看了我前面写过的两个片段的梓嘉给我提了点建议,她说文字应该简洁点,故事应该明了一些。我思来想去,她说的很对,毕竟最...
    久是白久的久阅读 342评论 0 0
  • 当你出生的那一天 一个新的生命诞生 当我拥抱你的时候 你对我笑我对你笑 我的生命得到延续 我有许多期许祝福 但我最...
    我有温暖的怀抱阅读 69评论 0 0