探讨Java中的深浅拷贝问题


Posted in Java/Android onJune 26, 2021

一、前言

拷贝这个词想必大家都很熟悉,在工作中经常需要拷贝一份文件作为副本。拷贝的好处也很明显,相较于新建来说,可以节省很大的工作量。在Java中,同样存在拷贝这个概念,拷贝的意义也是可以节省创建对象的开销。

Object类中有一个方法clone(),具体方法如下:

protected native Object clone() throws CloneNotSupportedException;

1.该方法由 protected 修饰,java中所有类默认是继承Object类的,重载后的clone()方法为了保证其他类都可以正常调用,修饰符需要改成public

2.该方法是一个native方法,被native修饰的方法实际上是由非Java代码实现的,效率要高于普通的java方法。

3.该方法的返回值是Object对象,因此我们需要强转成我们需要的类型。

4.该方法抛出了一个CloneNotSupportedException异常,意思就是不支持拷贝,需要我们实现Cloneable接口来标记,这个类支持拷贝。

为了演示方便,我们新建两个实体类DeptUser,其中User依赖了Dept,实体类代码如下:

Dept类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {

    private int deptNo;
    private String name;
}

User类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private int age;
    private String name;
    private Dept dept;
}

二、浅拷贝

对于基本类型的的属性,浅拷贝会将属性值复制给新的对象,而对于引用类型的属性,浅拷贝会将引用复制给新的对象。而像StringInteger这些引用类型,都不是不可变的,拷贝的时候会创建一份新的内存空间来存放值,并且将新的引用指向新的内存空间。不可变类型是特殊的引用类型,我们姑且认为这些final类型的应用也是复制值。

探讨Java中的深浅拷贝问题

浅拷贝功能实现

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Cloneable{

    private int age;
    private String name;
    private Dept dept;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

如何验证我们的结论呢?首先对比被拷贝出的对象和原对象是否相等,不等则说明是新拷贝出的一个对象。其次修改拷贝出对象的基本类型属性,如果原对象的此属性发生了修改,则说明基本类型的属性是同一个,最后修改拷贝出对象的引用类型对象即Dept属性,如果原对象的此属性发生了改变,则说明引用类型的属性是同一个。清楚测试原理后,我们写一段测试代码来验证我们的结论。

public static void main(String[] args) throws Exception{

    Dept dept = new Dept(12, "市场部");
    User user = new User(18, "Java旅途", dept);

    User user1 = (User)user.clone();
    System.out.println(user == user1);
    System.out.println();

    user1.setAge(20);
    System.out.println(user);
    System.out.println(user1);
    System.out.println();

    dept.setName("研发部");
    System.out.println(user);
    System.out.println(user1);
}

上面代码的运行结果如下

false

 

User{age=18, name='Java', dept=Dept{deptNo=12, name='市场部'}}

User{age=20, name='Java', dept=Dept{deptNo=12, name='市场部'}}

 

User{age=18, name='Java', dept=Dept{deptNo=12, name='研发部'}}

User{age=20, name='Java', dept=Dept{deptNo=12, name='研发部'}}

三、深拷贝

相较于浅拷贝而言,深拷贝除了会将基本类型的属性复制外,还会将引用类型的属性也会复制。

探讨Java中的深浅拷贝问题

深拷贝功能实现

在拷贝user的时候,同时将user中的dept属性进行拷贝。

dept类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept implements Cloneable {

    private int deptNo;
    private String name;

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

user类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Cloneable{

    private int age;
    private String name;
    private Dept dept;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        User user = (User) super.clone();
        user.dept =(Dept) dept.clone();
        return user;
    }
}

使用浅拷贝的测试代码继续测试,运行结果如下:

false

 

User{age=18, name='Java旅途', dept=Dept{deptNo=12, name='市场部'}}

User{age=20, name='Java旅途', dept=Dept{deptNo=12, name='市场部'}}

 

User{age=18, name='Java旅途', dept=Dept{deptNo=12, name='研发部'}}

User{age=20, name='Java旅途', dept=Dept{deptNo=12, name='市场部'}}

除此之外,还可以利用反序列化实现深拷贝,先将对象序列化成字节流,然后再将字节流序列化成对象,这样就会产生一个新的对象。

以上就是探讨Java中的深浅拷贝问题的详细内容,更多关于Java深浅拷贝的资料请关注三水点靠木其它相关文章!

Java/Android 相关文章推荐
基于Java的MathML转图片的方法(示例代码)
Jun 23 Java/Android
利用Java设置Word文本框中的文字旋转方向的实现方法
Jun 28 Java/Android
Java常用函数式接口总结
Jun 29 Java/Android
java固定大小队列的几种实现方式详解
Jul 15 Java/Android
Java网络编程之UDP实现原理解析
Sep 04 Java/Android
InterProcessMutex实现zookeeper分布式锁原理
Mar 21 Java/Android
MybatisPlus EntityWrapper如何自定义SQL
Mar 22 Java/Android
Netty分布式客户端接入流程初始化源码分析
Mar 25 Java/Android
零基础学java之带返回值的方法的定义和调用
Apr 10 Java/Android
Spring Boot 实现 WebSocket
Apr 30 Java/Android
Spring Boot优化后启动速度快到飞起技巧示例
Jul 23 Java/Android
Java使用HttpClient实现文件下载
Aug 14 Java/Android
解决SpringBoot跨域的三种方式
Jun 26 #Java/Android
分析Java中Map的遍历性能问题
Jun 26 #Java/Android
SpringCloud的JPA连接PostgreSql的教程
spring项目中切面及AOP的使用方法
Java 中的 Unsafe 魔法类的作用大全
Jun 26 #Java/Android
详解Java线程池是如何重复利用空闲线程的
Jun 26 #Java/Android
Spring Data JPA的Audit功能审计数据库的变更
You might like
php中数据的批量导入(csv文件)
2006/10/09 PHP
CentOS下与Apache连接的PHP多版本共存方案实现详解
2015/12/19 PHP
Yii2中设置与获取别名的函数(setAlias和getAlias)用法分析
2016/07/25 PHP
extjs中grid中嵌入动态combobox的应用
2011/01/01 Javascript
jquery xMarquee实现文字水平无缝滚动效果
2014/04/29 Javascript
JS动态增加删除UL节点LI及相关内容示例
2014/05/21 Javascript
js怎么判断flash swf文件是否加载完毕
2014/08/14 Javascript
js实现最短的XML格式化工具实例
2015/03/12 Javascript
javascript属性访问表达式用法分析
2015/04/25 Javascript
浅谈JavaScript中null和undefined
2015/07/09 Javascript
javascript实现密码验证
2015/11/10 Javascript
如何利用Promises编写更优雅的JavaScript代码
2016/05/17 Javascript
JS集成fckeditor及判断内容是否为空的方法
2016/05/27 Javascript
JavaScript实现计数器基础方法
2017/10/10 Javascript
Vue在H5 项目中使用融云进行实时个人单聊通讯
2020/12/14 Vue.js
[19:15]DK战队纪录片
2014/09/02 DOTA
[52:37]完美世界DOTA2联赛循环赛 Forest vs DM BO2第一场 10.29
2020/10/29 DOTA
Python中zip()函数用法实例教程
2014/07/31 Python
Python字符和字符值(ASCII或Unicode码值)转换方法
2015/05/21 Python
Python中的ctime()方法使用教程
2015/05/22 Python
python监控文件或目录变化
2016/06/07 Python
python 生成器生成杨辉三角的方法(必看)
2017/04/10 Python
Python数据结构之单链表详解
2017/09/12 Python
Python实现加载及解析properties配置文件的方法
2018/03/29 Python
Python文件操作中进行字符串替换的方法(保存到新文件/当前文件)
2019/06/28 Python
Myprotein芬兰官网:欧洲第一运动营养品牌
2019/05/05 全球购物
艺术设计专业个人求职信
2013/09/21 职场文书
生物科学系大学生的自我评价
2013/12/20 职场文书
小学生班会演讲稿
2014/01/09 职场文书
公司活动邀请函
2014/01/24 职场文书
大学本科生职业生涯规划书范文
2014/09/14 职场文书
2014年作风建设工作总结
2014/10/29 职场文书
2015年元旦联欢晚会活动总结
2014/11/28 职场文书
2015年英语教研组工作总结
2015/05/23 职场文书
Redis缓存-序列化对象存储乱码问题的解决
2021/06/21 Redis
我的收音机情缘
2022/04/05 无线电