有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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,Java会知道如何做正确的事情吗?或者我最终会得到比最初更多的C实例吗


共 (1) 个答案

  1. # 1 楼答案

    不,您不会得到超过必要数量的C实例。这是因为在内部,^{}在一个“句柄表”中注册所有曾经序列化过的对象。因此,即使在多次调用^{}时,同一个对象也不会被写入两次

    用于^{}的API文档:

    (...) Multiple references to a single object are encoded using a reference sharing mechanism so that graphs of objects can be restored to the same shape as when the original was written. (...)

    考虑此代码(假定{{CD5>},^ {< CD6>}和^ {< CD1>}是^{},并且两者,^ {< CD5>}和^ {CD6>}有一个非瞬时字段^ {CD11>}指向^ {CD1>}的实例):

    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
    

    通过调用^{},可以清除“handle table”,这样流的行为就像新创建的一样

    请注意,ObjectOutputStream还提供了一个方法^{},该方法始终将对象作为新的唯一对象写入流