我有一个客户端/服务器程序,我通过ObjectOutputStream
和writeObject()
通过readObject()
发送对象。
我发送的对象是由几个字段和内部另一个对象组成的类(让我们调用外部对象Wrapper
和内部Inner
。两个自定义对象都实现{{1 }}
我第一次发送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"
现在新值将按原样更新。
为什么序列化以这种方式工作?
答案 0 :(得分:2)
这是ObjectOutputStream
的预期行为。引用Javadocs:
使用参考共享机制对单个对象的多个引用进行编码,以便可以将对象图形恢复为与写入原始图像时相同的形状。
由于您使用相同的内部类引用,它只是通过对先前发送的对象的引用发送。它不检查所有对象的所有字段,以查看是否有任何更改。我怀疑inner.getValue()
不仅等于发送的第一个对象,而且第二个对象中服务器收到的inner
对象是同一个对象({{1} })作为第一个对象的==
。
如果您曾致电:
inner
在发送带有调整后的out.reset();
字段的对象之前,您的代码应该可以正常工作。 inner
方法清除引用缓存,这有助于序列化流的高效。作为旁注,如果要在流中发送大量个临时对象,则reset()
尤为必要,因为否则这些对象会缓存在内存中并导致堆耗尽。