5

2 つHashMapの s:hashMapFooとがあるとしhashMapBarます。

いくつかのオブジェクトを作成しobjCakeputそれを両方のマップに作成するため、各マップには への参照があり、アクセス元のマップにobjCake変更を加えると、オブジェクトの正しい状態が得られます。objCake

両方のマップをシリアル化して逆シリアル化した後、オブジェクトobjCakeが 2 つの異なるオブジェクトになるという問題が発生しました。で状態を変更しましたhashMapFooが、 では何も起こりませんhashMapBarhashMapBarには正しい参照が含まれていません! すべてのマップとオブジェクトimplement Serializable

誰でも説明できますか?

4

3 に答える 3

6

私のために働く:

public class MapSerializationTest {
    private static class Foo implements Serializable {
    }

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

        Map<String, Foo> map1 = new HashMap<String, Foo>();
        map1.put("foo", foo);
        Map<String, Foo> map2 = new HashMap<String, Foo>();
        map2.put("foo", foo);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(map1);
        oos.writeObject(map2);
        oos.close();

        byte[] bytes = baos.toByteArray();

        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        ObjectInputStream ois = new ObjectInputStream(bais);
        map1 = (Map<String, Foo>) ois.readObject();
        map2 = (Map<String, Foo>) ois.readObject();
        System.out.println(map1.get("foo") == map2.get("foo")); // prints true
    }
}

コードを見せてください。おそらくreset()、最初のマップと2番目のマップの間でObjectOutputStreamを呼び出します。または、2つの異なるObjectOutputStreamインスタンスを使用します。

于 2012-07-17T13:31:29.590 に答える
4

両方のHashMapにコンテナを使用して、両方が同じオブジェクトグラフに属するようにすることができます。そうしないと、オブジェクトグラフが再作成されたときに、Javaはそれらが同じオブジェクトであると判断できません。結局のところ、それらをシリアル化し、個別に逆シリアル化しますね。

public class Container implements Serializable {
   private Map<Object, Object> hashMapFoo ;
   private Map<Object, Object> hashMapBar;

  //...
}

コンテナをシリアル化して逆シリアル化する場合、ObjectInputStreamとObjectOutputStreamはオブジェクトグラフをシリアル化/逆シリアル化する間、参照を保持するため、参照は期待どおりである必要があります。

例:

これは私のために働きます:

public static void test() {

    class Container implements Serializable {
            Map<String,StringBuilder> map1 = new HashMap<String, StringBuilder>();
            Map<String,StringBuilder> map2 = new HashMap<String, StringBuilder>();
    }

    try(ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("jedis.bin"))){

        StringBuilder text = new StringBuilder("Hello Elvis");

        Container container = new Container();
        //same object in two different maps
        container.map1.put("one", text);
        container.map2.put("one", text);

        out.writeObject(container);

    }catch(IOException e) {
        System.out.println(e.getMessage());
    }

    try(ObjectInputStream in = new ObjectInputStream(new FileInputStream("jedis.bin"))) {
        Container container = (Container) in.readObject();
        StringBuilder text1 = container.map1.get("one");
        StringBuilder text2 = container.map2.get("one");

        assert text1 == text2 : "text1 and tex2 are not the same reference";

    }catch(Exception e) {
        System.out.println(e.getMessage());
    }
}
于 2012-07-17T13:26:32.300 に答える
2

差出人:オブジェクトのシリアル化におけるセキュリティ

シリアル化パッケージを使用して、オブジェクトを再作成または再初期化することはできません。バイトストリームを逆シリアル化すると、新しいオブジェクトが作成される可能性がありますが、既存のオブジェクトの内容を上書きまたは変更することはありません。

また、外部参照を持ち、それを使用してオブジェクトの状態を変更することは(マップから参照を取得する代わりに)悪い考えです。

于 2012-07-17T13:29:38.607 に答える