Інтерфейси-маркери, глибоке клонування - 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, для читання (десеріалізації) об'єкта.

/p>

На 11-му рядку ми читаємо наш об'єкт і перетворимо його до типу BigObject.

Як тобі?

— Краса.

До речі, коли код розфарбований різними кольорами – набагато легше його розуміти.