如何在内存序列化中使用Java深克隆对象

In my previous articles, I had explained the difference between deep and shallow cloning and how copy-constructors and defensive copy methods are better than default java cloning.

Ĵava object cloning using copy constructors and defensive copy methods certainly have some advantages but we have to explicitly write some code to achieve deep cloning in all these approaches. And still, there are chances that we might miss something and do not get deeply cloned object.

And as discussed in 5 different ways to create objects in java, deserialising a serialised object creates a new object with the same state as in the serialized object. So similar to above cloning approaches we can achieve deep cloning functionality using object serialization and deserialization as well and with this approach we do not have worry about or write code for deep cloning, we get it by default.

但是,使用序列化克隆对象会带来一些性能开销,我们可以通过使用进行改进内存中序列化如果我们只需要克隆对象,而无需将其保存在文件中以备将来使用。

We will use below Employee class as an example which has name, doj and skills as the state, for deep cloning we do not need to worry about the code>name field because it is a String object and by default all strings are immutable in nature.

You can read more about immutability on How to Create an Immutable Class in Java and Why String is Immutable and Final.

class Employee implements Serializable {
    private static final long serialVersionUID = 2L;

    private String name;
    private LocalDate doj;
    private List<String> skills;

    public Employee(String name, LocalDate doj, List<String> skills) {
        this.name = name;
        this.doj = doj;
        this.skills = skills;
    }

    public String getName() { return name; }
    public LocalDate getDoj() { return doj; }
    public List<String> getSkills() { return skills; }

    // Method to deep clone a object using in memory serialization
    public Employee deepClone() throws IOException, ClassNotFoundException {
        // First serializing the object and its state to memory using ByteArrayOutputStream instead of FileOutputStream.
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bos);
        out.writeObject(this);

        // And then deserializing it from memory using ByteArrayOutputStream instead of FileInputStream.
        // Deserialization process will create a new object with the same state as in the serialized object,
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream in = new ObjectInputStream(bis);
        return (Employee) in.readObject();
    }

    @Override
    public String toString() {
        return String.format("Employee{name='%s', doj=%s, skills=%s}", name, doj, skills);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;

        return Objects.equals(name, employee.name) &&
            Objects.equals(doj, employee.doj) &&
            Objects.equals(skills, employee.skills);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, doj, skills);
    }
}

深度克隆对象雇员我提供的课程deepClone()通过使用以下方法将对象序列化到内存的方法ByteArrayOutputStream而不是FileOutputStream并反序列化使用ByteArrayInputStream而不是FileInputStream。 在这里,我们将对象序列化为字节,然后再次将其从字节反序列化为对象。

How To Deep Clone An Object Using Java In Memory Serialization

Employee class implements Serializable interface to achieve serialization which has its own disadvantages and we can overcome some of these disadvantages by customizing the serialization process by using Ëxternalizable interface.

我们可以在下面的测试中运行,以了解我们的克隆方法是深克隆还是浅克隆,此处全部==操作将返回false(因为两个对象是分开的)并且所有等于将返回true(因为两者的内容相同)。

public static void main(String[] args) throws IOException, ClassNotFoundException {
 Employee emp = new Employee("Naresh Joshi", LocalDate.now(), Arrays.asList("Java", "Scala", "Spring"));
 System.out.println("Employee object: " + emp);

 // Deep cloning `emp` object by using our `deepClone` method.
 Employee clonedEmp = emp.deepClone();
 System.out.println("Cloned employee object: " + clonedEmp);

 System.out.println();

 // All of this will print false because both objects are separate.
 System.out.println(emp == clonedEmp);
 System.out.println(emp.getDoj() == clonedEmp.getDoj());
 System.out.println(emp.getSkills() == clonedEmp.getSkills());

 System.out.println();

 // All of this will print true because `clonedEmp` is a deep clone of `emp` and both have the same content.
 System.out.println(Objects.equals(emp, clonedEmp));
 System.out.println(Objects.equals(emp.getDoj(), clonedEmp.getDoj()));
 System.out.println(Objects.equals(emp.getSkills(), clonedEmp.getSkills()));
}

我们知道反序列化过程每次都会创建一个新对象,如果我们必须使我们的类单身,那将是不好的。 这就是为什么我们需要重写和禁用单例类的序列化,这可以通过提供writeReplace和readResolve方法来实现。

与序列化类似,Java克隆也不能与单例模式一起使用,这就是为什么我们也需要覆盖和禁用它。 我们可以通过实现克隆的方式来做到这一点,以便它要么抛出CloneNotSupportedException或每次都返回相同的实例。

You can read more about Java cloning and serialization on Java Cloning and Java Serialization topics.

You can find the complete source code for this article on this Github Repository and please feel free to provide your valuable feedback.

from: https://dev.to//njnareshjoshi/how-to-deep-clone-an-object-using-java-in-memory-serialization-43a2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值