Интерфейсы-маркеры, глубокое клонирование - 1

— Привет, Амиго!

— Привет, Билаабо!

— Сегодня я расскажу тебе про интерфейсы-маркеры.

Интерфейсы-маркеры – это интерфейсы, которые не содержат методов. Когда класс наследуется от такого интерфейса, то говорят, что он им помечен.

Примеры таких интерфейсов: Cloneable, Serializable, Remote.

Интерфейс Serializable используется, чтобы помечать классы, которые поддерживают сериализацию — как доказательство того, что объекты класса можно автоматически сериализовать и десериализовать.

Интерфейс Remote используется, чтобы обозначать объекты, которые поддерживают удаленный вызов – вызов из другой Java-машины и/или другого компьютера.

Интерфейс Cloneable используется, чтобы помечать классы, которые поддерживают клонирование.

Кстати, о клонировании.

Клонирование делится на два типа – обычное клонирование и глубокое клонирование.

Обычное клонирование – это когда создается дубликат только указанного объекта, без его внутренних объектов.

Глубокое клонирование – это когда создается дубликат объекта, объектов, на которые он ссылается, объектов, на которые ссылаются они и т.д.

Есть очень хороший способ выполнить качественное глубокое клонирование.

Этот способ подходит, даже если разработчики классов забыли пометить его интерфейсом Cloneable. Достаточно, чтобы объекты были сериализуемыми.

Вот что можно сделать:

1) Создать буфер (массив байт) в памяти.

2) Сериализовать в него нужный объект с подобъектами.

3) Десериализовать из буфера копию сохраненной в него группы объектов.

Код
BigObject objectOriginal = new BigObject();

ByteArrayOutputStream writeBuffer = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(writeBuffer);
outputStream.writeObject(objectOriginal);
outputStream.close();

byte[] buffer = writeBuffer.toByteArray();
ByteArrayInputStream readBuffer = new ByteArrayInputStream(buffer);
ObjectInputStream inputStream = new ObjectInputStream(readBuffer);
BigObject objectCopy = (BigObject)inputStream.readObject();

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

На третьей строчке мы создаем ByteArrayOutputStream – массив байт, который будет динамически растягиваться при добавлении к нему новых данных (как ArrayList).

На 4-й строчке мы создаем ObjectOutputStream, который используется для сериализации.

В пятой строчке мы сериализуем объект objectOriginal в массив байт с помощью outputStream и сохраняем его в массив writeBuffer.

На 8-й строчке мы преобразовываем writeBuffer в обычный массив байт. Дальше мы из этого массива будем «читать» наш новый объект.

На 9-й строчке мы оборачиваем buffer в класс ByteArrayInputStream, чтобы из него можно было читать, как из InputStream.

На 10-й строчке передаем объект readBuffer классу ObjectInputStream, для чтения (десериализации) объекта.

На 11-й строчке мы читаем наш объект и преобразуем его к типу BigObject.

Как тебе?

— Красота.

Кстати, когда код раскрашен разными цветами – гораздо легче его понимать.