СЕРИАЛИЗАЦИЯ
|
ВОПРОС
| ОТВЕТ
|
Что такое сериализация и десериализация?
| Сериализация - это процесс сохранения состояния объекта в последовательность байт. Десериализация - это процесс восстановления объекта из этих байт.
|
Зачем вообще нужна сериализация?
| 1) Данные в памяти "живут", до момента завершения приложения. Сериализация позволяет записать объекты в файлы и, таким образом, восстановить их затем. 2) Сериализация предоставляет универсальный механизм обмена данными между компонентами приложения или узлами в интернете.
|
Что за интерфейс Serializable?
| 1) Интерфейс java.io.Serializable - это интерфейс-маркер, в нем нет методов. 2) Если класс реализует интерфейс, это говорит сериализующему механизму, что этот класс можно сериализовать.
|
Что нужно сделать, чтобы сериализовать объект?
| 1) Класс объекта должен реализовывать интерфейс Serializable 2) Создать поток ObjectOutputStream (oos), который записывает объект в переданный OutputStream. 3) Записать в поток: oos.writeObject(Object); 4) Сделать oos.flush() и oos.close()
|
Что нужно сделать, чтобы ДЕсериализовать объект?
| 1) Класс объекта должен реализовывать интерфейс Serializable 2) Создать поток ObjectInputStream (ois), в который передать InputStream (instream) (из файла, из памяти...) 3) Получить объект и привести к нужному типу: MyObject my = (MyObject) ois.readObject(instream)
|
Перечислит шаги, которые выполняет механизм сериализации при сериализации объекта (что за чем записывается в поток)
| 1) Запись метаданных: указание, что это сериализация, версия сериализации, указание "сейчас начнется объект". 2.1) Запись рекурсивно данных о классе объекта "снизу вверх": класс -> super -> supersuper и т.д пока не будет достигнут java.lang.Object. Сам класс Object не пишется. 2.2) При описании пишется имя класса, имена и тип его полей, примитивных и ссылок. Для ссылок просто указывается, что "там объект", без описания класса. 3.1) Запись значений данных в экземпляре, "сверху вниз": parent -> sub -> subsub... 3.2) Если поле - ссылка на объект, то рекурсивно идет запись объекта: описания полей "снизу вверх", затем написание значений "сверху вниз".
|
(Сериализация) Если у нас несколько объектов и мы хотим их сохранить в один файл - что мы делаем?
| 1) Делаем один FileOutputStream == fos 2) Оборачиваем его в ObjectOutputStream(fos) == oos 3) Пишем: oos.writeObject(object1); oos.writeObject(object2); ... oos.flush(); oos.close(); 4) Когда читаем объекты методом ObjectInputStream.readObject(), то получаем их в том же порядке, как они записаны.
|
Где ставится ключевое слово transient? Что оно означает?
| 1) Слово transient ("временный, переходный") - это модификатор для поля класса. 2) Если поле объявлено transient, это значит, что значение этого поля не нужно записывать при сериализации. 3) При восстановлении объекта у него будет это поле, но со значением null (0, false).
|
Чем отличаются методы восстановления объекта в интерфейсах Serializable и Externalizable?
| 1) Serializible не использует конструктор объекта - он просто восстанавливает его полностью из последовательности байтов. 2.1) Externalizible вначале вызывает public конструктор объекта без параметров, а затем наполняет поля объекта значениями. 2.2) Если у класса не будет public конструктора без параметров, при попытке десериализовать объект выпадет java.io.InvalidClassException.
|
Чем отличаются интерфейсы 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.
|
Мы хотим, чтобы при сериализации значения некоторых полей не сохранялись. Как этого достичь?
| 1) Добавить к полю модификатор transient. В таком случае после восстановления его значение будет null. 2) Сделать поле static. Значения статических полей автоматически не сохраняются. Впрочем, это можно сделать вручную: ObjectOutputStream oos = new ...; oos.writeInt(obj.staticField1); oos.writeObject(a); 3) Также можно написать свои методы read/writeObject или read/writeExternal и записать в них только те поля, которые нам нужны.
|
А что если у нас Serializable класс содержит поля, в которых объекты не Serializable?
| 1) В таком случае код скомпилируется. 2) Но в рантайме при попытке сериализации , когда мы дойдем до этого поля и объекта, мы получим NotSerializableException.
|
Что будет, если у нас класс Serializable, а его класс-родитель - нет?
| 1) В случае, если в цепочке классов (child -> parent -> grandparent) какой-то из них не Serializable, то он инициализируется public конструктором без параметров. 2) Даже если выше не-Serializable класса другие классы Serializable, это уже не важно - дальше создание идет просто по цепочке конструкторов. 3) Если в цепочке у какого-то класса не окажется конструктора без параметров - вылезет java.io.InvalidClassException с сообщением "no valid constructor".
|
Можно ли как-то вручную управлять процессом сериализации в 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();
|
Что если мы наследовали Serizlizable класс, но хотим сделать его не-Serializable?
| Нужно создать в классе собственные методы сериализации: writeObject() и readObject(). А в этих методах выкидывать исключение. Например: throw new NotSerializableException("Not serializable");
|
Какие объекты и методы используются при сериализации и де-сериализации в 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)
|
Как легко сгенерировать serialVersionUID для класса?
| Для этого есть утилита serialver, имеющаяся в JDK: $ serialver -classpath . Hello Hello: static final long SerialVersionUID = -4862926644813433707L;
|
Зачем может понадобиться вручную определять методы сериализации (read/writeObject, read/writeExternal)?
| 1) Чтобы сериализовать не все поля. 2) Чтобы повысить производительность. 3) Чтобы зашифровать данные в полях.
|
Что будет с работой интерфейсов Serizalizable и Externalizable в случае, если переменная - final?
| 1) Интерфейс Serializable отработает без проблем - он использует рефлексию для создания объекта. При этом используются методы ObjectInputStream.defaultReadObject() и ObjectOutputStream.defaultWriteObject(). 2) Однако, если мы создадим свои методы readObject() и writeObject(), то Serizalizable не сможет присвоить значение переменной: будет жаловаться, что она final. 3) У интерфейса Externalizable будет проблема в методе readExternal(). Он не сможет сделать this.field = in.readValue(). Потому что создает объект конструктором, а затем меняет значение.
|
Вы взяли класс и сериализовали его объект. Затем вы добавили новое поле в классе. После чего - пытаетесь десериализовать объект. Что произойдет?
| 1) Если в классе не был указан serialVersionUID, то выпадет InvalidClassException, поскольку у класса он поменяется. 2) Если же был объявлен - объект восстановится. При этом восстановит значения в поля, что были до сериализации восстановятся, а новые инициализируются как 0, null и т.д.
|
Вы сериализовали объект, а затем переименовали поле. Что будет при восстановлении?
| Если в объекте указан serialVersionUID, то объект восстановится, но значение в поле - нет. Оно будет инициализировано null, 0 и т.д.
|
Что такое совместимые и несовместимые изменения в механизме серилизации Java? Какие это изменения?
| Compatible и incompatible changes - изменения в классе, после которых ранее сериализованные объекты еще можно как-то восстановить или нельзя. 1) Совместимые добавление, изменение, удаление поля или метода. 2) Несовместимые: изменение места класса в иерархии классов (например, extends другого родителя), удаление надписи implements Serializable.
|
Можно ли передавать сериализованный объект по сети интернет?
| 1) Да, сериализованный объект - это просто набор байтов. 2) Его спокойно можно передать по сети и в другом месте восстановить объект. 3) Также объект можно хранить в таком виде в базе данных или в файле.
|
Какие поля в классе Java не сериализуются?
| 1) static поля - они часть класса, а не объекта. Следовательно, они не указывают на состояние объекта. 2) transient поля - модификатор как раз и говорит о том, что "это поле не отмечает состояние объекта". Следовательно, его не нужно сериализовать.
|
Что будет, если мы попробуем сериализовать класс, в котором не написано implements Serializable?
| Код скомпилируется, но во время выполнения выкинет java.io.NotSerializableException
|
Мы сериализовали объект класса Test и передали его на другую машину, где нет класса Test. Что будет, когда мы вызовем метод objectInputStream.readObject() ?
| Поскольку класс не будет найден, будет выкинуто java.lang.ClassNotFoundException.
|
Мы записали в ObjectOutputStream out: out.writeObject(obj); out.writeInt(2); А затем в ObjectInputStream in вызываем: in.readInt(); in.readObject(); Что произойдет?
| Поскольку записан объект, а мы пытаемся прочитать примитивный тип, то выпадет java.io.OptionalDataException. То же будет и если мы записали примитив, а считать хотим объект. А вот записать примитив и считать другой примитив можно.
|