Главная страница
Навигация по странице:

  • ObjectOutputStream

  • ObjectInputStream

  • "снизу вверх"

  • "сверху вниз"

  • private static final long serialVersionId = ...

  • public конструктором без параметров

  • java.io.InvalidClassException

  • private void writeObject(ObjectOutputStream out) throws IOException private void readObject(ObjectInputStream in)t hrows IOException, ClassNotFoundException

  • НЕ @Override!

  • writeObject

  • readExternal

  • Input_Output Ревью. Какие существуют виды потоков вводавывода Назовите основные предки потоков вводавывода


    Скачать 47.38 Kb.
    НазваниеКакие существуют виды потоков вводавывода Назовите основные предки потоков вводавывода
    АнкорInput_OutPut Review
    Дата05.10.2022
    Размер47.38 Kb.
    Формат файлаdocx
    Имя файлаInput_Output Ревью.docx
    ТипДокументы
    #715083
    страница3 из 3
    1   2   3



    СЕРИАЛИЗАЦИЯ

    ВОПРОС

    ОТВЕТ

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

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

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

    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. То же будет и если мы записали примитив, а считать хотим объект.
    А вот записать примитив и считать другой примитив можно.
    1   2   3


    написать администратору сайта