Java >> Java tutorial >  >> Java

Sådan dybkloner du et objekt ved hjælp af Java i hukommelsesserialisering

I mine tidligere artikler havde jeg forklaret forskellen mellem dyb og overfladisk kloning, og hvordan kopikonstruktører og defensive kopimetoder er bedre end standard java-kloning.

Java-objektkloning ved hjælp af kopikonstruktører og defensive kopimetoder har helt sikkert nogle fordele, men vi skal eksplicit skrive noget kode for at opnå dyb kloning i alle disse tilgange. Og stadig er der chancer for, at vi går glip af noget og ikke får dybt klonet objekt.

Og som diskuteret på 5 forskellige måder at skabe objekter i java, skaber deserialisering af et serialiseret objekt et nyt objekt med samme tilstand som i det serialiserede objekt. Så i lighed med ovenstående kloningsmetoder kan vi opnå dyb kloningsfunktionalitet ved at bruge objektserialisering og deserialisering også, og med denne tilgang behøver vi ikke bekymre os om eller skrive kode til dyb kloning, vi får det som standard.

Men kloning af et objekt ved hjælp af serialisering kommer med nogle præstationsomkostninger, og vi kan forbedre det ved at bruge in-memory serialisering hvis vi bare skal klone objektet og ikke behøver at bevare det i en fil til fremtidig brug.

Vi vil bruge nedenfor Employee klasse som et eksempel, der har name ,
doj og skills som tilstand behøver vi ikke at bekymre os om feltet kode>navn for dyb kloning, fordi det er et String-objekt og som standard alle
strenge er uforanderlige i naturen.

Du kan læse mere om uforanderlighed på, hvordan man opretter en uforanderlig klasse i Java, og hvorfor streng er uforanderlig og endelig.

0102030405060708091011121314151617181920212223242526272829303132333343536373734543454dclass 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);      } }

At dybklone et objekt med Employee klasse jeg har givet en
deepClone() metode, som serialiserer objektet til hukommelsen ved at bruge
ByteArrayOutputStream i stedet for FileOutputStream og deserialiserer det tilbage ved hjælp af ByteArrayInputStream i stedet for FileInputStream . Her serialiserer vi objektet til bytes og deserialiserer det fra bytes til objekt igen.

Medarbejderklasse implementerer Serializable interface for at opnå serialisering, som har sine egne ulemper, og vi kan overvinde nogle af disse ulemper ved at tilpasse serialiseringsprocessen ved at bruge Externalizable interface.

Vi kan køre nedenstående tests for at se, om vores kloningstilgang er dyb eller bare lavvandet, her alle == operationer vil returnere falsk (fordi begge objekter er separate) og alle equals vil returnere sand (fordi begge har det samme indhold).

01020304050607080910111213141516171819202122 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())); }

Vi ved, at deserialiseringsprocessen skaber et nyt objekt hver gang, hvilket ikke er godt, hvis vi skal lave vores klasse singleton. Og det er derfor, vi er nødt til at tilsidesætte og deaktivere serialisering for vores singleton-klasse, som vi kan opnå ved at levere writeReplace og readResolve-metoder.

I lighed med serialisering spiller Java-kloning heller ikke sammen med singleton-mønster, og det er derfor, vi skal tilsidesætte og deaktivere det også. Vi kan gøre det ved at implementere kloning på en måde, så det enten vil kaste
CloneNotSupportedException eller returner den samme forekomst hver gang.

Du kan læse mere om Java-kloning og serialisering på Java-kloning og
Java serialisering emner.

Du kan finde den komplette kildekode til denne artikel om dette
Github Repository, og du er velkommen til at give din værdifulde feedback.

Java tag