Java中深拷贝和浅拷贝的区别解析

 更新时间:2024年01月16日 10:45:02   作者:user2025  
这篇文章主要介绍了Java中深拷贝和浅拷贝的区别解析,浅拷贝是源对象和拷贝对象的存放地址不同,但被复制的源对象的引用类型属性存放的地址仍然和源对象的引用类型属性相同,修改引用类型属性的属性会影响相互影响,需要的朋友可以参考下

引用拷贝和对象拷贝

(1)引用拷贝:将对象的引用赋值给引用类型的变量

Object obj = new Object();
Object obj1 = obj;

(2)对象拷贝 创建对象的一个副本,其中副本和源对象的引用是两个不同的地址,而不是把一个引用赋值给一个新的引用类型的变量

class Demo{
    public static void main(String[] args) throws CloneNotSupportedException {
        User user = new User();
        User user1 = (User)user.clone();
        System.out.println(user);
        System.out.println(user1);
    }
}
class User implements Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

浅拷贝和深拷贝都是对象拷贝

  • 浅拷贝:源对象和拷贝对象的存放地址不同,但被复制的源对象的引用类型属性存放的地址仍然和源对象的引用类型属性相同,修改引用类型属性的属性会影响相互影响。
  • 深拷贝:源对象和拷贝对象的存放地址不同,源对象和拷贝对象各自的引用类型存放的地址也和源对象的引用类型属性不同,修改引用类型属性的属性不会相互影响拷贝对象和源对象。

常见的浅拷贝方式

(1)一个引用类型变量直接赋值给另一个变量

(2)BeaUtil.copyProperties()

常见的深拷贝方式

(1)通过构造器或new的方式

(2)重写继承至Object方法的clone方法,并实现Cloneable接口 如果在没有实现Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常,实现Cloneable 接口的目的是:为了告知JVM,此对象允许拷贝

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        User user = new User(1, "测试");
        User user1 = user.clone();
        System.out.println(user1);
    }
}
class User implements Cloneable{
    private Integer id;
    private String name;
	//必须重写此方法
    @Override
    protected User clone() throws CloneNotSupportedException {
        return (User)super.clone();
    }
    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

注意: 当通过Cloneable接口实现深拷贝时,拷贝的源对象的属性如果是引用对象(String类型除外),则该属性也需要实现Cloneable接口,并覆写clone方法,否则该属性是进行的浅拷贝。

深拷贝特殊情况(String类型)

String类型属性:Clonable拷贝后两个对象的相同属性指向了通过字符串,但字符串是不可以修改的,存放在常量池中,当其中1个对象的该属性指向另个字符串时,另外一个对象的属性的引用仍指向原字符串。

public class ProtoTypeDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.setId(1L);
        person.setName("test");
        User user = new User();
        user.setUsername("测试");
        person.setUser(user);
        Person person1 = person.clone();
        User user1 = user.clone();
        user1.setUsername("cs");
        person1.setUser(user1);
        System.out.println(person1);//Person{id=1, name='test', user=User{username='cs'}}
        System.out.println(person);//Person{id=1, name='test', user=User{username='测试'}}
    }
}
public class Person implements Cloneable {
    private Long id;
    private String name;
    private User user;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", user=" + user +
                '}';
    }
}
public class User implements Cloneable{
    private String username;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    @Override
    public User clone() throws CloneNotSupportedException {
        return (User) super.clone();
    }
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                '}';
    }
}

(3)序列化的方式:FastJson、Gson等都可以

class Main{
    public static void main(String[] args) {
        User user = new User(1, "测试");
        //序列化
        String s = JSONObject.toJSONString(user);
        //反序列化
        System.out.println(s);
        User user1 = JSON.parseObject(s, User.class);
        System.out.println(user1);
    }
}
public class User {
    private Integer id;
    private String name;
    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

到此这篇关于Java中深拷贝和浅拷贝的区别解析的文章就介绍到这了,更多相关Java深拷贝和浅拷贝内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用Java将XLS转为XLSX格式

    使用Java将XLS转为XLSX格式

    在处理 Excel 文件时,常常会遇到两种主要的格式.xls 和 .xlsx,本文将介绍如何使用 Java 来实现 .xls 和 .xlsx 格式的相互转换,有需要的可以了解下
    2025-11-11
  • Java利用Spire.Doc实现XML转PDF的实战指南

    Java利用Spire.Doc实现XML转PDF的实战指南

    本文介绍了使用Spire.DocforJava将XML转换为PDF的过程,首先说明了XML和PDF的应用场景,然后通过Maven引入依赖,核心代码展示了加载XML并转换为PDF的方法,最后讨论了进阶设置、注意事项及常见问题,帮助开发者更好地完成转换任务,需要的朋友可以参考下
    2026-04-04
  • 深入了解Java语言中的并发性选项有何不同

    深入了解Java语言中的并发性选项有何不同

    这篇文章主要介绍了深入了解Java语言中的并发性选项有何不同,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,,需要的朋友可以参考下
    2019-06-06
  • springboot中在非bean类中调用bean的实现方法

    springboot中在非bean类中调用bean的实现方法

    在Spring Boot中,非Bean类调用Bean方法通常需要通过静态方法获取Bean实例,然后调用相应的方法,这种方法避免了直接在非Bean类中注入Bean,保持了代码的简洁和可维护性,通过这种方式,可以在不改变原有代码结构的情况下,实现Bean方法的调用
    2025-02-02
  • POI XSSFSheet shiftRows bug问题解决

    POI XSSFSheet shiftRows bug问题解决

    这篇文章主要介绍了POI XSSFSheet shiftRows bug问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • Java中list.contains()的用法及拓展

    Java中list.contains()的用法及拓展

    List集合相信大家在开发过程中几乎都会用到,有时候难免会遇到集合里的数据是重复的,需要进行去除,下面这篇文章主要给大家介绍了关于Java中list.contains()的用法及拓展的相关资料,需要的朋友可以参考下
    2023-03-03
  • java非官方常用类MessageInfo消息接口示例

    java非官方常用类MessageInfo消息接口示例

    这篇文章主要为大家介绍了java非官方常用类MessageInfo消息接口使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • SpringBoot连接Redis集群教程

    SpringBoot连接Redis集群教程

    这篇文章主要介绍了SpringBoot连接Redis集群教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • Java变量和对象的作用域

    Java变量和对象的作用域

    本文主要介绍了Java变量和对象的作用域的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-03-03
  • Java CRM系统用户登录功能实现代码实例

    Java CRM系统用户登录功能实现代码实例

    这篇文章主要介绍了Java CRM系统用户登录功能实现代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04

最新评论