2

DDに関するウィキペディアの記事を読んでいて、最後にある「Java でのダブル ディスパッチと例」リンクにジャンプしました。次の Serializable の例の説明は、私にとってかなり混乱しているようです。

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

説明は次のとおりです。

A をシリアル化するために、ObjectOutputStreamまずメソッドwriteObject( ObjectOutputStream oos)が存在するかどうかを確認します。存在する場合は、それ自体を引数としてそのメソッドを呼び出します。次に、writeObjectメソッドは呼び出しを にディスパッチしますObjectOutputStream(したがって、これは二重ディスパッチになります)。この非常に単純なコールバックを行う際に、ObjectOutputStreamは次のように述べています。「このストリームに状態を​​書き込む責任をあなたに委任します」その単純な選択を行うことで、ObjectOutputStreamはオブジェクトから切り離されましAた。オブジェクトAは、OK を返します。ここに、ストリームに書き込みたい状態があります。値がプリミティブの場合、write メソッドのオーバーロードによって処理できます。そうでない場合は、すべての有用な状態がストリームに配置されるまで、オブジェクト グラフの次のレベルで前後に続行できます。

説明されているのは舞台裏で起こっていることであり、提示されたコードではないため、説明が混乱している可能性があると思います。ここに私を混乱させる部分があります:

  • ObjectOutputStreamまず、メソッドwriteObject( ObjectOutputStream oos)が存在するかどうかを確認します」。ObjectOutputStreamこのメソッドは独自のメソッドであるため、このメソッドの存在を確認する必要があるのはなぜですか?
  • 「そうであれば、それ自体を引数としてそのメソッドを呼び出します」。writeObjectのインスタンスをA引数として呼び出しているように見えます。前の項目に戻ると、 のインスタンスで呼び出されているのに、なぜ argでwriteObject署名を探すのでしょうか?ObjectOutputStreamA
  • writeObjectその後、メソッドは呼び出しをにディスパッチしますObjectOutputStream(したがって、これを二重ディスパッチにします)」。繰り返しますが、writeObjectメソッドはクラスに属しているため、元の宛先のように見えるためObjectOutputStream、これがどのように「にディスパッチされているか」を確認できません。ObjectOutputStream

ここで基本的な何かが欠けているだけですか、それともこれは不十分に書かれた/説明された例ですか? それが悪い例である場合は、ウィキペディアの記事をより良い例に変更したいので、お気軽に提案をお寄せください.

ありがとう。

4

2 に答える 2

4

質問に順番に答えるには:

  1. ObjectOutputStream.writeObject(Object)はその引数を (リフレクションを使用して) チェックして、オブジェクトが を実装しているかどうかを判断しますwriteObject(ObjectOutputStream)。つまり、多かれ少なかれオブジェクトに「構造体を に書き込む方法を知っていますObjectOutputStreamか?」と尋ねます。

  2. 答えが「はい」の場合、はオブジェクトのObjectOutputStreamメソッドを呼び出し、それ自体 (オブジェクトではなく ) を引数として渡します。それは基本的に、「よし、あなたの構造を私に書いてくれ」と言います。 writeObject(ObjectOutputStream)ObjectOutputStream

  3. writeObject(ObjectOutputStream)オブジェクト内の の実装はObjectOutputStream、それ自体の要素を書き込むために を呼び出します。再度呼び出すことは想定されていませんoos.writeObject(this)

たとえば、次のようなオブジェクトがあるとします。

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);

リフレクションを使用して A のすべての (非一時的な) フィールドを書き込むのではなく、writeObjectクラス内のメソッドを使用して を書き込みます (ただし、この場合、違いはありません)。Aa

于 2012-10-31T05:08:18.150 に答える
1

Serializableインターフェイスのドキュメントから:

シリアライゼーションおよびデシリアライゼーション プロセス中に特別な処理を必要とするクラスは、次の正確なシグネチャを持つ特別なメソッドを実装する必要があります。

private void writeObject(java.io.ObjectOutputStream out) は IOException をスローします private void readObject(java.io.ObjectInputStream in) は IOException、ClassNotFoundException をスローします。private void readObjectNoData() は ObjectStreamException をスローします。

クラスをシリアライズ可能にしたい場合は、インターフェースを実装するだけで十分です。ただし、(クラスの) オブジェクト自体を出力ストリームに自身の状態をシリアル化する方法を伝えたい場合は、それらのメソッドを実装する必要があります。

于 2012-10-31T05:14:54.603 に答える