В моих предыдущих статьях я объяснил разницу между глубоким и мелким клонированием и тем, как конструкторы копирования и методы защитного копирования лучше, чем стандартное клонирование Java.
Клонирование Java-объектов с использованием конструкторов копирования и методов защитного копирования, безусловно, имеет некоторые преимущества, но мы должны явно написать некоторый код для достижения глубокого клонирования во всех этих подходах. И все же есть вероятность, что мы можем что-то упустить и не получить глубоко клонированный объект.
И как обсуждалось в 5 различных способах создания объектов в Java , десериализация сериализованного объекта создает новый объект с тем же состоянием, что и в сериализованном объекте. Таким образом, аналогично описанным выше подходам клонирования, мы можем достичь функциональности глубокого клонирования, используя сериализацию и десериализацию объектов, и с этим подходом у нас не возникает проблем с написанием кода для глубокого клонирования или его написанием, мы получаем его по умолчанию.
Однако клонирование объекта с использованием сериализации приводит к некоторому снижению производительности, и мы можем улучшить его, используя сериализацию в памяти, если нам просто нужно клонировать объект и не нужно сохранять его в файле для будущего использования.
 Мы будем использовать ниже класс Employee в качестве примера, который имеет name , 
  doj и skills как состояние, для глубокого клонирования нам не нужно беспокоиться о поле code> name, потому что это объект String и по умолчанию все 
  Строки являются неизменными по своей природе . 
Вы можете прочитать больше об неизменяемости в разделе Как создать неизменяемый класс в Java и почему String является неизменным и окончательным .
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | classEmployee implementsSerializable {    privatestaticfinallongserialVersionUID = 2L;    privateString name;    privateLocalDate doj;    privateList<String> skills;    publicEmployee(String name, LocalDate doj, List<String> skills) {        this.name = name;        this.doj = doj;        this.skills = skills;    }    publicString getName() { returnname; }    publicLocalDate getDoj() { returndoj; }    publicList<String> getSkills() { returnskills; }    // Method to deep clone a object using in memory serialization    publicEmployee deepClone() throwsIOException, ClassNotFoundException {        // First serializing the object and its state to memory using ByteArrayOutputStream instead of FileOutputStream.        ByteArrayOutputStream bos = newByteArrayOutputStream();        ObjectOutputStream out = newObjectOutputStream(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 = newByteArrayInputStream(bos.toByteArray());        ObjectInputStream in = newObjectInputStream(bis);        return(Employee) in.readObject();    }    @Override    publicString toString() {        returnString.format("Employee{name='%s', doj=%s, skills=%s}", name, doj, skills);    }    @Override    publicbooleanequals(Object o) {        if(this== o) returntrue;        if(o == null|| getClass() != o.getClass()) returnfalse;        Employee employee = (Employee) o;        returnObjects.equals(name, employee.name) &&            Objects.equals(doj, employee.doj) &&            Objects.equals(skills, employee.skills);    }    @Override    publicinthashCode() {        returnObjects.hash(name, doj, skills);    }} | 
  Для глубокого клонирования объекта класса Employee я предоставил 
  deepClone() который сериализует объект в память с помощью 
  ByteArrayOutputStream вместо FileOutputStream и десериализовывает его обратно, используя ByteArrayInputStream вместо FileInputStream .  Здесь мы сериализуем объект в байты и снова десериализуем его из байтов в объект. 

  Класс Employee реализует интерфейс Serializable для достижения сериализации, которая имеет свои недостатки, и мы можем преодолеть некоторые из этих недостатков, настроив процесс сериализации с помощью интерфейса Externalizable . 
  Мы можем запустить тесты ниже, чтобы увидеть, является ли наш подход клонирования глубоким или просто поверхностным, здесь все операции == вернут false (потому что оба объекта разделены), а все equals вернут true (потому что оба имеют одинаковое содержимое). 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | publicstaticvoidmain(String[] args) throwsIOException, ClassNotFoundException { Employee emp = newEmployee("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 или возвращать один и тот же экземпляр каждый раз. 
  Вы можете прочитать больше о клонировании и сериализации Java на Java Cloning и 
  Темы сериализации Java . 
 
  Вы можете найти полный исходный код этой статьи на этом 
  Github Repository и, пожалуйста, не стесняйтесь оставить свой ценный отзыв. 
| Опубликовано на Java Code Geeks с разрешения Нареша Джоши, партнера нашей программы JCG . См. Оригинальную статью здесь: Как глубоко клонировать объект, используя Java в сериализации памяти Мнения, высказанные участниками Java Code Geeks, являются их собственными. |