假设我有两个HashMap
:hashMapFoo
和hashMapBar
。
我在两个地图中创建了一些对象objCake
和put
,因此每个地图都引用了objCake
,当我对objCake
进行一些更改时,无论哪个地图我从中获取它,我得到了我的对象的正确状态。
在我序列化两个地图并反序列化之后,我遇到问题,我的对象objCake
已成为两个不同的对象!我在hashMapFoo
中更改了其状态,但在hashMapBar
中没有任何反应。 hashMapBar
不再包含正确的引用!
所有地图和对象implement Serializable
。
有人可以解释一下吗?
答案 0 :(得分: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
}
}
告诉我们你的代码。您可能在第一个和第二个映射之间的ObjectOutputStream上调用reset()
。或者您使用两个不同的ObjectOutputStream实例。
答案 1 :(得分:4)
您可以为HashMaps使用容器,以便它们都属于同一个对象图,否则,在重新创建对象图时,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());
}
}
答案 2 :(得分:2)
来自:Security in Object Serialization:
序列化包不能用于重新创建或重新初始化 对象。反序列化字节流可能会导致创建新的 对象 ,但不会覆盖或修改现有内容 对象。
另外 - 使用外部引用并使用它来修改对象状态(而不是从Map获取引用)是一个坏主意。