【问题标题】:Java Serialization through Network, repasses same objects?Java通过网络序列化,重新传递相同的对象?
【发布时间】:2013-11-21 20:43:47
【问题描述】:

我要布局情况,问题在底部。

我有一个像这样的对象:

public class GameObject implements Serializable{
/**
 * 
 */
    private static final long serialVersionUID = 3081889342394131807L;
    public float x, y, vx, vy;
    public int size;
    public int mass;

    public GameObject()
    {
        Random rand = new Random();
        x = rand.nextInt(400);
        y = rand.nextInt(400);
        size = rand.nextInt(10);
        mass = size * size * size;
        vx = 0.3f;
        vy = 0.3f;
    }

    public void updateGameObject()
    {
        x+=vx;
        y+=vy;
    }
}

我有一个使用套接字的客户端-服务器设置:当服务器启动时,它会创建一个 GameObject 并将其添加到 HashMap。然后服务器循环,更新对象并发送更新的对象。连接是标准套接字。

while (true)
{
    gameObject.updateGameObject();
    try {
        if (objOutputStream == null)
            objOutputStream = new ObjectOutputStream(connection.getOutputStream());
        objOutputStream.writeObject(o);
        objOutputStream.flush();
    } catch (Exception e) { e.printStackTrace(); }
}

在客户端,我只是读取对象并将其绘制到屏幕上。这就是问题发生的地方。我肯定会在每个循环中收到一个对象,但是当我阅读它时,GameObject 的字段似乎没有改变。

while (true)
{
    try {
            if (objInputStream == null)
                objInputStream = new ObjectInputStream(connection.getInputStream());
            return objInputStream.readObject();
        } catch (Exception e) { e.printStackTrace(); }
}

objInputStream 和 objOutputStream 都在 while 循环之上初始化。

如果我对我在客户端获取的对象的 x 和 y 值执行 println(),则这些值永远不会从它们的初始值改变。

当我在发送之前对服务器上的 x 和 y 值执行 println() 时,它会打印出正确的值。像这样:

Sending Object with 1, 1
Received Object with 1, 1
Sending Object with 2, 2
Received Object with 1, 1
Sending Object with 3, 3
Received Object with 1, 1

我觉得我缺少一些基本的东西。虽然当我尝试找到与这个问题有关的其他问题时,我似乎找不到一个。也许你们中的一个可以提供一些见解?

【问题讨论】:

    标签: java sockets serialization deserialization


    【解决方案1】:

    ObjectOutputStream 试图通过不将您之前写入的任何对象重新写入流(由引用相等性,而不是equals() 确定)来使序列化复杂的对象图变得轻松。

    一个懒惰的解决方案是在发送之前实现 Cloneableclone() 您的对象 - 但除非您使用的是非常古老的 JDK,否则您需要调用 writeUnshared(),因为它会写一个“对象的新”副本,而不是对先前版本的引用。

    【讨论】:

    • 或者,您可以在每次编写对象时使用新的ObjectOutputStream,以避免此问题。那么你就不需要clone了。我不确定哪种方法更有效。
    • @RobinGreen 不,这只会导致更多问题。接收者如何知道何时创建新的ObjectInputStream?
    • 不是一个好的答案。 reset() 在一行代码中完成,而不必在所有相关对象中实现 Cloneable。
    • 这个解决方案确实对我有用,但我可能会将其更改为 reset 或 writeUnshared;如果我不需要,我看不到创建一堆额外对象的意义。感谢您告诉我有关克隆的信息(以前不知道)并解释为什么这些对象似乎发送过时的数据。当我获得足够的声望时,我会尽量记住投票。
    • 不用担心 - 我在脑海中写下了我的答案,不知道writeUnshared()。现在已经编辑以避免误导粗心的人(并在几天前支持其他答案)。
    【解决方案2】:

    使用ObjectOutputStream.writeUnshared() 代替writeObject(), 或调用reset() 以重新开始使用一组新值。

    【讨论】:

    • 感谢添加此解决方案,它更直接地解决了问题。在发送之前克隆所有对象有点烦人。如果有人好奇为什么你应该使用这些方法而不是普通的 writeObject(),请阅读下面 pobrelkey 的答案。
    猜你喜欢
    • 1970-01-01
    • 2015-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-13
    • 2014-07-30
    相关资源
    最近更新 更多