开发者

Java中实现对象深克隆的四种方式

目录
  • 方法1:手动实现深克隆
  • 方法2:使用序列化 Serializable
  • 方法3:使用第三方库 Apache Commons Lang(推荐使用,因为一般项目中都会引入这个依赖)
  • 方法4:使用第三方库 Hutool

在Java中实现对象的深克隆(Deep Clone)需要确保对象及其所有引用类型的字段都被复制,而不是共享相同的内存地址。以下是几种常见的实现方式:

方法1:手动实现深克隆

通过重写 clone() 方法并逐层复制引用对象:

@Data
@AllArgsConstructor
@NoArgsConstructor
class Address implements Cloneable {
    private String city;
    
    @Override
    protected Address clone() throws CloneNotSupportedException {
        return (Address) super.clone();
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Person implements Cloneable {
    private String name;
    private Address address;
    private List<String> hobbies;

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        // 深克隆引用对象
        cloned.address = this.address.clone();
        // 若hobbies是自定义对象列表,需逐个深克隆
        return cloned;
    }
}

public class DeepCloneExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address addr = new Address("Beijing");
        List<String> hobbies = List.of("reading", "swimming");
        Person p1 = new Person("Alice", addr, hobbies);
        
        // 深克隆
        Person p2 = p1.clone();
        
        // 修改克隆对象的属性,不会影响原对象
        p2.getAddress().setCity("Shanghai");
        p2.getHobbies().add("running");
        
        System.out.println(p1.getAddress().getCity()); // 输出: Beijing
        System.out.println(p2.getAddresandroids().getCity()); // 输出: Shanghai
        System.out.println(androidp1.getHobbies()); // 输出: [reading, swimming]
        System.out.println(p2.getHobbies()); // 输出: [reading, swimming, running]
    }
}

关键点:

  1. 实现 Cloneable 接口:标记类支持克隆。
  2. 重写 clone() 方法:调用 super.clone() 后,手动复制引用类型字段。
  3. 逐层深克隆:对每个引用对象(如 Address)也需实现深克隆。

方法2:使用序列化 Serializable

通过序列化和反序列化实现深克隆:

@Data
@AllArgsConstructor
@NoArgsConstructor
class Address implements Serializable {
    private static final long serialVersionUID = 1L;
    private String city;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private Address address;
    private List<String> hobbies;
    
    // 深克隆方法
    public Person deepClone() {
      // 序列化
      try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"))) {
          oos.writeObject(this);
      } catch (Exception e) {
          e.printStackTrace();
      }

      // 反序列化
      try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"))) {
          return (Person) ois.readObject();
      } catch (Exception e) {
          e.printStackTrace();
      }
        
    }
}

public class DeepCloneBySerialization {
    public static void main(String[] args) {
        Address addr = new Address("Beijing");
        List<String> hobbies = new ArrayList<>(List.of("reading", "swimming"));
        Person p1 = new Person("Alice", addr, hobbies);
        
        // 深克隆
        Person p2 = p1.deepClone();
        
        // 修改克隆对象的属性,不会影响原对象
        p2.getAddress().setCity("Shanghai");
        p2.getHobbies().add("running");
        
        System.out.println(p1.getAddress().getCity()); // 输出: Beijing
        System.out.println(p2.getAddress().getCity()); // 输出: Shanghai
        System.out.println(p1.getHobbies()); // 输出: [reading, swimming]
        System.out.println(p2.getHobbies()); // 输出: [reading, swimming, running]
    }
}

使用 ByteArrayOutputStream 将对象序列化为内存中的字节数组。 再通过 ByteArrayInputStream 从内存中读取该字节数组并反序列化成新对象。 整个过程不涉及任何磁盘 I/O,完全在内存中完成,效率更高。

import java.io.*;

public class DeepCloneUtil {
    public static <T extends Serializable> T deepClone(T object) {
        try (
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
        ) {
            // 序列化对象到内存中的字节数组
            oos.writeObject(object);

            try (
                ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bis);
            ) {
                // 反序列化并返回新对象
                return (T) ois.readObject();
            }
        } catch (IOException | ClassNotFoundException e) {
      js      throandroidw new RuntimeException("深克隆失败", e);
        }
    }

    public static void main(String[] args) {
        Address address = new Address("Beijing");
        Person person1 = new Person("Alice", address, List.of("reading", "swimming"));

        // 深克隆
        Person person2 = DeepCloneUtil.deepClone(person1);

        // 修改克隆对象的属性,不会影响原对象
        person2.getAddress().setCity("Shanghai");

        System.out.println(person1.getAddress().getCity()); // 输出: Beijing
        System.out.println(person2.getAddress().getCity()); // 输出: Shanghai
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Address implements Serializable {
    private static final long编程客栈 serialVersionUID = 1L;
    private String city;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private Address address;
    private List<String> hobbies;
}

关键点:

  1. 实现 Serializable 接口:所有类(包括嵌套类)必须可序列化。
  2. 通过流操作:将对象序列化为字节流,再反序列化为新对象,确保所有引用都被复制。
  3. 自动处理嵌套对象:无需手动逐层克隆

方法3:使用第三方库 Apache Commons Lang(推荐使用,因为一般项目中都会引入这个依赖)

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>

使用 SerializationUtils.clone()

import org.apache.commons.lang3.SerializationUtils;

// 确保所有类实现Serializable接口
class Address implements Serializable { /* ... */ }
class Person implements Serializable { /* ... */ }

public class DeepCloneWithLibrary {
    public static void main(String[] args) {
        // 创建对象
        Person p1 = new Person("Alice", new Address("Beijing"), List.of("reading"));
        
        // 深克隆
        Person p2 = SerializationUtils.clone(p1);
        
        // 修改克隆对象,不影响原对象
        p2.getAddress().setCity("Shanghai");
    }
}

方法4:使用第三方库 Hutool

使用 CloneUtil.cloneByStream(obj)

需要对象及其嵌套对象实现 java.io.Serializable 接口

@Data
@AllArgsConstructor
@NoArgsConstructor
class Address implements java.io.Serializable {
  private String city;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Person implements java.io.Serializable {
  private String name;
  private Address address;
}

public class HutoolDeepCloneExample {
  public static void main(String[] args) {
    Address addr = new Address("Beijing");
    Person p1 = new Person("Alice", addr);
    
    Person p2 = CloneUtil.cloneByStream(p1);
    
    p2.getAddress().setCity("Shanghai"); // 修改克隆对象的属性,不会影响原对象
    System.out.println(p1.getAddress().getCity()); // 输出: Beijing
    System.out.println(p2.getAddress().getCity()); // 输出: Shanghai
  }
}

到此这篇关于Java中实现对象深克隆的四种方式的文章就介绍到这了,更多相关Java实现对象深克隆内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新开发

开发排行榜