如何在内存序列化中使用Java深克隆对象
在我以前的文章中,我解釋了深度克隆和淺層克隆之間的區(qū)別 , 以及復(fù)制構(gòu)造函數(shù)和防御性復(fù)制方法比默認的Java克隆更好。
使用復(fù)制構(gòu)造函數(shù)和防御性復(fù)制方法進行的Java對象克隆當然具有某些優(yōu)勢,但是我們必須顯式編寫一些代碼才能在所有這些方法中實現(xiàn)深度克隆。 而且,仍然有可能我們會錯過某些東西并且不會得到深克隆的對象。
正如在Java中創(chuàng)建對象的5種不同方式所討論的那樣,對序列化對象進行反序列化將創(chuàng)建一個狀態(tài)與序列化對象相同的新對象。 因此,與上述克隆方法類似,我們也可以使用對象序列化和反序列化來實現(xiàn)深度克隆功能,并且通過這種方法,我們不必擔心或編寫用于深度克隆的代碼,默認情況下會得到它。
但是,使用序列化克隆對象會帶來一些性能開銷,如果我們只需要克隆對象而不需要將其持久保存在文件中以備將來使用,則可以通過使用內(nèi)存中序列化來改進它。
我們將使用以下Employee類作為示例,其name ,
作為狀態(tài)的doj和skills ,對于深度克隆,我們無需擔心code> name字段,因為它是String對象,默認情況下是all
弦在本質(zhì)上是不變的 。
您可以在《 如何在Java中創(chuàng)建不可變的類》以及《 為什么String是不可變的和Final》上閱讀有關(guān)不可變性的更多信息。
Employee class 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; } name; } public LocalDate getDoj() { return doj; } doj; } public List<String> getSkills() { return skills; } 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); } } 為了深度克隆Employee類的對象,我提供了一個
deepClone()方法,通過使用將對象序列化到內(nèi)存
ByteArrayOutputStream而不是FileOutputStream并使用ByteArrayInputStream而不是FileInputStream將其反序列化。 在這里,我們將對象序列化為字節(jié),然后再次將其從字節(jié)反序列化為對象。
Employee類實現(xiàn)Serializable接口來實現(xiàn)序列化,這有其自身的缺點,我們可以通過使用Externalizable接口自定義序列化過程來克服其中的一些缺點。
我們可以在下面的測試中運行,以了解我們的克隆方法是深層克隆還是淺層克隆,此處所有==操作將返回false(因為兩個對象是分開的),而所有equals將返回true(因為兩者具有相同的內(nèi)容)。
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())); }我們知道反序列化過程每次都會創(chuàng)建一個新對象,如果我們必須使我們的類單身,那將是不好的。 這就是為什么我們需要重寫和禁用單例類的序列化,這可以通過提供writeReplace和readResolve方法來實現(xiàn)。
與序列化類似,Java克隆也不能與單例模式一起使用,這就是為什么我們也需要覆蓋和禁用它。 我們可以通過實現(xiàn)克隆的方式來做到這一點,以便它要么拋出
CloneNotSupportedException或每次都返回相同的實例。
您可以在Java Cloning和Java上閱讀有關(guān)Java克隆和序列化的更多信息。
Java序列化主題。
您可以在此找到本文的完整源代碼。
Github存儲庫 ,請隨時提供寶貴的反饋。
翻譯自: https://www.javacodegeeks.com/2019/08/deep-clone-using-java-memory-serialization.html
總結(jié)
以上是生活随笔為你收集整理的如何在内存序列化中使用Java深克隆对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (安卓电视tv)
- 下一篇: ziplinux解压命令(zip lin