在对象序列化流上发送具有不同字段的相同对象

时间:2013-02-14 20:03:30

标签: java multithreading sockets serialization

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

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

我第一次发送serializable时,一切都完美无瑕。存储在WrapperWrapper和所有字段中的所有内容都会毫无问题地序列化和反序列化。

然而,当客户端随后修改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"

现在新值将按原样更新。

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

1 个答案:

答案 0 :(得分:2)

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

  

使用参考共享机制对单个对象的多个引用进行编码,以便可以将对象图形恢复为与写入原始图像时相同的形状。

由于您使用相同的内部类引用,它只是通过对先前发送的对象的引用发送。它检查所有对象的所有字段,以查看是否有任何更改。我怀疑inner.getValue()不仅等于发送的第一个对象,而且第二个对象中服务器收到的inner对象是同一个对象({{1} })作为第一个对象的==

如果您曾致电:

inner

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