Java отслеживает объекты, которые были записаны в поток, и последующие экземпляры записываются в виде идентификатора, а не фактического сериализованного объекта.
Итак, для вашего примера, если вы напишите экземпляр «a» в поток, поток даст этому объекту уникальный идентификатор (скажем, «1»). Как часть сериализации «a», вы должны сериализовать «b», и поток дает ему другой идентификатор («2»). Если вы затем пишете «b» в поток, единственное, что пишется, это идентификатор, а не фактический объект.
Входной поток делает то же самое в обратном порядке: для каждого объекта, который он читает из потока, он назначает идентификационный номер, используя тот же алгоритм, что и выходной поток, и этот идентификационный номер ссылается на экземпляр объекта на карте. Когда он видит объект, который был сериализован с использованием идентификатора, он получает исходный экземпляр с карты.
Вот как описывают документы API :
Несколько ссылок на один объект кодируются с использованием механизма совместного использования ссылок, так что графики объектов могут быть восстановлены в той же форме, что и при написании оригинала.
Такое поведение может вызвать проблемы: поскольку поток содержит жесткую ссылку на каждый объект (чтобы он знал, когда заменить идентификатор), вы можете исчерпать память, если вы записываете много временных объектов в поток. Вы решаете это по телефону reset()
.
В Java это решается путем кэширования сериализованных объектов и записи дескриптора этого при повторной записи.
См. Шаг 5 в http://docs.oracle.com/javase/6/docs/platform/serialization/spec/output.html .
источник