Чому Java потрібен інтерфейс, що підтримується?


114

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

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

Що я пропускаю?


Що робити, якщо ви хочете зробити власний об’єкт серіалізаційним? Або я щось неправильно зрозумів?
Джо Філіпс

Я все одно отримаю NotSerializableException, оскільки всі поля моїх об'єктів мають бути серіалізаційними
Yoni Roit

Цілком погоджуєтесь з поп-каталіном та димітрієм "Цей серіалізаційний трюк - це лише одне ще одне неправильне рішення, яке було прийняте десять-два тому". Не має значення, наскільки небезпечною може бути серіалізація. І це неправда, оскільки, оскільки декларація явна, то "ви знаєте, що вам потрібно приділити особливу увагу": кожен, кому це потрібно, спочатку кладе "речі", а потім замислюється про те, якщо щось пішло не так. Це могло б бути зрозумілішим, якби вони дали нам інтерфейс "Неможливість", який можна застосувати в особливих випадках.
Джек

Відповіді:


120

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

Для тривалої наполегливості клас повинен бути в змозі розшифрувати цю форму, що обмежує зміни, які ви можете внести до дизайну класу. Це порушує інкапсуляцію.

Серіалізація також може призвести до проблем із безпекою. Завдяки можливості серіалізувати будь-який об'єкт, на який він має посилання, клас може отримати доступ до даних, до яких зазвичай не зможе (розбираючи отримані дані байтів).

Є й інші питання, такі як серіалізована форма внутрішніх класів недостатньо чітко визначена.

Зростання серіалізму всіх класів посилить ці проблеми. Ознайомтеся з Ефективною версією Java другого видання , зокрема Пункт 74: Розумно реалізуйте Serializable .


2
Це, очевидно, краща відповідь, я розчарований, що обрана відповідь - це не це, здається, розміщений вибір вибраний з назвою "Я роздратований, тому що я мушу оголосити речі серіалізаційними" на увазі. Це приклад того, що хтось хоче звільнитись, а не прислухатися до уроків безпеки та дизайну, які вже були вивчені в минулому.
gbtimmon

@McDowell, що ви розумієте під стійкою формою занять? Я перейшов за цим посиланням, але не можу зрозуміти, що ти маєш на увазі? ви можете пояснити це будь ласка?
Geek

@Geek - серіалізована форма типу URL (наприклад) визначає, які приватні поля повинен мати тип і в якому порядку вони повинні бути оголошені.
McDowell,

@McDowell Чому порядок має значення?
Geek

12
@McDowell Привіт. Я оригінальний плакат цього питання від 4 років тому, і я щойно обрав вашу відповідь як прийняту, якщо це щось означає. Я думаю, що ваша відповідь справді краща, і я, мабуть, був занадто незрілим, щоб бачити це саме тоді. Виправлення зараз :)
Yoni Roit

32

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

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

Позначення об'єкта як серіалізабельний (з інтерфейсом) не робить магічний серіалізабельний об'єкт, він був серіалізаційним протягом усього часу , це просто те, що ви зараз висловили щось, що система могла б знайти самостійно, тому я не бачу справжньої вагомої причини для серіалізація - така, яка є зараз.

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


26
Вам потрібно бути особливо обережними при розробці та впровадженні класу, щоб переконатися, що екземпляри будуть серіалізовані розумним чином. Інтерфейс серіалізації насправді означає: "Я, як програміст, зрозумів наслідки серіалізації і дозволяю JVM це серіалізувати"
Рольф Рендер

@ Рольф Рендер: більшу частину часу вам взагалі не потрібно піклуватися, просто позначте клас серіалізаційним. Якби серіалізація була ВКЛ за замовчуванням на всіх об'єктах, мислення кожного розробника було б і іншим, це було б щось природне, щоб зробити клас серіалізаційним ...
Поп Каталін

це додало б ще одного занепокоєння до списку гарного дизайну класу, як, наприклад, переконання, що у вас немає витоків пам’яті. Тим не менш, гарний дизайн класів все більше і більше вимагає, щоб ваші заняття були серійними, коли вони можуть бути.
Поп Каталін

3
@StaxMan, оскільки зрозуміти пізніше, що вам потрібно серіалізувати клас, а ви не можете, це може бути дуже дорого. Це один із тих випадків, коли платять додаткові зусилля. Це особливо актуально, якщо ви пишете бібліотеку, і хтось інший буде споживати її без вихідного коду
Pop Catalin,

2
Я повністю згоден з цією відповіддю. У багатьох мовах за замовчуванням все серіалізується. І насправді те саме з JVM, тому що Reflection легко використовувати для доступу до будь-якого члена класу, незалежно від того, приватний він чи ні. Цей Serializableтрюк - це ще одне неправильне рішення, яке було прийнято десять-два тому тому, і ще одне доповнення до роздратування при роботі з чистою формою Java, як деякі недоліки в колекції та обробці рядків у стандартній бібліотеці. На щастя, Крио є, але це залежність, і його потрібно знайти в першу чергу. Ось як має бути зроблена вбудована серіалізація.
dmitry

20

Не все справді серіалізується. Наприклад, візьміть підключення до мережевої розетки. Ви можете серіалізувати дані / стан об’єкта сокета, але суть активного з'єднання буде втрачена.


Це буде моєю проблемою, і якби я не був достатньо розумним, щоб спробувати серіалізувати сокет, я виявив би свою помилку під час налагодження. Однак зараз я переживаю ситуацію, коли я не можу використовувати серіалізацію Java взагалі через третій клас, який не реалізує Serializable без поважних причин.
Yoni Roit

4
Існує кілька пристойних способів вирішити цей випадок, наприклад, написання класу "обгортка", що вміє читати та записувати ключові дані третього класу; зробити загорнутий екземпляр тимчасовим і переосмислити writeObject і readObject.
Грег Кейс

Чи можете ви успадкувати від потрібних об'єктів у вашому api та серіалізувати ці класи?
Joel Coehoorn,

@Joel: Це гарна ідея, але все-таки хак. Я здогадуюсь, що вся ця річ - це лише черговий компроміс. Дякуємо за ваші коментарі.
Yoni Roit

1
Це один з тих рідкісних прикладів, який ілюструє, що все, що нам дійсно потрібно, - implements NotSerializable:)
Роб Грант

13

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

Серіалізація додає обмежень та потенційних проблем, оскільки сумісність структури не застрахована. Добре, що воно вимкнено за замовчуванням.

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


9

Для деяких класів, особливо тих, які представляють щось більш фізичне, наприклад з'єднання Файл, Сокет, Нитка або БД, серіалізувати екземпляри абсолютно не має сенсу. Для багатьох інших серіалізація може бути проблематичною, оскільки вона руйнує унікальні обмеження або просто змушує вас мати справу з екземплярами різних версій класу, чого ви, можливо, не хочете.

Можливо, було б краще зробити все Serializable за замовчуванням і зробити класи не серіалізаційними через ключове слово або інтерфейс маркера, але тоді, ті, хто повинен використовувати цю опцію, напевно, не думали б про це. Таким чином, якщо вам потрібно реалізувати Serializable, вам це скажуть винятком.


4

Я думаю, що все-таки потрібно було переконатись, що ти, як програміст, знаєш, що твій об’єкт мій буде серіалізований.



1

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

Просто покладаючись на стандартну підтримку серіалізації JVM, ви піддаєте себе всіляким неприємним проблемам версій.

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


1

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

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


0

Ну, моя відповідь - це недарма причини. І з ваших коментарів я бачу, що ви вже це дізналися. Інші мови із задоволенням намагаються серіалізувати все, що не перескакує на дереві після того, як ви порахували до 10. Об'єкт повинен за замовчуванням бути серіалізаційним.

Отже, що вам в основному потрібно зробити, це прочитати всі властивості вашого стороннього класу самостійно. Або, якщо для вас це варіант: декомпілюйте, поставте туди прокляте ключове слово та перекомпілюйте.


2
Серіалізація додає обмежень та потенційних проблем, оскільки сумісність структури не застрахована. ІМХО, добре, що він вимкнено за замовчуванням.
Урі

Я не впевнений, що ви маєте на увазі під "сумісністю структури".
nes1983

0

У Java є деякі речі, які просто неможливо серіалізувати, оскільки вони є специфічними для виконання. Такі речі, як потоки, потоки, час виконання тощо, і навіть деякі класи GUI (які підключені до базової ОС) не можуть бути серіалізовані.


0

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


Це неправильно. Вам потрібно прочитати Версія версій серіалізаційних об’єктів у специфікації специфікації об'єкта, який би не існував, якби те, що ви тут заявляли, було правдою. Визначення класу може змінюватися в досить широких межах, перш ніж воно стане несумісним з попередніми серіалізаціями. І це, звичайно, не є відповіддю на питання. Справжня причина пов'язана з питаннями безпеки.
Маркіз Лорнський

@EJP, в інтересах правдивості я відредагував свою відповідь, щоб відобразити ваші моменти. Сентиляція стоїть, однак, це велике зобов’язання, яке, безумовно, повинно бути відмова, а не відмова
CurtainDog

0

Клас, який потрібно зберігати до файлу чи іншого носія, повинен реалізувати інтерфейс Serializable, щоб JVM дозволяв серіалізувати об'єкт класу. Чому клас Object не серіалізується, тоді жодному з класів не потрібно реалізовувати інтерфейс, адже JVM серіалізує клас лише тоді, коли я використовую ObjectOutputStream, а це означає, що управління все ще в моїх руках, щоб дозволити JVM серіалізувати.

Причина, по якій клас Object не є серіалізаційним за замовчуванням у тому, що версія класу є основною проблемою. Тому кожен клас, який зацікавлений у серіалізації, повинен бути позначений як Serializable явно та надати номер версії serialVersionUID.

Якщо serialVersionUID не надається, ми отримуємо несподівані результати під час десеріалізації об'єкта, тому JVM викидає InvalidClassException, якщо serialVersionUID не відповідає. Тому кожен клас повинен реалізувати інтерфейс Serializable і надати serialVersionUID, щоб переконатися, що клас, представлений на обох кінцях, однаковий.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.