Подтвердить что ты не робот

Почему функция defaultWriteObject должна быть вызвана первым при записи в ObjectOutputStream?

Когда я прочитал о интерфейсе Serializable в Thinking in java, есть предложение, в котором говорится:

Если вы используете механизм по умолчанию для записи непереходных частей вашего объекта, вы должны вызвать функцию defaultWriteObject() в качестве первой операции в writeObject() и defaultReadObject() как первую операцию в readObject().

И в docs.oracle.com 5.6.2:

Добавление методов writeObject/readObject. Если версия, читающая поток, имеет эти методы, то, как обычно, readObject, как обычно, считывает требуемые данные, записанные в поток по сериализации по умолчанию. Он должен сначала вызвать defaultReadObject перед чтением любых дополнительных данных. Метод writeObject, как обычно, обычно вызывает вызов функции defaultWriteObject для записи необходимых данных, а затем может записывать дополнительные данные.

Итак, если я сначала не вызываю defaultWriteObject, и если я напишу что-то еще до этого вызова, будет ли какая-нибудь проблема? Я пробовал это, но кажется, что он по-прежнему хорошо работает в моем примере. Итак, если есть какие-то проблемы, при каких условиях это может произойти?

4b9b3361

Ответ 1

Спецификация сериализации объектов Java неопределенна по этому вопросу:

Любой метод ObjectOutputStream defaultWriteObject или writeFields должен вызываться один раз (и только один раз) перед записью любых необязательных данных, которые будут необходимы соответствующим методом readObject для восстановления состояния объекта; даже если никакие дополнительные данные не записываются, defaultWriteObject или writeFields все равно нужно вызывать один раз. Если defaultWriteObject или writeFields не вызывается один раз перед записью дополнительных данных (если они есть), то поведение десериализации семпла undefined в случаях, когда ObjectInputStream не может разрешить класс, который определил рассматриваемый метод writeObject.

Здесь старый поток, который дает пример, когда могут возникнуть проблемы.

И вот JBoss AS Jira ticket с другим примером.

Ответ 2

Я думаю, что ключевое слово в документации - "должно" , а это значит, что вам это не нужно.

Я думаю, что это более эффективная практика, чем что-либо еще. Если я прочитаю ваш код в первый раз и увижу, что вы по умолчанию прочитали чтение/запись в первой строке, я могу просто сказать себе "хорошо, сделано с 90% класса" и сосредоточиться на своем пользовательском коде, который позаботится о все непереходные, нестатические переменные экземпляра..

Самое главное - читать/писать в том же порядке. Кроме того, вы можете делать все, что захотите.

Ответ 3

Я думаю, что потому, что вы знаете, что делаете с обеих сторон, и делаете "то же" или лучше противоположное...

НО: Если какой-либо другой программист напишет десериализацию против вашей сериализации, не зная, что вы не используете значение по умолчанию, он, вероятно, будет использовать рекомендуемый файл defaultReadObject, а затем запустить в странные исключения.

Ответ 4

Это описано в "Эффективной Java":

Если все поля экземпляра являются временными, технически допустимо отказаться от вызова defaultWriteObject и defaultReadObject, но это не рекомендуется. Даже если все поля экземпляров являются временными, вызов defaultWriteObject влияет на сериализованную форму, что приводит к значительному повышению гибкости. Полученная сериализованная форма позволяет добавлять непереходные поля экземпляра в более позднем выпуске, сохраняя при этом совместимость назад и вперед. Если экземпляр сериализуется в более поздней версии и десериализован в более ранней версии, добавленные поля будут проигнорированы. Если в более ранних версиях метод readObject не смог вызвать defaultReadObject, десериализация завершилась неудачей с использованием исключения StreamCorruptedException.