Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Java: Общие вопросы > Десериализация: зачем нужен пустой конструктор? |
Автор: Dims 2.3.2009, 12:09 |
При десериализации объекта, система ругается InvalidClassException, no valid constructor. В инструкции читаю, что в классе должен быть доступный конструктор без параметров. А зачем? Получается, я должен всем классам и классам членов добавить implements Serializable и пустые конструкторы. Как-то стрёмно. Что я при этом должен обеспечить логически? Может ли быть так, что я всё это сделаю, а сериализация будет работать неправильно? |
Автор: gambit 2.3.2009, 13:06 |
мне всегда казалось, что при вызове конструктора происходит выделение памяти необходимое объекту. Добавлено через 1 минуту и 15 секунд блин, я разделом ошибся. ![]() но может и для java это справедливо? |
Автор: Platon 2.3.2009, 13:26 | ||
http://ru.wikipedia.org/wiki/JavaBeans
|
Автор: dorogoyIV 2.3.2009, 14:30 |
по моему компилятор должен сам создавать конструктор дефолтный - по крайней мере так написано у меня в учебнике, т.е. конструктор у класса есть всегда, даже если сам его не писал |
Автор: powerOn 2.3.2009, 15:14 |
только если нет других конструкторов. Стоит написать какой-либо с параметрами, так дефолтный не будет создан. |
Автор: COVD 2.3.2009, 16:21 | ||
Наверное, это позволяет восстанавливать сериализованный обьект из потока, т.е. начать не дожидаясь получения всего обьекта. Сериализованный обьект начинается с описания класса. Читается описание и создается пустой обьект. Для этого класс и должен иметь пустой конструктор. Потом идут параметры, если есть. Они последовательно читаются и вставляются в созданный обьект (через сеттеры, ведь наверное речь идет о javabean). Вторая причина - при сериализации пустые параметры ( параметр = null ) просто не пишутся в поток, т.е. минимизируется размер сериализованного обьекта. |
Автор: lemonade 2.3.2009, 16:39 | ||
Dims еще жедательно добавить serialVersionUID поле
|
Автор: Dims 2.3.2009, 16:46 |
Нет, у меня класс не следует спецификациям бинов. Получается, его нельзя сериализовать? Мне кажется, что можно. И отсюда вопрос. Вот у меня класс с приватным параметром. Десериализатор ведь как-то умудряется его прочитать из файла и присвоить, хотя сеттера и геттера у меня к нему может и не быть. Так почему же ему нужен конструктор, чтобы создать объект? Вопрос можно сформулировать более общо: достаточно ли удовлетворить формальным требованиям компиллятора и джавамашины к сериализуемым объектам, чтобы всё работало правильно? Иными словами, вот у меня есть класс, который нормально, без ошибок, сериализуется и десериализуется. Могу ли я быть уверен, что всё работает правильно, или я должен ещё за чем-то проследить? Вот, например, при работе с многопоточными приложениями, я должен следить, чтобы не было каких-нибудь дедлоков. Я могу совершить логическую ошибку, которую не заметит ни компиллятор ни джавамашина при выполнении, но из-за которой программа будет виснуть. То есть, не совершать такую ошибку -- это моя ответственность. А в чём моя ответственность при сериализации? Какие тут могут быть логические ошибки? Добавлено через 5 минут и 8 секунд Допустим, у меня класс, который внутри содержит массив. Параметр конструктора --это число элементов в этом массиве. Есть дефолтный конструктор, который устанавливает число элементов в 100. Допустим, у меня был объект, в котором было 42 элемента. Я его сериализовал. Получается, при десериализации будет вызван дефолтный конструктор, то есть, создадутся 100 элементов. Затем из файла будет прочитан массив из 42 элементов. В лучшем случае 100 элементный массив просто пойдёт в мусорку, то есть, это лишняя работа. А в худшем - возникнет какая-то ошибка. |
Автор: COVD 2.3.2009, 16:54 | ||
если без ошибок, то да. Изначально то вопрос был отчего требование пустого конструктора. Как я уже добавил выше, наверное, основная причина в том, что неопределенные параметры обьекта не сериализуются в целях минимизации размера. |
Автор: COVD 2.3.2009, 17:10 | ||
Вы логику разработчиков десериализатора хотите понять? Мне кажется она проста и надежна - делай раз (создай пустой обьект), делай два (если есть параметр, прочитай и засунь в обьект). Пункт два выполняется в цикле. Сериализованный обьект - это последовательность байт, которые и обрабатываются последовательно. Очевидно, именно последовательно и будет "тупо", а не "прочитать ВСЕ" и "тупо присвоить". А требование наличия пустого конструктора не выглядит обременительным. |
Автор: LSD 2.3.2009, 17:26 | ||
Необходимость того чтобы объект был корректно создан. Когда ты объявляешь объект сериализуемым ты закладываешь (по крайней мере должен) возможность того что он будет создан без вызова конструктора (тогда логика инициализации закладывается в defaultReadObject()). А вот не сериализуемый суперкласс, такого метода не имеет и потому для него вызов конструктора - обязателен. |
Автор: Vitaly333 2.3.2009, 18:35 | ||||||
Да ,здесь всё дело именно в этом. Допустим у вас есть такой класс c несколькими конструкторами и он не реализует Serializable:
И есть класс его наследник:
Допустим вы породили некий объект, от класса Chield и хотите его сериализовать. Так как суперкласс не реализует Serializable, то поля a и b, унаследованные от него не будут сериализованы. Но при диссериализации их же нужно как - то инициализировать. Единственная возможность - вызвать конструктор суперкласса! Но у суперкласса определенно 2 конструктора. Возникает вопрос - а какой из них вызывать и какие значения ему передовать??? Поэтому и было принято решение , что при сериализации в суперклассе (который не реализует Serializable) обязательно должен быть определен конструктор по умолчанию(без параметров), который и осуществляет эту инициализацию. |
Автор: Dims 2.3.2009, 18:46 | ||||||||
Я нашёл ссылку. В ней написано, что это НЕ ТАК. Конструктор без параметров не нужен, что подтверждается тем, что ошибка сохранилась тогда, когда я такой конструктор создал.
Вообще-то, следования тут нет. Разработчики могли бы сделать так, чтобы это просто было запрещено. То есть, они могли потребовать, чтобы объекты Serializable обязательно имели в предках тоже Serializable, либо не имели предков вовсе (примерно так, как сделали с Cloneable). Но они поступили по-иному, они разрешили сериализовать объекты с несериализуемыми предками при условии, что предок имеет конструктор по умолчанию, то есть, осмысленно существование "пустого" объекта.
Вот в таком виде это уже кажется разумным. Изначально мне это было непонятно. Добавлено через 2 минуты и 43 секунды
Это уже ясно. Просто первоначально я не понял, какой именно класс должен иметь пустой конструктор. Я думал, что такой конструктор должен быть у каждого сериализуемого класса. Мне кажется, многие из тех, кто мне отвечал, тоже так думали ;) |
Автор: gosnis 2.3.2009, 19:09 | ||
Читаем javadoc интерфэйса Serializable:
То есть, у вас есть Base класс (несериализируемый) и его наследник - Derived класс. Что бы сделать Derived класс сериализируемым, в Base класс должен быть конструктор без аргументов (Base()) иначе получите ошибку во время запуска программы (runtime). |
Автор: COVD 2.3.2009, 20:24 | ||
Да. Я по аналогии с xml сериализацией рассуждал. Спасибо! |
Автор: chand0s 4.3.2009, 11:03 |
Для общего развития В Java есть 2 способа сделать объект сериализуемым: Serializable и Externalizable 1) Serializable При сериализации: определяются поля, которые сериализуются, , значения этих полей вычитываются через reflection и записываются в выходной поток. При десериализации: под объект выделяется место в памяти, и в эту память записываются значения из потока. Конструктор объекта не вызывается. Какие поля сериализуются/не сериализуются: поля static и transient не сериализуются. Все остальные сериализуются. Немного отдельно стоит механизм с объявлением в классе переменной serialPersistentFields. 2) Externalizable При сериализации: управление передается методу writeExternal сериализуемого объекта. Что писать в поток - решает сам объект. При десериализации: создается экземпляр объекта с помощью дефолтного конструктора и вызывается метод readExternal, который вычитывает данные из потока и присваивает значения своим полям. Какие поля можно сериализовать - а какие угодно. Вы сами это решаете в методе writeExternal. Некоторые выводы: 1) Для реализации Serializable наличие/отсутствие каких-либо конструкторов роли не играет. Для Externalizable нужен дефолтный public-конструктор (без параметров) 2) Serializable нормально сериализует/десериализует final-поля. Externalizable этого не умеет. 3) В случае Serializable static и transient поля не сериализуются. В случае Externalizable можно записать в поток все что угодно. 4) Если класс одновременно реализует Serializable и Externalizable интерфейсы - "победит" Externalizable Некоторые плюсы и минусы Externalizable: Плюс: скорость сериализации/десериализации и свобода обращения с данными. Минус: нарушение связности графа сериализуемых объектов (точнее, не нарушение, а необходимость самому за этим следить) Есть еще ряд интересных ньюансов, но что-то пост длинный слишком получается ![]() |