专栏首页小巫技术博客开发Java这么久还不知深浅?

开发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的定义:

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

浅拷贝:主要在于“浅”字,何为浅? 比如基本数据类型,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方法了。

本文分享自微信公众号 - 巫山老妖(wwjblog),作者:污748

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Hello Jenkins

    用户1130025
  • 高效mac(二)

    用户1130025
  • 代码Review的一些事

    用户1130025
  • x86_64汇编调试程序初步

    掌握此基础,就可以用来修改无源代码的程序等,比如希望jstatd在指定的端口上监听,而不是一个值为0的随机端口号,请参见《防火墙内JVisualVM连接jst...

    一见
  • 【每天一个数据分析师】面对毫无基础的业务人员,好的分析师解释逻辑,而不是细节

    论坛君 “每天一个数据分析师”在第七期有幸采访到谢宇先生,他是中国联通广西分公司的大数据负责人,有超过7年的电信行业数据挖掘经验,目前主要负责大数据应用规划、基...

    小莹莹
  • DSL 系列(2) - 插件的论述与实现

    本文主要探讨基于 DSL(domain specific language) 之上的插件设计,他们是领域的附属,为领域提供额外的服务,但领域不依赖于他们。

    捷义
  • 用Python将word文件转换成html

    序 最近公司一个客户大大购买了一堆医疗健康方面的科普文章,希望能放到我们正在开发的健康档案管理软件上。客户大大说,要智能推送!要掌握节奏!要深度学习!要让用户...

    Python中文社区
  • 你在看电脑,我们在看你~

    这是早期的一则推特,眼尖的用户能注意到: 似乎扎克伯格的笔记本摄像头和麦克风插口都是用胶带蒙住的 Mark Zuckerberg为什么要把摄像头给封住了? ...

    用户1631416
  • 统一批处理流处理——Flink批流一体实现原理

    无限流处理:输入数据没有尽头;数据处理从当前或者过去的某一个时间 点开始,持续不停地进行

    实时计算
  • 数说专车用户的用车体验

    腾讯研究院首席经济学家 孟昭莉 腾讯研究院高级研究员 孙晓菲 对于最近炙手可热的专车服务,有人质疑,甚至打压,也有人将其视为打破出租车行业垄断、互联网...

    腾讯研究院

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动