在Java中,如何实现对象的拷贝?

开发 前端
开发中可以使用第三方库如Apache Commons Lang的SerializationUtils类或Google的Guava库来实现对象的深拷贝。这些库提供了更加灵活和方便的深拷贝实现方式,同时也提供了更多的自定义选项和错误处理机制。

在Java中,对象的拷贝可以分为浅拷贝(shallow copy)和深拷贝(deep copy)。

  1. 「浅拷贝」:
  • 创建一个新对象,然后将原始对象中的非静态字段复制到新对象,如果字段是值类型,那么对该字段执行逐位复制。如果字段是引用类型,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。
  • 在Java中,我们可以通过实现Cloneable接口并重写clone()方法来实现浅拷贝。需要注意的是,Object类中的clone()方法是受保护的,所以我们需要在我们的类中将其重写为public。
  • 另外,如果对象的字段也是需要拷贝的复杂对象,那么可能需要在这些类中也实现Cloneable接口并重写clone()方法。
  1. 「深拷贝」:
  • 创建一个新对象,然后将原始对象中的非静态字段复制到新对象。如果字段是值类型,那么对该字段执行逐位复制。如果字段是引用类型,则递归地复制该字段引用的对象,而不是只复制引用。

  • 在Java中,深拷贝通常需要我们自己写代码来实现,因为Java并没有提供直接实现深拷贝的内置方法。

  • 深拷贝的一个常见实现方式是使用序列化。我们可以将对象写入到一个流中,然后再从流中读取出来,这样得到的就是原对象的一个深拷贝。但是这种方法有一些限制,比如被拷贝的对象以及它引用的所有对象都必须是可序列化的。

注意:Cloneable接口和clone()方法的设计在Java社区中常常被认为是有缺陷的,因为它们有很多问题,比如Cloneable接口没有定义任何方法(它是一个标记接口),clone()方法的访问修饰符是protected,而且它使用的是浅拷贝,这可能会导致意外的对象共享问题。因此,在实际编程中,很多开发者更倾向于自己写代码来实现对象的拷贝,而不是使用Cloneable接口和clone()方法。

  1. 通过实现Cloneable接口并重写clone()方法来实现浅拷贝

我们定一个实体类People,实现了Cloneable接口,并且重写了clone()方法当然也是直接调用的父类的clone()方法。

public class People implements Cloneable {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    protected People clone() throws CloneNotSupportedException {
        return (People) super.clone();
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试拷贝:

public class Main {

    public static void main(String[] args) {
        People people = new People();
        people.setName("Reathin");
        people.setAge(30);

        System.out.println("原People" + people.toString());

        try {
            People people1 = people.clone();
            System.out.println("拷贝People" + people1);
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }

    }
}

输出结果如下,我们实现了一次浅拷贝。

图片图片

  1. 通过将原始对象中的非静态字段复制到新对象实现深拷贝
People people2 = new People();
people2.setName(people.getName());
people2.setAge(people.getAge());
System.out.println("深拷贝对象1" + people2);
  1. 通过序列化对象流实现深拷贝
// 序列化对象到字节数组
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(people);
byte[] serializedData = byteArrayOutputStream.toByteArray();

// 从字节数组中反序列化对象以创建深拷贝
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serializedData);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
People people3 = (People) objectInputStream.readObject();
System.out.println("深拷贝对象2" + people3);

最终输出结果如下:

图片图片

完整示例代码:

public class People implements Cloneable, Serializable {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    protected People clone() throws CloneNotSupportedException {
        return (People) super.clone();
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Main {

    public static void main(String[] args) throws IOException, ClassNotFoundException, CloneNotSupportedException {
        People people = new People();
        people.setName("Reathin");
        people.setAge(30);
        System.out.println("原People" + people.toString());

        People people1 = people.clone();
        System.out.println("浅拷贝People" + people1);

        //深拷贝方式一
        People people2 = new People();
        people2.setName(people.getName());
        people2.setAge(people.getAge());
        System.out.println("深拷贝对象1" + people2);

        //深拷贝方式2
        // 序列化对象到字节数组
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(people);
        byte[] serializedData = byteArrayOutputStream.toByteArray();

        // 从字节数组中反序列化对象以创建深拷贝
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serializedData);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        People people3 = (People) objectInputStream.readObject();
        System.out.println("深拷贝对象2" + people3);

    }
}

开发中可以使用第三方库如Apache Commons Lang的SerializationUtils类或Google的Guava库来实现对象的深拷贝。这些库提供了更加灵活和方便的深拷贝实现方式,同时也提供了更多的自定义选项和错误处理机制。


责任编辑:武晓燕 来源: 沐雨花飞蝶
相关推荐

2009-07-01 09:17:36

对象比较Java

2021-04-07 10:12:05

Javascript对象拷贝开发

2024-09-03 10:06:43

JavaMap项目

2018-09-26 14:37:17

JavaScript前端编程语言

2021-06-03 10:00:47

JavaScript 前端数克隆对象

2009-05-19 17:28:44

深拷贝浅拷贝clone()

2022-11-07 11:37:27

深拷贝浅拷贝底层

2023-05-05 08:47:35

Java浅拷贝深拷贝

2020-05-18 10:52:00

前端JavaScript html

2010-09-08 16:50:11

JavaScriptDOM操作

2020-08-19 08:29:22

JavaScript 对象函数

2024-08-02 08:43:24

JavaScript开发者工具箱深拷贝

2022-05-16 08:22:37

零拷贝Netty

2021-07-16 12:33:24

Javascript深拷贝浅拷贝

2009-06-30 09:37:02

对象比较Java

2021-11-10 15:18:16

JavaGo命令

2020-10-12 08:35:22

JavaScript

2024-04-17 09:01:08

Python深拷贝浅拷贝

2020-12-09 09:33:16

编程语言C语言汇编语言

2019-12-09 15:08:30

JavaTomcatWeb
点赞
收藏

51CTO技术栈公众号