Java中的浅拷贝与深拷贝

Java中的浅拷贝与深拷贝

一、前言

在Java中,拷贝(Copy)是指复制一个对象或数据的值,并创建一个新的对象或数据,而不是简单地引用原始对象。Java中的拷贝操作可以分为两种类型:浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。

二、拷贝操作

  • 浅拷贝
    浅拷贝创建一个新对象,该对象与原始对象共享部分或全部属性的引用。换句话说,浅拷贝只复制对象的引用,而不复制引用指向的对象本身。这意味着对于原始对象和浅拷贝对象的某些属性的修改会相互影响。在Java中,可以使用clone()方法来进行浅拷贝。
  • 深拷贝
    深拷贝创建一个新对象,并复制原始对象的所有属性及其引用指向的对象。换句话说,深拷贝会递归复制对象及其关联的所有对象,从而生成一个完全独立的对象。这意味着对于原始对象和深拷贝对象的任何修改都不会相互影响。在Java中,可以通过实现Serializable接口或自定义拷贝方法来实现深拷贝。

注意:对于对象中的引用类型属性,拷贝操作可能会涉及到对引用对象的拷贝方式。如果是浅拷贝,那么引用对象将被共享;如果是深拷贝,那么引用对象也将被递归拷贝。

三、clone()实现浅拷贝

  1. 目标类需要实现 Cloneable 接口,该接口是一个标记接口,表示类支持克隆操作。
  2. 在目标类中,需要重写 Object 类的 clone() 方法,并将访问修饰符设置为 public

    注:文中省略了setter和getter方法

    public class User implements Cloneable {
    
        private String username;
    
        private Integer age;
    
        // 只有一个String类型的value属性
        private Hobby hobby;
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    public static void main(String[] args) {
        // 原始对象
        User source = new User();
        source.setUsername("admin");
        source.setAge(18);
        source.setHobby(new Hobby("游泳"));
        // clone()实现浅拷贝
        try {
            User target = (User) source.clone();
            // 打印各自的值
            System.out.println("===修改前===");
            System.out.println(source);
            System.out.println(target);
            // 修改值后再打印
            target.getHobby().setValue("跑步");
            System.out.println("===修改后===");
            System.out.println(source);
            System.out.println(target);
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
    
    结果记录:
    ===修改前===
    User{username='admin , age=18, hobby=Hobby{value='游泳'}}
    User{username='admin , age=18, hobby=Hobby{value='游泳'}}
    ===修改后===
    User{username='admin , age=18, hobby=Hobby{value='跑步'}}
    User{username='admin , age=18, hobby=Hobby{value='跑步'}}
    

四、序列化实现深拷贝

  1. 目标类需要实现 Serializable 接口,表示该类支持序列化。
    public class User implements Serializable {
    
        private String username;
    
        private Integer age;
    
        private Hobby hobby;
    }
    
    public class Hobby implements Serializable {
    
        private String value;
    }
    
    public static void main(String[] args) {
        // 原始对象
        User source = new User();
        source.setUsername("admin");
        source.setAge(18);
        source.setHobby(new Hobby("游泳"));
        // 序列化实现深拷贝
        try {
            // 将原始对象写入字节流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(source);
            oos.close();
            // 从字节流中读取对象,进行反序列化
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            User target = (User) ois.readObject();
            // 打印各自的值
            System.out.println("===修改前===");
            System.out.println(source);
            System.out.println(target);
            // 修改值后再打印
            target.getHobby().setValue("跑步");
            System.out.println("===修改后===");
            System.out.println(source);
            System.out.println(target);
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    
    结果记录:
    ===修改前===
    User{username='admin , age=18, hobby=Hobby{value='游泳'}}
    User{username='admin , age=18, hobby=Hobby{value='游泳'}}
    ===修改后===
    User{username='admin , age=18, hobby=Hobby{value='游泳'}}
    User{username='admin , age=18, hobby=Hobby{value='跑步'}}
    

五、Spring中的BeanUtils.copyProperties()方法

  • 在 Spring 框架中,BeanUtils.copyProperties() 是一个常用的工具方法,用于将一个 Java 对象的属性值复制到另一个对象中。这个方法可以实现对象之间的属性拷贝,包括基本类型、引用类型和集合类型的属性。
  • BeanUtils.copyProperties() 方法的语法如下:
    public static void copyProperties(Object source, Object target)
    

    其中,source 是源对象,target 是目标对象。该方法会将 source 对象的属性值复制到 target 对象中,属性名称和类型相同的属性会被复制。如果 source 对象的属性在 target 对象中不存在,则会被忽略。需要注意的是,BeanUtils.copyProperties() 方法执行的是浅拷贝,即对于引用类型的属性,只复制了引用而不是创建新的对象。如果需要实现深拷贝,可以考虑使用其他方式,比如手动逐个复制属性或者使用其他工具库。此外,BeanUtils.copyProperties() 方法要求源对象和目标对象的属性名称和类型相同,否则可能会出现类型转换错误或属性丢失的问题。

  • 使用示例:
    public static void main(String[] args) {
        // 原始对象
        User source = new User();
        source.setUsername("admin");
        source.setAge(18);
        source.setHobby(new Hobby("游泳"));
    
        // 目标
        User target = new User();
        BeanUtils.copyProperties(source, target);
    
        // 打印各自的值
        System.out.println("===修改前===");
        System.out.println(source);
        System.out.println(target);
    
        // 修改值后再打印
        target.getHobby().setValue("跑步");
        System.out.println("===修改后===");
        System.out.println(source);
        System.out.println(target);
    }
    
    结果记录:
    ===修改前===
    User{username='admin , age=18, hobby=Hobby{value='游泳'}}
    User{username='admin , age=18, hobby=Hobby{value='游泳'}}
    ===修改后===
    User{username='admin , age=18, hobby=Hobby{value='跑步'}}
    User{username='admin , age=18, hobby=Hobby{value='跑步'}}
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值