3

タイプ A、B、および C のオブジェクトがあるとします。それぞれ A、B、および C のすべてのインスタンスを含む 3 つのマップがあります。内部的には、A と B の両方に C のマップがあります。アプリケーションの状態をいつでも保存および復元できるようにしたいと考えています。

そのため、今日まで、私は常にピラミッドのようなアプリケーションをシリアライズしていました。そこでは、最上位のオブジェクトで serialize を呼び出し、その呼び出しが他のすべてに伝播していました。この状況にどう対処すればよいですか?A マップで serialize を呼び出してから B マップで呼び出すと、C インスタンスが 2 回保存されませんか? 仮にそうしたとしても、A マップをデシリアライズした後に B マップをデシリアライズすると、C インスタンスを上書きしただけなので、デシリアライズはアプリケーションの状態のままになりますか?

前もって感謝します。

4

3 に答える 3

8

Java シリアライゼーション メカニズムは、同じオブジェクトへの複数の参照を認識しており、それらを複製しません。オブジェクトは一度保存され、すべての内部参照が保持されます。

逆シリアル化の後、オブジェクトは同じ状態になります。インスタンスは 1 つだけで、そのオブジェクトへの複数の参照です。

于 2012-04-29T18:13:05.950 に答える
4

ObjectOutputStream の Javadoc には次のように書かれています。

メソッド writeObject は、オブジェクトをストリームに書き込むために使用されます。文字列や配列を含むすべてのオブジェクトは、writeObject で書き込まれます。複数のオブジェクトまたはプリミティブをストリームに書き込むことができます。オブジェクトは、対応する ObjectInputstream から、書き込まれたときと同じ型および同じ順序で読み戻される必要があります。

他のオブジェクトへの参照 (一時フィールドまたは静的フィールドを除く) により、それらのオブジェクトも書き込まれます。単一のオブジェクトへの複数の参照は、参照共有メカニズムを使用してエンコードされるため、オブジェクトのグラフを元のオブジェクトが作成されたときと同じ形状に復元できます。

特に、同じオブジェクトが に繰り返し書き込まれる場合ObjectOutputStream、そのデータは 1 回だけ書き込まれます。

これを確認するには、次のプログラムを実行します。

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"
        }
    }
}
于 2012-04-29T18:17:54.270 に答える
1

最善の方法は、マップを単一のオブジェクトに格納し、このオブジェクトをシリアル化することにより、「ピラミッドのような」モデルに戻ることです。

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

シリアル化メカニズムは、同じオブジェクトのグラフと複数のインスタンスを問題なく処理します。

于 2012-04-29T18:14:22.103 に答える