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

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

Статья из группы Java Developer
Перевод статьи 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 в случае несоответствия. Чтобы узнать больше о serialversionuid, см. тут. Вопрос 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 Serialization specification adding any field or method comes under compatible change and changing class hierarchy or UN-implementing Serializable interfaces some under non compatible changes). Для получения полного списка совместимых и несовместимых изменений я бы посоветовал прочитать спецификацию сериализации Java. Вопрос 12) Можем ли мы передать сериализованный объект через сеть? Да, вы можете передать сериализованный объект по сети, потому что сериализованный объект Java представляет собой набор байтов, которые могут быть переданы как угодно. Вы также можете сохранить сериализованный объект на диске или в базе данных как Blob. Вопрос 13) Какие типы переменных не сериализуются во время сериализации Java? Этот вопрос иногда задавали по-другому, но цель одна и та же: выяснить, знает ли разработчик Java особенности сериализации static и transient переменных. Поскольку статические переменные принадлежат классу, а не объекту, они не являются частью состояния объекта, поэтому они не сохраняются во время процесса сериализации Java. Поскольку сериализация Java сохраняет только состояние объекта, а не сам объект, transient (временные) переменные также не включаются в процесс сериализации и не являются частью сериализованного состояния объекта. После этого вопроса, возможно, интервьюер спросит: если вы не храните значения этих переменных, то каким будет значение этих переменных после десериализации и воссоздания этого объекта? А это уже, коллеги, сами думайте :) Оригинал статьи здесь.
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Максим Li Уровень 36
28 ноября 2023
First comment😎