Сериализация Java и дубликаты объектов

У меня есть следующая настройка:

public class A {
  private Set<C> cSet;
}

public class B {
  private Set<C> cSet;
}

public class C {}

A и B cSet могут иметь ссылки на те же экземпляры C. Я хочу сериализовать A и B таким образом, что при десериализации я не дублирую объекты C. Будет ли Java знать, как правильно поступать, если я сериализую/десериализую ее в один и тот же объект ObjectOutputStream или могу ли я получить больше экземпляров C, чем я начал с?

Ответ 1

Нет, вы не получите больше экземпляров C, чем необходимо. Это из-за того, что внутри ObjectOutputStream регистрирует каждый сериализованный объект в таблице дескрипторов. Поэтому даже при нескольких вызовах ObjectOutputStream#writeObject(Object) один и тот же объект никогда не будет записан дважды!

Рассмотрим этот код:

A a = new A();
B b = new B();
C c = new C();
a.c = c;
b.c = c;

out.writeObject(a); // writes a and c
out.writeObject(b); // writes b and the handle to c

Теперь прочитайте оба объекта:

A a2 = (A)in.readObject(); // reads a and c
B b2 = (B)in.readObject(); // reads b and handle to c, so b.c point to existing c
// now this is true: a2.c == b2.c

Это также работает, если вы дважды пишете объект дважды, например:

A a = new A();
out.writeObject(a); // writes a
out.writeObject(a); // writes handle to a

Второй writeObject будет записывать только дескриптор, а не сам объект. Это означает, что при повторной десериализации объектов вы не получите два экземпляра A:

A a1 = (A)in.readObject(); // reads a
A a2 = (A)in.readObject(); // reads the handle and returns existing a
// now this is true: a1 == a2

Вызывая reset, вы можете очистить "таблицу дескрипторов" так, чтобы поток вел себя как вновь созданный.