0

我有一个客户端/服务器程序,我ObjectOutputStream通过writeObject()和发送对象readObject()

我发送的对象是由几个字段和另一个内部对象组成的类(让我们调用外部对象Wrapper和内部对象Inner。两个自定义对象都实现serializable.

我第一次发送Wrapper过来时,一切正常。存储在两者Wrapper中的所有内容,Inner所有字段都可以毫无问题地进行序列化和反序列化。

但是,当客户端随后修改Inner类,将其放入 中Wrapper并再次发送时,Inner服务器接收到的实例与第一次接收到的实例相同。

我的客户:

Inner inner = new Inner();
inner.setValue("value");

ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(new Wrapper(inner));

服务器:

ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
Wrapper wrapper = (Wrapper) in.readObject();
String value = wrapper.getInner().getValue();

Inner客户端然后用不同的字符串(即包含其他字母然后第一个)修改类(与以前相同的实例):

inner.setValue("newValue");
out.writeObject(new Wrapper(inner));

但是,当我查看inner.getValue()服务器上的 时,它并没有改变,仍然等于"value".

在发送之前,我通过制作内部类的硬拷贝解决了这个问题:

Inner newInner = new Inner();
newInner.setValue("newValue");
out.writeObject(new Wrapper(newInner));

现在,新值已按应有的方式更新。

为什么序列化以这种方式工作?

4

1 回答 1

2

这是预期的行为ObjectOutputStream。引用 Javadocs:

对单个对象的多个引用使用引用共享机制进行编码,以便对象的图形可以恢复到与原始对象相同的形状。

由于您使用的是相同的内部类引用,它只是发送对先前发送的对象的引用。它不会检查所有对象的所有字段以查看它们是否已更改。我怀疑这不仅inner.getValue()等于发送的第一个对象,而且inner服务器在第二个对象中接收到的对象与来自第一个对象的对象( ==)相同inner

如果您致电:

out.reset();

在发送带有调整inner字段的对象之前,您的代码应该可以工作。该reset()方法清除了有助于序列化流高效的参考缓存。作为旁注,reset()如果您通过流发送大量临时对象,则尤其必要,因为否则这些对象会缓存在内存中并可能导致堆耗尽。

于 2013-02-14T20:10:15.047 回答