Java 套接字/序列化,对象不会更新

2022-09-03 18:11:09

我正在编写一个基于套接字的小程序。我正在使用类 ModelEvent 通过套接字传递信息。在 ModelEvent 中,有一个类型 (Object) 的变量 obect。

对象本身是具有某些值的 2D 数组。

object[1][2] = 2;
ModelEvent event = new ModelEvent("allo", object);
dispatchEvent(event);

object[2][3] = 2;
ModelEvent event2 = new ModelEvent("you", object);
dispatchEvent(event2);

假设数组对象用值 1 填充。第一个事件(事件)由客户端接收,数据是正确的。通过数据不正确发送的第二个事件。其数据与第一次调度中的数据相同。“allo”和“you”是看看我是否没有两次阅读同一事件,答案不是。字符串是正确的,但对象不是事件(如果已更新)。在发送第二个事件之前,我循环访问了数组,以查看它是否在服务器端进行了更新,并且确实如此。但在客户端,它仍然与第一次调度中相同,即使事件本身已更改也是如此。


答案 1

请参阅 ObjectOutputStream.reset

重置将忽略已写入流的任何对象的状态。状态被重置为与新 .流中的当前点被标记为已重置,因此相应的点将在同一点重置。以前写入流的对象不会被引用为已在流中。它们将再次写入流。ObjectOutputStreamObjectInputStream

/* prevent using back references */
output.reset();
output.writeObject(...);

在写入同一对象之前调用 reset,以确保其更新状态已序列化。否则,它将仅使用对先前写入的对象及其过期状态的反向引用

或者,您也可以使用 ObjectOutputStream.writeUnshared,如下所示。

将“未共享”对象写入 .此方法与 相同,只是它始终将给定对象作为流中新的唯一对象写入(而不是指向以前序列化的实例的反向引用)。ObjectOutputStreamwriteObject

具体说来:

  • 通过 writeUnshared 编写的对象始终以与新出现的对象(尚未写入流的对象)相同的方式进行序列化,而不管该对象以前是否被写入过。

  • 如果 用于写入以前使用 writeUnshared 编写的对象,则以前的 writeUnshared 操作将被视为对单独对象的写入。换句话说,永远不会生成对通过调用 写入的对象数据的反向引用。writeObjectObjectOutputStreamwriteUnshared

虽然通过编写对象本身并不能保证在反序列化对象时对对象的唯一引用,但它允许在流中多次定义单个对象,以便接收方对的多次调用不会发生冲突。请注意,上述规则仅适用于与 一起编写的基级对象,而不适用于要序列化的对象图中任何可传递引用的子对象。writeUnsharedreadUnsharedwriteUnshared

output.writeUnshared(...);

请注意,最好将其与 ObjectInputStream.readUnshared 结合使用。

从 中读取“未共享”对象。此方法与 readObject 相同,只是它阻止后续调用以及返回对通过此调用获取的反序列化实例的其他引用。ObjectInputStreamreadObjectreadUnshared

具体说来:

  • 如果调用 来反序列化反向引用(之前已写入流的对象的流表示形式),则将抛出readUnsharedObjectStreamException
  • 如果返回成功,则任何后续尝试反序列化对反序列化为 的流句柄的引用都将导致抛出 。readUnsharedreadUnsharedObjectStreamException

通过 反序列化对象会使与返回对象关联的流句柄失效。请注意,这本身并不总是保证 返回的引用是唯一的。反序列化的对象可以定义一个方法,该方法返回对其他方可见的对象,或者readUnshared可以返回可在流中的其他地方或通过外部方式获得的对象或常量。如果反序列化对象定义了一个方法,并且该方法的调用返回一个数组,则返回该数组的浅克隆;这保证了返回的数组对象是唯一的,并且不能从 上的调用或读取不共享中获取第二次,即使底层数据流已纵也是如此。readUnsharedreadUnsharedreadResolveClassenumreadResolvereadUnsharedreadObjectObjectInputStream

obj = input.readUnshared();

答案 2

我没有看到 dispatchEvent 代码,但从你写的内容中,我假设以下内容:你编写相同的对象(仅更改其状态),这意味着它只会写入引用两次。您可以在java输出流文档中看到(用于性能)。

你应该使用 writeUnshared(),它将在每次写入时创建一个新对象

我看到建议重置,这将使您获得相同的结果,但它会影响性能。