我有一个客户端/服务器程序,我通过 writeObject()
和 readObject()
通过 ObjectOutputStream
发送对象。
我发送的对象是由几个字段和内部另一个对象组成的类(我们将外部对象称为Wrapper
和内部对象Inner
。自定义对象实现可序列化
。
我第一次发送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));
新值现在已按其应有的方式更新。
为什么序列化会这样工作?
最佳答案
这是 ObjectOutputStream
的预期行为。引用 Javadocs 中的内容:
Multiple references to a single object are encoded using a reference sharing mechanism so that graphs of objects can be restored to the same shape as when the original was written.
由于您使用相同的内部类引用,因此它只是发送对先前发送的对象的引用。它不会检查所有对象的所有字段以查看其中是否有任何已更改。我怀疑 inner.getValue()
不仅等于发送的第一个对象,而且服务器在第二个对象中接收的 inner
对象也相同 object (==
) 作为第一个对象的内部
。
如果您调用:
out.reset();
在发送带有调整后的inner
字段的对象之前,您的代码应该可以工作。 reset()
方法清除引用缓存,这有助于提高序列化流的效率。附带说明一下,如果您要通过流发送大量临时对象,则 reset()
尤其必要,否则这些对象会缓存在内存中并可能导致堆疲惫不堪。
关于java - 通过对象序列化流发送具有不同字段的相同对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14883073/