探讨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 Nio使用NioSocket客户端与服务端交互实现方式
Jun 15 Java/Android
Springboot使用Spring Data JPA实现数据库操作
Jun 30 Java/Android
JavaWeb Servlet实现网页登录功能
Jul 04 Java/Android
JavaGUI模仿QQ聊天功能完整版
Jul 04 Java/Android
Lombok的详细使用及优缺点总结
Jul 15 Java/Android
Java并发编程之原子性-Atomic的使用
Mar 16 Java/Android
java中为什么说子类的构造方法默认访问的是父类的无参构造方法
Apr 13 Java/Android
引用计数法和root搜索算法以及JVM中判定对象需要回收的方法
Apr 19 Java/Android
Spring Boot 使用 Spring-Retry 进行重试框架
Apr 24 Java/Android
Java 定时任务技术趋势简介
May 04 Java/Android
Android Studio实现简易进制转换计算器
May 20 Java/Android
Java实现贪吃蛇游戏的示例代码
Sep 23 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执行速度全攻略
2006/10/09 PHP
PHP如何编写易读的代码
2007/07/10 PHP
PHP 最大运行时间 max_execution_time修改方法
2010/03/08 PHP
php生成随机密码的三种方法小结
2010/09/04 PHP
PHP setTime 设置当前时间的代码
2012/08/27 PHP
PHP面向对象精要总结
2014/11/07 PHP
PHP使用in_array函数检查数组中是否存在某个值
2015/03/25 PHP
Zend Framework教程之分发器Zend_Controller_Dispatcher用法详解
2016/03/07 PHP
php微信公众号开发之微信企业付款给个人
2018/10/04 PHP
php生成word并下载代码实例
2019/03/15 PHP
JQuery,Extjs,YUI,Prototype,Dojo 等JS框架的区别和应用场景简述
2010/04/15 Javascript
javascript对中文按照拼音排序代码
2014/08/20 Javascript
jQuery子窗体取得父窗体元素的方法
2015/05/11 Javascript
常用的JQuery函数及功能小结
2016/03/24 Javascript
浅谈addEventListener和attachEvent的区别
2016/07/14 Javascript
BootStrap 模态框实现刷新网页并关闭功能
2017/01/04 Javascript
jQuery实现动态文字搜索功能
2017/01/05 Javascript
提高Web性能的前端优化技巧总结
2017/02/27 Javascript
js数字计算 误差问题的快速解决方法
2017/02/28 Javascript
微信小程序实现给嵌套template模板传递数据的方式总结
2017/12/18 Javascript
vue左右侧联动滚动的实现代码
2018/06/06 Javascript
Vue 页面状态保持页面间数据传输的一种方法(推荐)
2018/11/01 Javascript
ES6 迭代器与可迭代对象的实现
2019/02/11 Javascript
基于Vue的商品主图放大镜方案详解
2019/09/19 Javascript
layui禁用侧边导航栏点击事件的解决方法
2019/09/25 Javascript
vue自动化路由的实现代码
2019/09/30 Javascript
VUE实现密码验证与提示功能
2019/10/18 Javascript
webpack DllPlugin xxx is not defined解决办法
2019/12/13 Javascript
python实现抖音视频批量下载
2018/06/20 Python
python实现kNN算法识别手写体数字的示例代码
2019/08/16 Python
Python终端输出彩色字符方法详解
2020/02/11 Python
Pycharm和Idea支持的vim插件的方法
2020/02/21 Python
Python PyQt5整理介绍
2020/04/01 Python
类和结构的区别
2012/08/15 面试题
依法行政工作汇报材料
2014/10/28 职场文书
Java中使用Filter过滤器的方法
2021/06/28 Java/Android