различия и сходства между defaultWriteObject и writeObject методов java ObjectOutputStream

Я пытаюсь понять механизм сериализации Java, и у меня мало сомнений

Пожалуйста, ответьте на следующие вопросы, касающиеся сериализации Java:

  • Почему мы используем oos.defaultWriteObject(); ? Согласно этот пост есть для обратной совместимости. И я не совсем понимаю, как это достигается. Одним из несовместимых изменений для сериализации является удаление поля в более новой версии. Это означает, что более старые версии должны будут устанавливать значения по умолчанию, которые иногда недействительны для пользователя. Чем это отличается от более новых версий, добавляющих новое поле и позволяющих устанавливать значения по умолчанию?
  • во время пользовательской сериализации имеет ли значение использование как oos.defaultWriteObject();, так и oos.writeObject(address);, разве оба они не делают одно и то же? Я имею в виду, что оба записывают непереходные нестатические поля всех суперклассов и текущего класса в OOS.

здесь

private void writeObject(java.io.ObjectOutputStream stream)
        throws IOException {
    stream.writeObject(name);
    stream.writeInt(id);
    stream.writeObject(DOB);
}

private void readObject(java.io.ObjectInputStream stream)
        throws IOException, ClassNotFoundException {
    name = (String) stream.readObject();
    id = stream.readInt();
    DOB = (String) stream.readObject();
}

приведенный выше код дает тот же результат, что и приведенный ниже код

private void writeObject(java.io.ObjectOutputStream stream)
            throws IOException {
        stream.defaultWriteObject();
    }

    private void readObject(java.io.ObjectInputStream stream)
            throws IOException, ClassNotFoundException {
         stream.defaultReadObject();
    }

когда использовать эти 2 метода, когда использовать только writeObject(employee);//employee — это весь мой объект//

  1. вот список возможных повторяющихся вопросов, которые не отвечают на мой вопрос.
  2. вопрос 1 он говорит * Если defaultWriteObject или writeFields не вызываются один раз перед записью необязательных данных (если они есть), то поведение десериализации экземпляра не определено в случаях, когда ObjectInputStream * но я все еще могу вызвать writeObject без использования deafultwriteobject.right ?
  3. вопрос 2 эти ответы говорят, что метод defaultwriteobject записывает некоторые дополнительные данные в поток, и это рефлективно проверяет, что писать. разве oos.writeobject(object obj) также не выполняет рефлексивную проверку?
  4. Наконец-то я могу получить контроль над своей сериализацией, переопределив методы writeObject и ReadObject, тогда в чем смысл Externalizable?
  5. Если предоставление серийного номера versionUID не вызывает исключение, что произойдет, если я десериализую объект с отсутствующим полем из более старого класса, в котором есть это поле, в основном, что произойдет со всеми несовместимыми изменениями, если я предоставлю свой собственный SerialverUID? есть ли у него собственный UID серийной версии, который не будет вызывать исключение streamcorrupted для всех совместимых изменений?

person amarnath harish    schedule 22.08.2018    source источник
comment
@eugene вы не могли бы мне помочь?   -  person amarnath harish    schedule 19.12.2019
comment
Упомянутая обратная совместимость относится к совместимости с предыдущими версиями класса, в которых не было специального метода writeObject(), но это еще не все. Он вызывается внутри пользовательского метода writeObject(), когда вам нужны действия сериализации по умолчанию плюс некоторые ваши собственные. Все это задокументировано. Когда вы вызываете его вне этого контекста, как у вас, вы получаете это исключение. Это также задокументировано. Как и все остальное, о чем вы спрашивали. См. Спецификацию сериализации объектов.   -  person user207421    schedule 20.12.2019
comment
@user207421 user207421 я просмотрел документацию, и я здесь для уточнения. если defaultwriteobject предназначен для пользовательской сериализации, то почему у нас есть внешний интерфейс? мы могли бы просто переопределить метод writeobject правильно   -  person amarnath harish    schedule 20.12.2019
comment
Я не собираюсь излишне объяснять вам то, что уже полностью раскрыто в документе, на который я вас сослал.   -  person user207421    schedule 20.12.2019


Ответы (1)


На ваш вопрос

  1. writeObject не для обратной совместимости. readObject есть.
  2. Они такие же. defaultWriteObject поможет вам быстро записать "сериализуемые" значения.

Обратная совместимость

Предположим, ваш компонент добавил новое поле.

class Bean implements Serializable {
  int id;
  String name;
  String newValue = "123";
}

Хотя вы указали значение по умолчанию newValue, сериализация Java проигнорирует его. (Потому что он выделяет экземпляр вместо new его)

Теперь, если вы не используете readObject, вы получите newValue=null. Поэтому вам также нужно выполнить инициализацию в readObject.

  private void readObject(ObjectInputStream stream) throws Exception {
    stream.defaultReadObject();
    this.newValue = "123";
  }

Как defaultWriteObject поможет вам

Учтите, что ваш bean-компонент почти "сериализуем", за исключением некоторого поля.

См. следующий код. BadThing не является Serializable или содержит некоторые конфиденциальные данные, которые вы не хотите сериализовать.

class Bean implements Serializable {
  int id;
  String string;
  BadThing badThing;
}

Чтобы быстро сериализовать его, вы можете оставить поле transient и написать свой метод writeObject для его обработки.

  private void writeObject(ObjectOutputStream stream) throws Exception {
    stream.defaultWriteObject();
    stream.writeInt(badThing.id);
  }

  // Corresponding `readObject`

Конечно, вы можете заменить defaultWriteObject на несколько writeXXX. Но если у вас много много полей, писать код уже утомительно и скучно, правда?

Так что defaultWriteObject просто спасает вас от написания скучного кода.

person Dean Xu    schedule 25.12.2019