java - 通过对象序列化流发送具有不同字段的相同对象

标签 java multithreading sockets serialization

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

我发送的对象是由几个字段和内部另一个对象组成的类(我们将外部对象称为Wrapper和内部对象Inner。自定义对象实现可序列化

我第一次发送Wrapper时,一切工作都完美无缺。存储在 WrapperInner 和所有字段中的所有内容都可以毫无问题地序列化和反序列化。

但是,当客户端修改 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/

相关文章:

java - 更新 build.gradle 会从类路径中删除库

java - 计算 AWS4 签名后无法重置流

asp.net mvc 操作中的 c# 异步方法

sockets - "connection reset by peer"是什么意思?

Java - Java Web 应用程序中文件的相对路径

java - Autowiring :expected at least 1 bean which qualifies as autowire candidate for this dependency

java - 如何在Spring-Boot中创建DefaultMessageListenerContainer?

C# - 同时增加两个进度条(多线程)

本地主机上的 Java 和 SSL

Java Socket 为传出连接指定特定的网络接口(interface)