Сериализация

Réussis tes devoirs et examens dès maintenant avec Quizwiz!

Что такое сериализация и десериализация?

Сериализация - это процесс сохранения состояния объекта в последовательность байт. Десериализация - это процесс восстановления объекта из этих байт.

Чем отличаются интерфейсы Serializable и Externalizable?

1) Externalizable extends Serializable 2) Интерфейс Serializable полностью реализует виртуальная машина JVM. 3) Интерфейс Externalizable имеет методы writeExternal() и readExternal(), которые позволяют вручную указать - какие поля записывать. Это может в том числе повысит производительность.

Что такое serialVersionUID? Как он указывается? Что если его не определить?

1) SerialVersionUID - это "штамп" или код, который присваивается объекту при сериализации. Этот штамп позволяет отслеживать "версию" класса или объекта, который сериализуется или десериализуется. 2) Указывается в классе: *private static final long serialVersionId = ... * 3) Если SerialVersionId не задать явно, то при малейшем изменении класса (переименовали поле) оно изменится. 4) Если объект был сериализован, то теперь его не восстановить: его serialVersionId будет отличаться от сохраненного. Метод readObject() в этом случае только выдаст java.io.InvalidClassException.

Чем отличаются методы восстановления объекта в интерфейсах Serializable и Externalizable?

1) Serializible не использует конструктор объекта - он просто восстанавливает его полностью из последовательности байтов. 2.1) Externalizible вначале вызывает public конструктор объекта без параметров, а затем наполняет поля объекта значениями. 2.2) Если у класса не будет public конструктора без параметров, при попытке десериализовать объект выпадет java.io.InvalidClassException.

Какие поля в классе Java не сериализуются?

1) static поля - они часть класса, а не объекта. Следовательно, они не указывают на состояние объекта. 2) transient поля - модификатор как раз и говорит о том, что "это поле не отмечает состояние объекта". Следовательно, его не нужно сериализовать.

Какие объекты и методы используются при сериализации и де-сериализации в Java?

1) Интерфейс Serializable: void java.io.ObjectOutputStream.*writeObject*(object) Object java.io.ObjectInputStream.*readObject*() Также есть методы ручного чтения примитивных полей: readInt(), readFloat, writeByte и т.д. 2) Интерфейс Externalizable: void java.io.Externalizable.*readExternal*(ObjectInputStream in) void java.io.Externalizable.*writeExternal*(ObjectOutputStream out)

Что будет, если у нас класс Serializable, а его класс-родитель - нет?

1) В случае, если в цепочке классов (child -> parent -> grandparent) какой-то из них не Serializable, то он инициализируется *public конструктором без параметров*. 2) Даже если выше не-Serializable класса другие классы Serializable, это уже не важно - дальше создание идет просто по цепочке конструкторов. 3) Если в цепочке у какого-то класса не окажется конструктора без параметров - вылезет *java.io.InvalidClassException* с сообщением "no valid constructor".

А что если у нас Serializable класс содержит поля, в которых объекты не Serializable?

1) В таком случае код *скомпилируется*. 2) Но *в рантайме* при попытке сериализации , когда мы дойдем до этого поля и объекта, мы получим *NotSerializableException*.

Можно ли передавать сериализованный объект по сети интернет?

1) Да, сериализованный объект - это просто набор байтов. 2) Его спокойно можно передать по сети и в другом месте восстановить объект. 3) Также объект можно хранить в таком виде в базе данных или в файле.

Зачем вообще нужна сериализация?

1) Данные в памяти "живут", до момента завершения приложения. Сериализация позволяет записать объекты в файлы и, таким образом, восстановить их затем. 2) Сериализация предоставляет универсальный механизм обмена данными между компонентами приложения или узлами в интернете.

(Сериализация) Если у нас несколько объектов и мы хотим их сохранить в один файл - что мы делаем?

1) Делаем один FileOutputStream == fos 2) Оборачиваем его в ObjectOutputStream(fos) == oos 3) Пишем: oos.writeObject(object1); oos.writeObject(object2); ... oos.flush(); oos.close(); 4) Когда читаем объекты методом ObjectInputStream.readObject(), то получаем их в том же порядке, как они записаны.

Мы хотим, чтобы при сериализации значения некоторых полей не сохранялись. Как этого достичь?

1) Добавить к полю модификатор transient. В таком случае после восстановления его значение будет null. 2) Сделать поле static. Значения статических полей автоматически не сохраняются. Впрочем, это можно сделать вручную: ObjectOutputStream oos = new ...; oos.writeInt(obj.staticField1); oos.writeObject(a); 3) Также можно написать свои методы read/writeObject или read/writeExternal и записать в них только те поля, которые нам нужны.

Вы взяли класс и сериализовали его объект. Затем вы добавили новое поле в классе. После чего - пытаетесь десериализовать объект. Что произойдет?

1) Если в классе не был указан serialVersionUID, то выпадет InvalidClassException, поскольку у класса он поменяется. 2) Если же был объявлен - объект восстановится. При этом восстановит значения в поля, что были до сериализации восстановятся, а новые инициализируются как 0, null и т.д.

Перечислит шаги, которые выполняет механизм сериализации при сериализации объекта (что за чем записывается в поток)

1) Запись метаданных: указание, что это сериализация, версия сериализации, указание "сейчас начнется объект". 2.1) Запись рекурсивно данных о классе объекта *"снизу вверх"*: класс -> super -> supersuper и т.д пока не будет достигнут java.lang.Object. *Сам класс Object не пишется.* 2.2) При описании пишется имя класса, имена и тип его полей, примитивных и ссылок. Для ссылок просто указывается, что "там объект", без описания класса. 3.1) Запись значений данных в экземпляре, *"сверху вниз"*: parent -> sub -> subsub... 3.2) Если поле - ссылка на объект, то рекурсивно идет запись объекта: описания полей "снизу вверх", затем написание значений "сверху вниз".

Что будет с работой интерфейсов Serizalizable и Externalizable в случае, если переменная - final?

1) Интерфейс Serializable отработает без проблем - он использует рефлексию для создания объекта. При этом используются методы ObjectInputStream.defaultReadObject() и ObjectOutputStream.defaultWriteObject(). 2) Однако, если мы создадим свои методы readObject() и writeObject(), то Serizalizable не сможет присвоить значение переменной: будет жаловаться, что она final. 3) У интерфейса Externalizable будет проблема в методе readExternal(). Он не сможет сделать this.field = in.readValue(). Потому что создает объект конструктором, а затем меняет значение.

Что за интерфейс Serializable?

1) Интерфейс java.io.Serializable - это интерфейс-маркер, в нем нет методов. 2) Если класс реализует интерфейс, это говорит сериализующему механизму, что этот класс можно сериализовать.

Что нужно сделать, чтобы ДЕсериализовать объект?

1) Класс объекта должен реализовывать интерфейс Serializable 2) Создать поток *ObjectInputStream* (ois), в который передать *InputStream* (instream) (из файла, из памяти...) 3) Получить объект и привести к нужному типу: MyObject my = (MyObject) *ois.readObject*(instream)

Что нужно сделать, чтобы сериализовать объект?

1) Класс объекта должен реализовывать интерфейс Serializable 2) Создать поток *ObjectOutputStream* (oos), который записывает объект в переданный *OutputStream*. 3) Записать в поток: *oos.writeObject*(Object); 4) Сделать oos.flush() и oos.close()

Где ставится ключевое слово transient? Что оно означает?

1) Слово transient ("временный, переходный") - это модификатор для поля класса. 2) Если поле объявлено transient, это значит, что значение этого поля не нужно записывать при сериализации. 3) При восстановлении объекта у него будет это поле, но со значением null (0, false).

Зачем может понадобиться вручную определять методы сериализации (read/writeObject, read/writeExternal)?

1) Чтобы сериализовать не все поля. 2) Чтобы повысить производительность. 3) Чтобы зашифровать данные в полях.

Что такое совместимые и несовместимые изменения в механизме серилизации Java? Какие это изменения?

Compatible и incompatible changes - изменения в классе, после которых ранее сериализованные объекты еще можно как-то восстановить или нельзя. 1) Совместимые добавление, изменение, удаление поля или метода. 2) Несовместимые: изменение места класса в иерархии классов (например, extends другого родителя), удаление надписи implements Serializable.

Можно ли как-то вручную управлять процессом сериализации в Java?

Да, можно. Мы можем создать в классе методы: 1) *private void writeObject(ObjectOutputStream out) throws IOException* *private void readObject(ObjectInputStream in)t hrows IOException, ClassNotFoundException* Увидев эти методы, JVM будет вызывать их вместо стандартных. ВНИМАНИЕ: это *НЕ @Override!* Но это фича на уровне JVM. 2) Внутри этих методов можно вызвать "обычную" их реализацию, написав: out.defaulWriteObject(); in.defaultReadObject();

Как легко сгенерировать serialVersionUID для класса?

Для этого есть утилита *serialver*, имеющаяся в JDK: $ serialver -classpath . Hello Hello: static final long SerialVersionUID = -4862926644813433707L;

Вы сериализовали объект, а затем переименовали поле. Что будет при восстановлении?

Если в объекте указан serialVersionUID, то объект восстановится, но значение в поле - нет. Оно будет инициализировано null, 0 и т.д.

Что будет, если мы попробуем сериализовать класс, в котором не написано implements Serializable?

Код скомпилируется, но во время выполнения выкинет *java.io.NotSerializableException*

Что если мы наследовали Serizlizable класс, но хотим сделать его не-Serializable?

Нужно создать в классе собственные методы сериализации: writeObject() и readObject(). А в этих методах выкидывать исключение. Например: throw new NotSerializableException("Not serializable");

Мы записали в ObjectOutputStream out: out.writeObject(obj); out.writeInt(2); А затем в ObjectInputStream in вызываем: in.readInt(); in.readObject(); Что произойдет?

Поскольку записан объект, а мы пытаемся прочитать примитивный тип, то выпадет *java.io.OptionalDataException*. То же будет и если мы записали примитив, а считать хотим объект. А вот записать примитив и считать другой примитив можно.

Мы сериализовали объект класса Test и передали его на другую машину, где нет класса Test. Что будет, когда мы вызовем метод objectInputStream.readObject() ?

Поскольку класс не будет найден, будет выкинуто *java.lang.ClassNotFoundException*.


Ensembles d'études connexes

Essentials Exam 1: chapter 28 Practice Questions

View Set

ANTH 202: Study Guide Questions Exam 1

View Set

Chapter 4, Chapter 5, Chapter 7 Combined Quiz

View Set

geo final study guide (quiz questions and answers)

View Set

Chapter 15: Cardiovascular System

View Set

PEDS PrepU Chapter 21: Nursing Care of the Child with a Genitourinary Disorder

View Set

Med srug 13: Fluid and Electrolytes: Balance and Disturbance Prepu

View Set