java中相关对象的序列化

时间:2012-04-29 18:07:26

标签: java serialization

假设我有A,B和C类型的对象。我有3个地图,分别包含A,B和C的所有实例。在内部,A和B都有C的映射。我希望能够随时存储和恢复应用程序的状态。

所以,直到今天我总是序列化类似金字塔的应用程序,我将在顶部的Object上调用serialize,并且调用将传播到其他所有内容。我该如何处理这种情况?如果我在A地图上然后在B地图上调用序列化,那么C实例是否会被保存两次?即使它们这样做,反序列化是否会离开应用程序状态,因为在反序列化A映射后反序列化B映射时它只是覆盖C实例?

提前致谢。

3 个答案:

答案 0 :(得分:4)

Java序列化机制知道对同一对象的多个引用,并且不会复制它们。该对象将被存储一次,并且将保留所有内部引用。

反序列化后,您的对象将处于相同的状态:只有一个实例和多个对该对象的引用。

答案 1 :(得分:3)

ObjectOutputStream writes的Javadoc:

  

writeObject方法用于将对象写入流。任何对象,包括字符串和数组,都是用writeObject编写的。可以将多个对象或基元写入流。必须从相应的ObjectInputstream中读取对象,这些对象具有与写入时相同的类型和顺序。

  

对其他对象的引用(瞬态或静态字段除外)也会导致写入这些对象。使用引用共享机制对对单个对象的多个引用进行编码,以便可以将对象图形恢复为与写入原始图像时相同的形状。

特别是,如果将同一个对象重复写入ObjectOutputStream,其数据只会写入一次。

您可以通过运行以下程序来验证这一点:

class A implements Serializable {
    C c;
}

class B implements Serializable {
    C c;
}

class C implements Serializable {

}

public class Test {

    public static void main(String[] args) throws Exception {
        C c = new C();

        A a = new A();
        a.c = c;

        B b = new B();
        b.c = c;


        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(a);
            oos.writeObject(b);
            oos.writeObject(c);
        }
        byte[] data = baos.toByteArray();

        try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {
            A newA = (A) ois.readObject();
            B newB = (B) ois.readObject();
            C newC = (C) ois.readObject();

            System.out.println(newA.c == newC && newB.c == newC); // prints "true"
        }
    }
}

答案 2 :(得分:1)

最好的办法是回到你的“金字塔式”模型,将你的地图存储在一个对象中,然后序列化这个对象;

public class ApplicationState implements Serializable {
    private Map<Foo, A> aMap;
    private Map<Bar, B> bMap;
}

序列化机制可以毫无问题地处理同一对象的图形和多个实例。