Зачем Java нужен сериализуемый интерфейс?

114

Мы много работаем с сериализацией, и необходимость указывать тег Serializable для каждого используемого объекта является своего рода бременем. Особенно, когда это сторонний класс, который мы не можем изменить.

Возникает вопрос: поскольку Serializable - это пустой интерфейс, а Java обеспечивает надежную сериализацию после добавления, implements Serializableпочему они не сделали все сериализуемым и все?

Что мне не хватает?

Йони Ройт
источник
Что, если вы хотите сделать свой собственный объект сериализуемым? Или я что-то неправильно понял?
Джо Филлипс,
Я все равно получу NotSerializableException, потому что все поля моих объектов должны быть сериализуемыми
Йони Ройт,
Полностью согласен с Попом Каталином и Дмитрием: «Этот трюк с сериализацией - еще одно неправильное решение, которое было принято десять или два года назад». Неважно, насколько опасной может быть сериализация. И это неправда, что, поскольку декларация является явной, то «вы знаете, что вам нужно уделять особое внимание»: каждый, кому это нужно, сначала помещает материал «реализует», а затем думает о последствиях, если что-то пойдет не так. Все могло бы быть более ясным, если бы они предоставили нам «несериализуемый» интерфейс, который можно было бы применять в особых случаях.
Джек

Ответы:

120

Сериализация чревата подводными камнями. Поддержка автоматической сериализации этой формы делает внутренние компоненты класса частью общедоступного API (поэтому javadoc предоставляет вам постоянные формы классов ).

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

Сериализация также может привести к проблемам с безопасностью. Имея возможность сериализовать любой объект, на который он ссылается, класс может получить доступ к данным, которые он обычно не мог бы получить (путем анализа полученных байтовых данных).

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

Создание сериализуемых классов усугубит эти проблемы. Ознакомьтесь с « Эффективным вторым изданием Java» , в частности с правилом 74: разумно реализуйте Serializable .

Макдауэлл
источник
2
Это явно лучший ответ, я разочарован тем, что выбранный ответ не такой, кажется, что опубликованный вариант был выбран с повесткой дня «Я раздражен, потому что я должен объявить вещи сериализуемыми». Это пример того, как кто-то хочет освободиться и не прислушиваться к урокам безопасности и дизайна, которые уже были извлечены в прошлом.
gbtimmon 09
@McDowell, что вы подразумеваете под постоянной формой классов? Я перешел по этой ссылке, но не понимаю, о чем вы? не могли бы вы это объяснить?
Geek
@Geek - Сериализованная форма типа URL (например) определяет, какие частные поля должен иметь тип и в каком порядке они должны быть объявлены.
МакДауэлл,
@McDowell Почему порядок важен?
Geek
12
@McDowell Привет. Я автор этого вопроса 4 года назад и только что выбрал ваш ответ как принятый, если он хоть что-то значит. Я думаю, что ваш ответ действительно лучше, и я, вероятно, был слишком незрелым, чтобы так думать в то время. Исправляем сейчас :)
Йони Ройт
32

Я думаю, что на этот раз люди как Java, так и .Net ошиблись, было бы лучше сделать все сериализуемым по умолчанию и вместо этого нужно было бы отмечать только те классы, которые нельзя безопасно сериализовать.

Например, в Smalltalk (язык, созданный в 70-х годах) каждый объект по умолчанию сериализуем. Я понятия не имею, почему это не так в Java, учитывая тот факт, что подавляющее большинство объектов безопасно сериализовать, а лишь некоторые из них - нет.

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

Я думаю, что либо дизайнеры приняли плохое решение, либо сериализация была запоздалой мыслью, либо платформа никогда не была готова выполнять сериализацию по умолчанию для всех объектов безопасно и последовательно.

Поп-каталин
источник
26
При разработке и реализации класса необходимо проявлять особую осторожность, чтобы обеспечить разумную сериализацию экземпляров. Сериализуемый интерфейс на самом деле означает: «Я, как программист, понял последствия сериализации и разрешаю JVM сериализовать это»
Рольф Рандер,
@Rolf Rander: в большинстве случаев вам вообще не нужно беспокоиться, просто отметьте класс как сериализуемый. Если бы сериализация была включена по умолчанию для всех объектов, мышление каждого разработчика тоже было бы другим, было бы естественным сделать класс сериализуемым ...
Поп Каталин
это добавило бы еще одну проблему к списку хорошего дизайна классов, например, убедитесь, что у вас нет утечек памяти. Тем не менее, хороший дизайн классов все больше и больше требует, чтобы ваши классы были сериализуемыми, когда это возможно.
Pop Catalin
3
@StaxMan, потому что понимание того, что вам нужно сериализовать класс, а вы не можете, может оказаться очень дорогостоящим. Это один из тех случаев, когда окупаются небольшие дополнительные усилия. Это особенно верно, если вы пишете библиотеку, и кто-то другой будет использовать ее без исходного кода
Pop Catalin
2
Я полностью согласен с этим ответом. На многих языках по умолчанию все сериализуемо. И на самом деле то же самое и с JVM, потому что Reflection легко использовать для доступа к любому члену класса, независимо от того, является ли он частным или нет. Этот Serializableтрюк - еще одно неправильное решение, которое было принято десять или два года назад, и еще одно добавление к раздражению при работе с чистой java, например, некоторые недостатки в сборе и обработке строк в стандартной библиотеке. К счастью, есть Крио, но это зависимость, и ее нужно сначала найти. Вот как должна была выполняться встроенная сериализация.
дмитрий
20

Не все действительно сериализуемо. Возьмем, к примеру, подключение к сетевому сокету. Вы можете сериализовать данные / состояние вашего объекта сокета, но суть активного соединения будет потеряна.

Джоэл Кохорн
источник
Это было бы моей проблемой, и если бы я не был достаточно умен, чтобы попытаться сериализовать сокет, я бы нашел свою ошибку во время отладки. Однако теперь я нахожусь в ситуации, когда я вообще не могу использовать сериализацию Java из-за стороннего класса, который не реализует Serializable без уважительной причины.
Йони Ройт,
4
Есть несколько достойных способов справиться с этим случаем, например, написать класс-оболочку Serializable, который знает, как читать и записывать ключевые данные стороннего класса; сделать обернутый экземпляр временным и переопределить writeObject и readObject.
Грег Кейс,
Можете ли вы унаследовать от требуемых объектов в своем API и сериализовать эти классы?
Джоэл Кохорн
@ Джоэл: Это хорошая идея, но все же хакерство. Я предполагаю, что все это просто очередной раз ошибся. Спасибо за ваши комментарии.
Йони Ройт
1
Это один из тех редких примеров, который показывает, что все, что нам действительно нужно, это implements NotSerializable:)
Роб Грант,
13

Основная роль Serializable в Java - сделать по умолчанию все другие объекты несериализуемыми. Сериализация - очень опасный механизм, особенно в его реализации по умолчанию. Следовательно, как и дружба в C ++, он отключен по умолчанию, даже если сделать вещи сериализуемыми стоит немного.

Сериализация добавляет ограничения и потенциальные проблемы, поскольку совместимость структур не гарантируется. Хорошо, что по умолчанию он выключен.

Должен признать, что встречал очень мало нетривиальных классов, в которых стандартная сериализация делает то, что я хочу. Особенно в случае сложных структур данных. Таким образом, усилия, которые вы бы потратили на правильную сериализацию классов, значительно уменьшают затраты на добавление интерфейса.

Uri
источник
9

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

Возможно, было бы лучше сделать все сериализуемым по умолчанию и сделать классы несериализуемыми с помощью интерфейса ключевого слова или маркера, но тогда те, кто должен использовать эту опцию, вероятно, не подумают об этом. Таким образом, если вам нужно реализовать Serializable, вам об этом сообщит исключение.

Майкл Боргвардт
источник
4

Я думаю, это было сделано для того, чтобы вы, как программист, знали, что ваш объект может быть сериализован.

Милхаус
источник
3

По-видимому, в некоторых предварительных проектах все было сериализуемым, но из соображений безопасности и правильности окончательный дизайн закончился, как мы все знаем.

Источник: Почему классы должны реализовывать Serializable, чтобы их можно было записать в ObjectOutputStream? .

cic
источник
1

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

Просто полагаясь на стандартную поддержку сериализации JVM, вы подвергаете себя всевозможным неприятным проблемам с версией.

Уникальность, ссылки на «реальные» ресурсы, таймеры и множество других типов артефактов НЕ являются кандидатами на сериализацию.

Йерун ван Берген
источник
1

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

http://www.codingeek.com/java/io/object-streams-serialization-deserialization-java-example-serializable-interface/

Хитеш Гарг
источник
0

Что ж, я отвечаю, что это без уважительной причины. И из ваших комментариев я вижу, что вы это уже узнали. Другие языки с радостью пытаются сериализовать все, что не прыгает по дереву после того, как вы посчитали до 10. Объект по умолчанию должен быть сериализуемым.

Итак, что вам в основном нужно сделать, так это самому прочитать все свойства вашего стороннего класса. Или, если это для вас вариант: декомпилируйте, вставьте туда чертово ключевое слово и перекомпилируйте.

Nes1983
источник
2
Сериализация добавляет ограничения и потенциальные проблемы, поскольку совместимость структур не гарантируется. ИМХО, хорошо, что по умолчанию он выключен.
Uri
Я не уверен, что вы имеете в виду под «структурной совместимостью».
nes1983
0

В Java есть некоторые вещи, которые просто невозможно сериализовать, потому что они зависят от времени выполнения. Такие вещи, как потоки, потоки, среда выполнения и т. Д., И даже некоторые классы графического интерфейса (которые подключены к базовой ОС) не могут быть сериализованы.


источник
0

Хотя я согласен с пунктами, изложенными в других ответах здесь, настоящая проблема связана с десериализацией: если определение класса изменится, существует реальный риск, что десериализация не сработает. Никогда не изменять существующие поля - довольно серьезное обязательство для автора библиотеки! Поддержание совместимости API - это и так достаточно рутинная работа.

ЗанавесСобака
источник
Это не так. Вам необходимо прочитать главу «Управление версиями сериализуемых объектов» Спецификации сериализации объектов, которой бы не существовало, если бы то, что вы утверждаете здесь, было правдой. Определение класса может измениться в довольно широких пределах, прежде чем станет несовместимым с предыдущими сериализациями. И это, конечно, не ответ на вопрос. Настоящая причина связана с проблемами безопасности.
Marquis of Lorne
@EJP, ради правдивости я отредактировал свой ответ, чтобы отразить вашу точку зрения. Однако мнение остается неизменным, это большое обязательство, которое определенно должно быть
согласием,
0

Класс, который необходимо сохранить в файле или другом носителе, должен реализовывать интерфейс Serializable, чтобы JVM могла позволить сериализацию объекта класса. Почему класс Object не сериализуется, тогда ни один из классов не должен реализовывать интерфейс, ведь JVM сериализует класс только тогда, когда я использую ObjectOutputStream, что означает, что элемент управления все еще находится в моих руках, чтобы позволить JVM сериализоваться.

Причина, по которой класс Object не может быть сериализован по умолчанию, заключается в том, что версия класса является основной проблемой. Поэтому каждый класс, который заинтересован в сериализации, должен быть явно помечен как Serializable и предоставить номер версии serialVersionUID.

Если serialVersionUID не указан, мы получаем неожиданные результаты при десериализации объекта, поэтому JVM выдает исключение InvalidClassException, если serialVersionUID не совпадает. Поэтому каждый класс должен реализовать интерфейс Serializable и предоставить serialVersionUID, чтобы убедиться, что класс, представленный на обоих концах, идентичен.

Тринеш Андхурти
источник