Java示例中的双重调度

时间:2012-10-31 05:00:23

标签: java double-dispatch

我正在阅读DD上的维基百科文章,并跳到最后给出的"Double dispatch in Java and an example"链接。以下Serializable示例的描述对我来说似乎相当混乱:

A a = new A();
ObjectOutputStream oos = new ObjectOutputStream();
oos.writeObject( a);

以下是描述:

  

为了序列化A,ObjectOutputStream首先查看方法writeObject( ObjectOutputStream oos)是否存在。如果是,则调用该方法作为参数。然后writeObject方法将调用发送回ObjectOutputStream(从而使其成为双重调度)。在进行这个非常简单的回调时,ObjectOutputStream已经说过:“我将你的州写入这个流的责任归还给你”。在做出这个简单的选择时,ObjectOutputStream已将自己与对象A分离。对象A反过来说好了,这是我想在流上写的一些状态。如果该值是基元,则可以通过写入方法的重载来处理它。如果没有,则来回可以在对象图中的下一级继续,直到所有有用的状态都被放置在流上。

我猜测描述可能会令人困惑,因为所描述的是幕后发生的事情,而不是代码,因为否则它似乎没有多大意义。以下是令我困惑的部分:

  • ObjectOutputStream首先查看方法writeObject( ObjectOutputStream oos)是否存在”。为什么ObjectOutputStream需要检查此方法是否存在,因为它是自己的方法?
  • “如果确实如此,那么它将自己作为参数调用该方法”。在我看来,它正在使用writeObject的实例作为参数调用A。回到上一个项目,如果使用writeObject的实例调用ObjectOutputStream arg,为什么它会查找带有A arg的writeObject签名?
  • ObjectOutputStream方法然后将回调调度回writeObject(从而使其成为双重调度)”。同样,ObjectOutputStream方法属于ObjectOutputStream类,因此我无法看到它如何“发送回{{1}}”,因为它似乎是原始目标。

我是否只是缺少一些基本的东西,或者这是一个写得不好的/描述的例子?如果这是一个不好的例子,我想改变维基百科的文章,指出一个更好的文章,所以随时提供建议。

感谢。

2 个答案:

答案 0 :(得分:4)

按顺序回答您的问题:

  1. ObjectOutputStream.writeObject(Object)检查其参数(使用反射)以确定对象是否实现writeObject(ObjectOutputStream)。也就是说,它或多或少地询问对象,“你知道如何将你的结构写成ObjectOutputStream吗?”

  2. 如果答案为“是”,则ObjectOutputStream调用对象的 writeObject(ObjectOutputStream)方法,传递自己(ObjectOutputStream,而不是object)作为参数。它基本上说:“好。把你的结构写给我。”

  3. 对象中writeObject(ObjectOutputStream)的实现调用ObjectOutputStream来编写自身的元素。它不应该再次呼叫oos.writeObject(this)

  4. 例如,假设我有一个这样的对象:

    class A {
        int x;
    }
    

    如果我想让它自己写入ObjectOutputStream,我可能会像这样展开它:

    class A implements Serializable {
        int x;
        private void writeObject(ObjectOutputStream stream) throws IOException {
            stream.writeInt(x);
        }
    }
    

    然后这段代码:

    A a = new A();
    ObjectOutputStream oos = . . .;
    oos.writeObject(a);
    

    会使用类writeObject中的A方法来编写a,而不是使用反射来编写A的所有(非瞬态)字段。(在这种情况下,不过,没有区别。)

答案 1 :(得分:1)

来自Serializable界面的文档:

  

在序列化期间需要特殊处理的类   反序列化过程必须实现这些特殊方法   确切的签名:

     

private void writeObject(java.io.ObjectOutputStream out)        抛出IOException private void readObject(java.io.ObjectInputStream in)        抛出IOException,ClassNotFoundException; private void readObjectNoData()        抛出ObjectStreamException;

如果你想使你的类可序列化实现接口就足够了。但是,如果你想让make(类的)对象本身告诉输出流如何序列化它自己的状态,那么它应该实现这些方法。