5

假设我有两个HashMaps:hashMapFoohashMapBar.

我在两个地图中创建了一些对象objCakeput因此每个地图都有一个对 的引用objCake,当我对我访问它的任何地图进行一些更改时objCake,我得到了我的对象的正确状态。

在我序列化两个地图并反序列化它们之后,我遇到了我的对象objCake变成了两个不同的对象的问题!我在 中更改了它的状态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()第一个和第二个地图之间的 ObjectOutputStream。或者您使用两个不同的 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

来自:对象序列化中的安全性

序列化包不能用于重新创建或重新初始化对象。反序列化字节流可能会导致创建新对象,但不会覆盖或修改现有对象的内容。

另外 - 使用外部引用并修改对象状态(而不是从 Map 获取引用)是一个坏主意。

于 2012-07-17T13:29:38.607 回答