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深拷贝和浅拷贝内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mybatis一对多关联关系映射实现过程解析

    Mybatis一对多关联关系映射实现过程解析

    这篇文章主要介绍了Mybatis一对多关联关系映射实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • SpringBoot整合SSO(single sign on)单点登录

    SpringBoot整合SSO(single sign on)单点登录

    这篇文章主要介绍了SpringBoot整合SSO(single sign on)单点登录,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • idea文件被锁无法更改问题

    idea文件被锁无法更改问题

    这篇文章主要介绍了idea文件被锁无法更改问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Java easyui树形表格TreeGrid的实现代码

    Java easyui树形表格TreeGrid的实现代码

    这篇文章主要为大家详细介绍了Java easyui树形表格TreeGrid的实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • 详解spring集成mina实现服务端主动推送(包含心跳检测)

    详解spring集成mina实现服务端主动推送(包含心跳检测)

    本篇文章主要介绍了详解spring集成mina实现服务端主动推送(包含心跳检测),具有一定的参考价值,与兴趣的可以了解一下
    2017-09-09
  • Spring Cache的使用示例详解

    Spring Cache的使用示例详解

    SpringCache是构建在SpringContext基础上的缓存实现,提供了多种缓存注解,如@Cachable、@CacheEvict、@CachePut等,本文通过实例代码介绍了Spring Cache的使用,感兴趣的朋友一起看看吧
    2025-01-01
  • @PathParam和@QueryParam区别简析

    @PathParam和@QueryParam区别简析

    这篇文章主要介绍了@PathParam和@QueryParam区别,分享了相关实例代码,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • Java中数组的使用与注意事项详解(推荐)

    Java中数组的使用与注意事项详解(推荐)

    数组是一组地址连续、长度固定的具有相同类型的数据的集合,通过数组下标我们可以指定数字中的每一个元素,下面这篇文章主要给大家介绍了关于Java中数组的使用与注意事项的相关资料,需要的朋友可以参考下
    2021-08-08
  • Java的几种文件拷贝方式示例详解

    Java的几种文件拷贝方式示例详解

    在Java编程中文件操作是常见且重要的任务之一,其中文件拷贝是一种基本操作,这篇文章主要给大家介绍了关于Java几种文件拷贝方式的相关资料,文中给出了详细的代码示例,需要的朋友可以参考下
    2024-08-08
  • Java使用agent实现main方法之前的实例详解

    Java使用agent实现main方法之前的实例详解

    这篇文章主要介绍了Java使用agent实现main方法之前的实例详解的相关资料,希望通过本文能帮助到大家,让大家理解这部分内容,需要的朋友可以参考下
    2017-10-10

最新评论