Зачем Java нужен Serializable интерфейс?
Мы много работаем с сериализацией, и необходимость указывать тег Serializable для каждого используемого нами объекта является своего рода бременем. Особенно когда это сторонний класс, который мы не можем изменить.
Вопрос в том, что Serializable - пустой интерфейс, а Java обеспечивает надежную сериализацию после добавления. implements Serializable
- почему они не сделали все сериализуемым и все?
Что мне не хватает?
13 ответов
Сериализация таит в себе подводные камни. Автоматическая поддержка сериализации этой формы делает внутренние классы частью открытого API (именно поэтому javadoc предоставляет вам постоянные формы классов).
Для долговременного сохранения класс должен иметь возможность декодировать эту форму, что ограничивает изменения, которые вы можете внести в дизайн класса. Это нарушает инкапсуляцию.
Сериализация также может привести к проблемам с безопасностью. Будучи способным сериализовать любой объект, на который он ссылается, класс может получить доступ к данным, на которые он обычно не способен (путем анализа результирующих байтовых данных).
Есть и другие проблемы, такие как нечетко определенная сериализованная форма внутренних классов.
Создание всех сериализуемых классов усугубит эти проблемы. Ознакомьтесь с Effective Java Second Edition, в частности с пунктом 74: Осуществляйте сериализацию разумно.
Я думаю, что на этот раз и Java, и люди.Net ошиблись, было бы лучше сделать все сериализуемыми по умолчанию, и им нужно помечать только те классы, которые нельзя сериализовать безопасно.
Например, в Smalltalk (язык, созданный в 70-х годах) каждый объект по умолчанию сериализуем. Я понятия не имею, почему это не так в Java, учитывая тот факт, что подавляющее большинство объектов безопасны для сериализации, а некоторые из них - нет.
Маркировка объекта как сериализуемого (с интерфейсом) волшебным образом не делает этот объект сериализуемым, он был сериализуемым все время, просто теперь вы выразили нечто, что система могла бы найти самостоятельно, поэтому я не вижу реальной веской причины для сериализация такая, какая она есть сейчас.
Я думаю, что это было или плохое решение, принятое дизайнерами, или сериализация была запоздалой мыслью, или платформа никогда не была готова делать сериализацию по умолчанию для всех объектов безопасно и последовательно.
Не все действительно сериализуемы. Возьмите, например, соединение с сетевым сокетом. Вы можете сериализовать данные / состояние вашего объекта сокета, но сущность активного соединения будет потеряна.
Основная роль Serializable в Java состоит в том, чтобы фактически сделать по умолчанию все остальные объекты несериализуемыми. Сериализация - очень опасный механизм, особенно в его реализации по умолчанию. Следовательно, как и дружба в C++, она отключена по умолчанию, даже если сделать сериализуемыми все стоит немного.
Сериализация добавляет ограничения и потенциальные проблемы, поскольку совместимость структуры не застрахована. Хорошо, что по умолчанию он выключен.
Я должен признать, что я видел очень мало нетривиальных классов, где стандартная сериализация делает то, что я хочу. Особенно в случае сложных структур данных. Таким образом, усилия, которые вы потратите на правильную сериализацию класса, уменьшат затраты на добавление интерфейса.
Для некоторых классов, особенно тех, которые представляют нечто более физическое, такое как соединение File, Socket, Thread или DB, абсолютно бессмысленно сериализовать экземпляры. Для многих других, сериализация может быть проблематичной, потому что она разрушает ограничения уникальности или просто вынуждает вас иметь дело с экземплярами различных версий класса, чего вы, возможно, не хотите.
Возможно, было бы лучше сделать все по умолчанию сериализуемым и сделать классы не сериализуемыми через интерфейс ключевых слов или маркеров - но тогда те, кто должен использовать эту опцию, вероятно, не подумают об этом. Таким образом, если вам нужно реализовать Serializable, вы получите исключение.
Я думаю, что хотя бы для того, чтобы вы, как программист, знали, что ваш объект может быть сериализован.
Очевидно, что в некоторых предварительных проектах все было сериализуемо, но из-за соображений безопасности и корректности окончательный проект закончился, как мы все знаем.
Источник: Почему классы должны реализовывать Serializable для записи в ObjectOutputStream?,
Прочтите это, чтобы понять Serializable Interface и почему мы должны сделать только несколько классов Serializable, а также мы позаботимся о том, где использовать временное ключевое слово в случае, если мы хотим удалить несколько полей из процедуры хранения.
Необходимость четко заявить, что экземпляры определенного класса являются сериализуемыми, язык заставляет вас задуматься, следует ли вам это разрешить. Для простых объектов-значений сериализация тривиальна, но в более сложных случаях вам нужно действительно продумать вещи.
Просто полагаясь на стандартную поддержку сериализации JVM, вы подвергаете себя всевозможным неприятным проблемам с версиями.
Уникальность, ссылки на "реальные" ресурсы, таймеры и множество других типов артефактов НЕ являются кандидатами на сериализацию.
Хотя я согласен с замечаниями, высказанными в других ответах, реальная проблема связана с десериализацией: если определение класса изменится, существует реальный риск, что десериализация не сработает. Никогда не вносить изменения в существующие поля - это довольно серьезное обязательство для автора библиотеки! Поддержание совместимости API достаточно рутинно.
Что ж, мой ответ таков: это ни по какой веской причине. И из ваших комментариев я вижу, что вы уже узнали это. Другие языки с радостью пытаются сериализовать все, что не попадает на дерево после того, как вы сосчитали до 10. Объект должен по умолчанию быть сериализуемым.
Итак, что вам в основном нужно сделать, так это прочитать все свойства вашего стороннего класса самостоятельно. Или, если это вариант для вас: декомпилируйте, поместите туда ключевое слово damn и перекомпилируйте.
В Java есть некоторые вещи, которые просто не могут быть сериализованы, потому что они зависят от времени выполнения. Такие вещи, как потоки, потоки, среда выполнения и т. Д. И даже некоторые классы GUI (которые подключены к базовой ОС) не могут быть сериализованы.
Класс, который необходимо сохранить в файле или другом носителе, должен реализовывать интерфейс Serializable, чтобы JVM могла позволить сериализовать объект класса. Почему класс Object не сериализован, тогда ни один из классов не должен реализовывать интерфейс, ведь JVM сериализует класс только тогда, когда я использую ObjectOutputStream, что означает, что элемент управления все еще в моих руках, чтобы позволить JVM сериализоваться.
Причина, по которой класс Object по умолчанию не сериализуем, заключается в том, что основной проблемой является версия класса. Поэтому каждый класс, который заинтересован в сериализации, должен быть явно помечен как Serializable и предоставить номер версии serialVersionUID.
Если serialVersionUID не предоставлен, то при десериализации объекта мы получим неожиданные результаты, поэтому JVM генерирует InvalidClassException, если serialVersionUID не совпадает. Поэтому каждый класс должен реализовывать интерфейс Serializable и предоставлять serialVersionUID, чтобы убедиться, что класс, представленный на обоих концах, идентичен.