Java中的浅拷贝与深拷贝
一、前言
在Java中,拷贝(Copy)是指复制一个对象或数据的值,并创建一个新的对象或数据,而不是简单地引用原始对象。Java中的拷贝操作可以分为两种类型:浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。
二、拷贝操作
- 浅拷贝
浅拷贝创建一个新对象,该对象与原始对象共享部分或全部属性的引用。换句话说,浅拷贝只复制对象的引用,而不复制引用指向的对象本身。这意味着对于原始对象和浅拷贝对象的某些属性的修改会相互影响。在Java中,可以使用clone()方法来进行浅拷贝。 - 深拷贝
深拷贝创建一个新对象,并复制原始对象的所有属性及其引用指向的对象。换句话说,深拷贝会递归复制对象及其关联的所有对象,从而生成一个完全独立的对象。这意味着对于原始对象和深拷贝对象的任何修改都不会相互影响。在Java中,可以通过实现Serializable接口或自定义拷贝方法来实现深拷贝。
注意:对于对象中的引用类型属性,拷贝操作可能会涉及到对引用对象的拷贝方式。如果是浅拷贝,那么引用对象将被共享;如果是深拷贝,那么引用对象也将被递归拷贝。
三、clone()实现浅拷贝
- 目标类需要实现
Cloneable接口,该接口是一个标记接口,表示类支持克隆操作。 - 在目标类中,需要重写
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='跑步'}}
四、序列化实现深拷贝
- 目标类需要实现
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='跑步'}}
本文介绍了Java中对象拷贝的两种主要方式:浅拷贝和深拷贝。浅拷贝只复制对象的引用,而深拷贝会递归复制所有属性及引用的对象。文章通过示例展示了如何使用`clone()`方法实现浅拷贝,通过序列化实现深拷贝,以及Spring的`BeanUtils.copyProperties()`方法进行浅拷贝。
1421

被折叠的 条评论
为什么被折叠?



