JavaRush /Java блог /Random UA /Топ-13 питань про серіалізацію на співбесідах
Dmitry Vasilyev
26 рівень
Саратов

Топ-13 питань про серіалізацію на співбесідах

Стаття з групи Random UA
Переклад статті https://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html Що таке серіалізація в Java? Серіалізація - це одна з важливих концепцій, яка досить рідко використовується як рішення для збереження стану програм, і тому розробники часто не беруть до уваги цей API-інтерфейс. Тим не менш, судячи з мого досвіду, серіалізація - досить важлива тема в будь-якій базовій співбесіді з Java. Майже у всіх інтерв'ю, з якими я стикався, є одне чи два питання про серіалізацію, і я бачив, як після кількох питань на цю тему кандидати починають почуватися некомфортно через відсутність досвіду у цій галузі. Вони не знають, як серіалізувати об'єкт в Java, вони не знайомі з будь-якими прикладами серіалізації і не можуть пояснити механіку її роботи, різницю між transient і volatile змінною, не знають, скільки методів має інтерфейс Serializable. Що таке marker interface? Яким є його призначення? У чому різниця між Externalizable та Serializable імплементацією в Java? А чому після введення інструкції java не замінила Serializable на @Serializable? У цій статті ми розберемо питання як для новачків, так і для просунутих, що може бути однаково корисним для всіх: від джуніорів до старших розробників. У більшості комерційних проектів використовуються або бази даних, або відображені в пам'ять файли , або звичайні "плоскі" файли для забезпечення більшої стійкості, але лише деякі з них покладаються на процес серіалізації в Java. У будь-якому випадку, цей пост не є підручником - він, скоріше, про питання, на які варто для себе прояснити, перш ніж йти на якесь інтерв'ю по Java і дивуватися там невідомим для себе термінам. Для тих, хто не знайомий із серіалізацією Java від слова зовсім: «Серіалізація в Java - це процес, який використовується для сепулювання серіалізації об'єкта в Java шляхом збереження стану об'єкта у файлі з розширенням .ser та відтворення стану об'єкта з цього файлу. Цей зворотний процес називається відповідно десеріалізацією. сепулька Java Serialization API надає розробникам стандартний механізм серіалізації об'єктів з використанням інтерфейсів Serializable і Externalizable. Між іншим, ця стаття є продовженням моїх ( не моїх, перекладача, а автора англійського оригіналу) попередніх статей: 20 питань на співбесіді за шаблонами проектування та 10 питань на співбесіді за шаблоном Singleton у Java . Отже, летс гоу! Що таке серіалізація в Java? Серіалізація об'єктів Java - це процес, що використовується для перетворення об'єкта в двійковий формат, який може бути збережений на диск або відправлений по мережі на будь-яку іншу віртуальну машину Java, що працює; зворотний процес створення об'єкта із двійкового потоку називається десеріалізацією. Java надає API, який включає java.io.Serializable, java.io.Externalizable, ObjectInputStream та ObjectOutputStream і т.д. Програмісти можуть вільно використовувати механізм серіалізації за умовчанням, який використовує Java на основі структури класу, але вони також можуть використовувати власний двійковий формат, що налаштовується, який часто рекомендується як краща практика серіалізації, оскільки серіалізований двійковий формат стає частиною експортованого API класу і потенційно може порушити інкапсуляцію в Java, що надається private та package-private полями. Загалом цієї інформації буде цілком достатньо для початку. Як зробити Java-клас серіалізується? Це дуже легко. Ваш клас просто повинен реалізовувати інтерфейс java.io.Serializable, а JVM подбає про серіалізацію об'єкта у форматі за замовчуванням. Рішення про створення класу, що серіалізується, слід приймати коротко, тому що, хоча короткострокові витрати на створення серіалізованого класу і невисокі, довгострокові витрати значні і потенційно можуть обмежити ваші можливості за подальшими модифікаціями реалізації. Це відбувається тому, що, як і будь-який загальнодоступний API, серіалізована форма об'єкта стає частиною загальнодоступного API, і коли ви змінюєте структуру свого класу, реалізуючи інтерфейс додавання, додавання або видалення будь-якого поля може потенційно порушити стандартну серіалізацію. Однак, це можна мінімізувати, використовуючи двійковий формат, що настроюється, але, як і раніше, потрібно багато зусиль для забезпечення зворотної сумісності. Одним із прикладів того, як серіалізація може накладати обмеження на вашу здатність змінювати клас, є поле SerialVersionUID. Якщо ви явно не оголошує SerialVersionUID, тоді віртуальна машина генерує його на основі структури класу, яка залежить від інтерфейсів, що реалізуються класом, та кількох інших факторів, які можуть бути змінені. Припустимо, що ви реалізуєте інший інтерфейс, на відміну від JVM, яка згенерує інший SerialVersionUID для нової версії файлів класів, і коли ви спробуєте завантажити старий об'єкт, серіалізований старою версією вашої програми, ви отримаєте InvalidClassException. Питання 1) У чому різниця між інтерфейсом Serializable та Externalizable у Java? Це питання, що найбільш часто ставиться на співбесіді з серіалізації Java. Інтерфейс Externalizable надає нам методи writeExternal() та readExternal(), які дають гнучкість для керування серіалізацією замість того, щоб покладатися на механізм за умовчанням. Правильна реалізація інтерфейсу Externalizable може значно покращити продуктивність програми. Питання 2) Скільки методів у Serializable? Якщо немає методу, то якою є мета інтерфейсу Serializable? Інтерфейс, що серіалізується, існує в пакеті java.io і становить ядро ​​механізму серіалізації Java. Він не має жодних методів і також називається інтерфейсом-маркером Java. Коли ваш клас реалізує інтерфейс java.io.Serializable, він стає серіалізованим. Все просто. Питання 3) Що таке serialVersionUID? Що станеться, якщо ви його не визначите? Одне з моїх улюблених питань на співбесіді із серіалізації Java. SerialVersionUID - це ідентифікатор, який ставиться на об'єкт, коли він серіалізується, зазвичай хеш-код об'єкта. Ви можете використовувати serialver інструмент, щоб отримати serialVersionUID серіалізованого об'єкта. SerialVersionUID використовується контролю версій об'єкта. Ви також можете вказати serialVersionUID у своєму файлі класу вручну. Наслідком відсутності вказівки serialVersionUID є те, що при додаванні або зміні будь-якого поля класу вже серіалізований клас не зможе відновитися, тому що serialVersionUID, згенерований для нового класу буде відрізнятися від того ж поля старого серіалізованого об'єкта. Процес серіалізації Java покладається на правильний serialVersionUID для відновлення стану серіалізованого об'єкта та видає виняток java.io.InvalidClassException у разі невідповідності. Щоб дізнатися більше про серійнуверсію, див . Запитання 4) При серіалізації ви хочете, щоб деякі члени не серіалізувалися? Як цього досягти? Ще одне питання, яке часто ставиться на співбесіді з серіалізації. Іноді також запитують, як використовується transient змінна, чи серіалізується transient і static змінна чи ні і т.д., тому, якщо ви не хочете, щоб будь-яке поле було частиною стану об'єкта, оголосіть його як static або transient залежно від ваших потреб, і вона не буде включена в процесі серіалізації Java. Питання 5) Що станеться, якщо один із членів класу не реалізує інтерфейс Serializable? Одне з найпростіших питань про процес серіалізації в Java. Якщо ви спробуєте серіалізувати об'єкт класу, який реалізує Serializable, але об'єкт включає посилання на клас, що не є Serializable, тоді під час виконання буде викинуто NotSerializableException, і тому я завжди поміщаю SerializableAlert (розділ коментарів у моєму коді), один із кращих прийомів коментування коду, щоб вказати розробнику пам'ятати про цей факт при додаванні нового поля до класу Serializable. Питання 6) Якщо клас серіалізується, а його суперклас - ні, яким буде стан змінних екземпляра, успадкованих від суперкласу після десеріалізації? Процес серіалізації Java продовжується лише в ієрархії об'єктів доти, доки клас реалізує інтерфейс Serializable, а значення змінних, успадкованих від суперкласу, будуть ініціалізовані шляхом виклику конструктора суперкласу, що не серіалізується, під час процесу десеріалізації. Як тільки ланцюжок конструкторів буде запущено, зупинити це буде неможливо, тому навіть якщо класи вище в ієрархії (не) реалізують інтерфейс Serializable (в оригіналі, мабуть, друкарська помилка - прим.пер. ), конструктор буде виконаний. Можливо, це питання на співбесіді із серіалізації виглядає дуже складним, але якщо ви знайомі з ключовими концепціями, труднощів не виникне. Питання 7) Чи можете ви налаштувати процес серіалізації або перевизначити процес серіалізації за замовчуванням Java? Відповідь – так, можна. Всі ми знаємо, що для серіалізації об'єкта викликається ObjectOutputStream.writeObject(saveThisObject), а для читання об'єкта викликається ObjectInputStream.readObject(), але є ще одна річ, яку віртуальна машина Java надає вам визначення цих двох методів у вашому класі. Якщо ви визначите їх у своєму класі, JVM викличе ці два методи замість застосування механізму серіалізації за промовчанням. Тут ви можете налаштувати поведінку серіалізації та десеріалізації об'єкта, виконавши будь-яке завдання попередньої або подальшої обробки. Важливо відзначити, що ці методи повинні бути закритими, щоб уникнути успадкування, перевизначення чи перевантаження. Оскільки тільки віртуальна машина Java може викликати private метод, цілісність вашого класу збережеться, і серіалізація буде працювати як завжди. На мій погляд, це одне з найкращих питань, які можна поставити на будь-якій співбесіді з Java Serialization. Хороше наступне питання: навіщо вам надавати серіалізовану форму, що настроюється, для вашого об'єкта? Запитання 8) Припустимо, суперклас нового класу реалізує інтерфейс Serializable, як можна уникнути серіалізації нового класу? Одне зі складних питань на співбесіді із серіалізації в Java. Якщо суперклас класу вже реалізує інтерфейс Serializable в Java, то клас-спадкоємець також є Serializable, оскільки ви не можете не реалізовувати інтерфейс батька, і насправді неможливо зробити його класом Non Serializable. Однак є спосіб уникнути серіалізації для цього нового класу. Для цього вам необхідно реалізувати методи writeObject() та readObject() і викинути NotSerializableException з цих методів. Зазвичай це питання задають як додаткове у міру проходження інтерв'ю. Питання 9) Які методи використовуються в процесі серіалізації та десеріалізації в Java? Це дуже поширене питання у серіалізації. Що в даному випадку намагається дізнатися про інтерв'юер? Чи знайомі ви з використанням readObject(), writeObject(), readExternal() і writeExternal() чи ні. Серіалізація Java виконується класом java.io.ObjectOutputStream. Цей клас є відфільтрованим потіком, який обернений навколо байтового потоку нижнього рівня для обробки механізму серіалізації. Щоб зберегти будь-який об'єкт з допомогою механізму серіалізації, ми викликаємо ObjectOutputStream.writeObject(saveThisObject), а десеріалізації цього об'єкта ми викликаємо метод ObjectInputStream.readObject(). Виклик методу writeObject() запускає процес серіалізації. Одна важлива річ, яку слід зазначити у методі readObject(), полягає в тому, що він використовується для читання байтів і для створення та повернення об'єкта з цих байтів, який, у свою чергу, має бути приведений до правильного типу. Питання 10) Припустимо, у вас є клас, який ви серіалізували та зберегли, а потім змінабо цей клас, щоб додати нове поле. Що станеться, якщо ви десеріалізуєте вже серіалізований об'єкт? Це залежить від того, чи має клас власний serialVersionUID чи ні. Як ми знаємо з вищезазначених питань, якщо ми не надамо serialVersionUID у нашому коді, компілятор java згенерує його сам, і зазвичай він дорівнюватиме хеш-коду цього об'єкта. Після додавання будь-якого нового поля, є ймовірність, що новий serialVersionUID, згенерований для цієї версії класу, не збігається з серіалізованим об'єктом, і в цьому випадку API видасть виняток java.io.InvalidClassException. З цієї причини рекомендується мати свій власний serialVersionUID у коді, який завжди однаковий для одного класу. Питання 11) Які сумісні та несумісні зміни у механізмі серіалізації Java? Справжня проблема полягає у зміні структури класів шляхом додавання будь-якого поля, методу чи видалення будь-якого поля чи методу з уже серіалізованим об'єктом. Відповідно до специфікації Java Serialization додавання будь-якого поля або методу піддається сумісній зміні, а зміна ієрархії класів або інтерфейсів Serializable, що реалізують UN, іноді може викликати несумісність (в оригіналі: As per Java class hierarchy або UN-implementing Serializable interfaces (не може бути змінений). Для отримання повного списку сумісних та несумісних змін я порадив би прочитати специфікацію серіалізації Java. Питання 12) Чи можемо передати серіалізований об'єкт через мережу? Так, ви можете передати серіалізований об'єкт по мережі, тому що серіалізований об'єкт Java є набір байтів, які можуть бути передані як завгодно. Ви також можете зберегти серіалізований об'єкт на диску або базі даних як Blob. Запитання 13) Які типи змінних не серіалізуються під час серіалізації Java? Це питання іноді ставабо по-іншому, але мета та сама: з'ясувати, чи знає розробник Java особливості серіалізації static і transient змінних. Оскільки статичні змінні належать класу, а не об'єкту, вони не є частиною стану об'єкта, тому вони не зберігаються під час серіалізації Java. Оскільки серіалізація Java зберігає тільки стан об'єкта, а не сам об'єкт, transient (тимчасові) змінні також не включаються до серіалізації і не є частиною серіалізованого стану об'єкта. Після цього питання, можливо, інтерв'юер запитає: якщо ви не зберігаєте значення цих змінних, то яким буде значення цих змінних після десеріалізації та відтворення цього об'єкта? А це вже, колеги, самі думайте:) Оригінал статті тут .
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ