Статьи

Клонирование сериализуемых и несериализуемых объектов Java

Часто разработчики полагаются на сторонние библиотеки, чтобы не изобретать велосипед, особенно в мире Java, с такими распространенными проектами, как Apache и Spring. При работе с этими структурами мы часто практически не контролируем поведение своих классов.

Иногда это может привести к проблемам. Например, если вы хотите глубоко клонировать объект, который не предоставляет подходящего метода клонирования, каковы ваши варианты, кроме написания множества кода?

Клонирование через сериализацию

Самый простой подход заключается в клонировании, используя преимущества объекта, являющегося сериализуемым . Apache Commons предоставляет метод для этого, но для полноты ниже приведен код, чтобы сделать это самостоятельно.

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
@SuppressWarnings("unchecked")
public static  T cloneThroughSerialize(T t) throws Exception {
   ByteArrayOutputStream bos = new ByteArrayOutputStream();
   serializeToOutputStream(t, bos);
   byte[] bytes = bos.toByteArray();
   ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
   return (T)ois.readObject();
}
 
private static void serializeToOutputStream(Serializable ser, OutputStream os)
                                                          throws IOException {
   ObjectOutputStream oos = null;
   try {
      oos = new ObjectOutputStream(os);
      oos.writeObject(ser);
      oos.flush();
   } finally {
      oos.close();
   }
}
 
// using our custom method
Object cloned = cloneThroughSerialize (someObject);
 
// or with Apache Commons
cloned = org.apache.commons.lang. SerializationUtils.clone(someObject);

Но что, если класс, который мы хотим клонировать, не Serializable и мы не можем контролировать исходный код или не можем сделать его Serializable ?

Вариант 1 — библиотека глубокого клонирования Java

Есть хорошая маленькая библиотека, которая может глубоко клонировать практически любой объект Java — клонирование . Он использует превосходные возможности отражения Java для предоставления оптимизированных глубоко клонированных версий объектов.

1
2
Cloner cloner=new Cloner();
Object cloned = cloner.deepClone(someObject);

Как видите, это очень просто и эффективно, и требует минимального кода. Помимо этого простого примера, у него есть более продвинутые способности, которые вы можете посмотреть здесь .

Вариант 2 — JSON Cloning

А что, если мы не сможем ввести новую библиотеку в нашу кодовую базу? Некоторые из нас имеют дело с процессами утверждения для введения новых библиотек, и это может не стоить этого для простого варианта использования.

Ну, пока у нас есть какой-то способ сериализации и восстановления объекта, мы можем сделать глубокую копию. Обычно используется JSON, поэтому это хороший кандидат, так как большинство из нас использует одну или другую библиотеку JSON.

Большинство библиотек JSON в Java имеют возможность эффективно сериализовать любой POJO без какой-либо настройки или отображения. Это означает, что если у вас есть библиотека JSON и вы не можете или не будете вводить больше библиотек для обеспечения глубокого клонирования, вы можете использовать существующую библиотеку JSON для получения того же эффекта. Обратите внимание, что этот метод будет медленнее других, но для подавляющего большинства приложений это не вызовет проблем с производительностью.

Ниже приведен пример использования библиотеки GSON .

1
2
3
4
5
6
7
8
@SuppressWarnings("unchecked")
public static  T cloneThroughJson(T t) {
   Gson gson = new Gson();
   String json = gson.toJson(t);
   return (T) gson.fromJson(json, t.getClass());
}
// ...
Object cloned = cloneThroughJson(someObject);

Обратите внимание, что это может сработать, только если скопированный объект имеет конструктор по умолчанию без аргументов. В случае GSON вы можете использовать создателя экземпляра, чтобы обойти это. Другие структуры имеют аналогичные концепции, поэтому вы можете использовать это, если столкнетесь с проблемой с неизменяемым классом, не имеющим конструктор по умолчанию.


Вывод

Одна вещь, которую я действительно рекомендую, состоит в том, что для любых классов, которые вам нужно клонировать, вы должны добавить несколько модульных тестов, чтобы убедиться, что все работает так, как ожидалось. Это может помешать изменениям в классах (например, обновлению версий библиотеки) без вашего ведома, особенно если у вас настроена среда непрерывной интеграции.

Я описал несколько методов для клонирования объекта вне обычных случаев без какого-либо специального кода. Если вы использовали любые другие методы, чтобы получить тот же результат, пожалуйста, поделитесь.

Ссылка: Простое глубокое клонирование сериализуемых и несериализуемых объектов в Java от нашего партнера по JCG Крейга Флихеля в блоге Carfey Software .

Статьи по Теме :