【问题标题】:Java serialization and duplicate objectsJava序列化和重复对象
【发布时间】:2013-12-03 07:33:26
【问题描述】:

我有以下设置:

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

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

public class C {}

A 和 B 的 cSet 可能引用相同的 C 实例。我想序列化 A 和 B 以便在反序列化时我没有重复的 C 对象。如果我将它序列化/反序列化到同一个 ObjectOutputStream 中,Java 会知道如何做正确的事情,还是我最终会得到比开始时更多的 C 实例?

【问题讨论】:

  • 有趣的问题...您是否尝试过序列化/反序列化并检查结果?
  • @user1339772,这个问题略有不同,因为它写入两个不同的文件。就我而言,我仍在写入一个文件。
  • 我希望我能遇到这样的情况,你的问题对我有很大的参考意义。 +代表

标签: java serialization duplicates


【解决方案1】:

不,您不会获得比必要更多的 C 实例。这是因为在内部,ObjectOutputStream 将每个曾经序列化的对象都注册到一个“句柄表”中。因此,即使多次调用writeObject(Object),同一个对象也永远不会被写入两次!

ObjectOutputStream 的 API 文档:

(...) 使用引用共享机制对单个对象的多个引用进行编码,以便对象的图形可以恢复到与原始对象相同的形状。 (...)

考虑这段代码(假设ABCSerializable 和两者,AB 有一个非瞬态字段c 指向C 的实例):

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 points 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,您可以清除“句柄表”,以便流的行为就像新创建的一样。

请注意,ObjectOutputStream 还提供了一个方法 writeObjectUnshared(Object),该方法始终将对象作为新的唯一对象写入流。

【讨论】:

  • 我不这么认为,他应该定义一个同时引用A和B的容器对象,并序列化该容器,反序列化时一切正常,但调用writeObject(a),writeObject( b) 不能随心所欲地工作。
  • @isnot2bad 代码应该可以工作,直到您调用 out.reset(),这会清除该处理表。
  • @AmirPashazadeh 是的,确实是这样!随意复制代码并运行它!
猜你喜欢
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
  • 2016-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多