目次 | 前の項目 | 次の項目 Java オブジェクト直列化仕様


2.1 ObjectOutputStream クラス

クラス ObjectOutputStream は、オブジェクト直列化を実装するためのものです。このクラスは、すでに直列化されたオブジェクトセットなどのストリームの状態を維持します。そのメソッドは、直列化するオブジェクトのトラバーサルを制御して、指定されたオブジェクトと参照するオブジェクトを保管します。

package java.io;

public class ObjectOutputStream
    extends OutputStream
    implements ObjectOutput, ObjectStreamConstants
{
    public ObjectOutputStream(OutputStream out)
        throws IOException;

    public final void writeObject(Object obj)
        throws IOException;

    public void defaultWriteObject();
        throws IOException, NotActiveException;

    public PutField putFields()
        throws IOException;

    public writeFields()
        throws IOException;

    public void reset() throws IOException;

    protected void annotateClass(Class cl) throws IOException;

    protected Object replaceObject(Object obj) throws IOException;

    protected boolean enableReplaceObject(boolean enable)
        throws SecurityException;

    protected void writeStreamHeader() throws IOException;

    public void write(int data) throws IOException;

    public void write(byte b[]) throws IOException;

    public void write(byte b[], int off, int len) throws IOException;

    public void flush() throws IOException;

    protected void drain() throws IOException;

    public void close() throws IOException;

    public void writeBoolean(boolean data) throws IOException;

    public void writeByte(int data) throws IOException;

    public void writeShort(int data) throws IOException;

    public void writeChar(int data) throws IOException;

    public void writeInt(int data) throws IOException;

    public void writeLong(long data) throws IOException;

    public void writeFloat(float data) throws IOException;

    public void writeDouble(double data) throws IOException;

    public void writeBytes(String data) throws IOException;

    public void writeChars(String data) throws IOException;

    public void writeUTF(String data) throws IOException;

    // Inner class to provide access to serializable fields.
    abstract static public class PutField
    {
        public void put(String name, boolean value)
            throws IOException, IllegalArgumentException;

        public void put(String name, char data)
            throws IOException, IllegalArgumentException;

        public void put(String name, byte data)
            throws IOException, IllegalArgumentException;

        public void put(String name, short data)
            throws IOException, IllegalArgumentException;

        public void put(String name, int data)
            throws IOException, IllegalArgumentException;

        public void put(String name, long data)
            throws IOException, IllegalArgumentException;

        public void put(String name, float data)
            throws IOException, IllegalArgumentException;

        public void put(String name, double data)
            throws IOException, IllegalArgumentException;

        public void put(String name, Object data)
            throws IOException, IllegalArgumentException;
    }

    public void useProtocolVersion(int version) throws IOException;

    protected ObjectOutputStream()
        throws IOException;

     protected writeObjectOverride()
        throws NotActiveException, IOException;
}
ObjectOutputStream コンストラクタには、OutputStream が必要です。このコンストラクタは、writeStreamHeader を呼び出して、マジック番号とバージョンをストリームに書き込みます。そして、このストリームは、ObjectInputStream コンストラクタの対応する readStreamHeader によって読み込まれ、検査されます。

writeObject メソッドは、オブジェクトをストリームに直列化するために使用します。オブジェクトは、次のように直列化されます。

  1. サブクラスが実装をオーバーライドする場合は、writeObjectOverride メソッドを呼び出してから、復帰します。実装のオーバーライドは、この節の最後で説明します。
  2. ブロックデータバッファにデータがあれば、それがストリームに書き込まれ、バッファがリセットされます。
  3. オブジェクトが null であれば、null がストリームに置かれ、writeObject から戻ります。
  4. 手順 8 に示したように、オブジェクトが以前に置き換えられていれば、置き換えのハンドルをストリームに書き込み、writeObject から戻ります。
  5. オブジェクトがストリームにすでに書き込まれていれば、そのハンドルがストリームに書き込まれ、writeObject から戻ります。
  6. オブジェクトが Class であれば、対応する ObjectStreamClass がストリームに書き込まれ、そのクラスのハンドルが割り当てられ、writeObject から戻ります。
  7. オブジェクトが ObjectStreamClass であれば、そのクラスの記述子がストリームに書き込まれます。これには、その名前、serialVersionUID、名前と型別のフィールドリストが含まれます。この記述子のハンドルが割り当てられます。writeObject から戻る前に、annotateClass サブクラスメソッドが呼び出されます。
  8. オブジェクトのクラスまたは ObjectInputStream のサブクラスによる置換を処理します。
    1. オブジェクトのクラスが適切な writeReplace メソッドを定義する場合は、そのメソッドが呼び出されます。このメソッドは、オプションで、直列化する置換オブジェクトを返すこともできます。
    2. 次に、enableReplaceObject メソッドの呼び出しによって有効になっていれば、replaceObject メソッドを呼び出して、直列化されるオブジェクトを ObjectOutputStream のサブクラスに置換できます。前の手順で元のオブジェクトが置き換えられている場合は、置換オブジェクトに対し replaceObject メソッドが呼び出されます。

    元のオブジェクトが上のどちらかまたは両方の手順によって置き換えられた場合は、元のオブジェクトから置換オブジェクトへのマッピングが格納されて、手順 4 で使用されます。新しいオブジェクトに対して、手順 3 から 7 が繰り返されます。

    置換オブジェクトが手順 3 から 7 で処理される型でない場合は、その置換オブジェクトを使った処理は手順 10 で再開されます。

  9. オブジェクトが java.lang.String であれば、その文字列が Universal Transfer Format (UTF) 形式で書き込まれ、ハンドルがその文字列に割り当てられ、writeObject から戻ります。
  10. オブジェクトが配列であれば、その配列の ObjectStreamClass を書き込むために、writeObject が再帰的に呼び出されます。その配列のハンドルが割り当てられます。このハンドルのあとには、配列の長さが続きます。次に、配列の各要素がストリームに書き込まれ、そのあと writeObject から戻ります。
  11. 正規オブジェクトの場合は、そのオブジェクトのクラスに対する ObjectStreamClass が、再帰的に呼び出される writeObject によって書き込まれます。これは、初めて参照されたときにだけストリームで行われます。このオブジェクトのハンドルが割り当てられます。
  12. オブジェクトの内容がストリームに書き込まれます。
    1. オブジェクトが直列化可能であれば、最上位の直列化可能クラスが見つけられます。そのクラスと各派生クラスに対し、そのクラスのフィールドが書き込まれます。そのクラスに writeObject メソッドがない場合は、defaultWriteObject メソッドが呼び出され、直列化可能フィールドがストリームに書き込まれます。そのクラスに writeObject メソッドがあれば、それが呼び出されます。このクラスは、defaultWriteObject または putFields、および writeFields を呼び出して、オブジェクトの状態を保管してから、他の情報をストリームに書き込むことができます。
    2. そのオブジェクトが外部化可能であれば、そのオブジェクトの writeExternal メソッドが呼び出されます。
    3. オブジェクトが直列化可能でも外部化可能でもなければ、NotSerializableException がスローされます。
トラバーサルの間に、または基本のストリーム内で例外が起こることがあります。IOException のどのサブクラスでも、例外は例外プロトコルを使ってストリームに書き込まれ、ストリーム状態は破棄されます。1 つ目の例外がストリームに書き込まれようとしているときに 2 つ目の IOException がスローされた場合は、そのストリームは不明な状態のままになり、writeObject から StreamCorruptedException がスローされます。ほかの例外では、ストリームは打ち切られ、不明で使用不能な状態のままになります。

defaultWriteObject メソッドは、現在のクラスのデフォルトの直列化機構を実装するためのものです。このメソッドは、クラスの writeObject メソッドだけから呼び出すことができます。このメソッドは、現在のクラスのすべての直列化可能フィールドをストリームに書き込みます。writeObject メソッド以外から呼び出すと、NotActiveException がスローされます。

putFields メソッドは、呼び出し元がストリームに直列化可能フィールドの値を設定するために使う PutField オブジェクトを返します。フィールドは、任意の順序で設定が可能です。すべてのフィールドが設定されたあと、フィールド値をストリームに標準の順序で書き込むために、writeFields が呼び出される必要があります。フィールドが設定されない場合は、そのフィールドの型に適切したデフォルト値がストリームに書き込まれます。このメソッドは、直列化可能なクラスの writeObject メソッド内からしか呼び出せません。また、このメソッドは、1 回しか呼び出すことができず、defaultWriteObject がすでに呼び出されている場合は、呼び出せません。writeFields が呼び出されたあとでのみ、ほかのデータをストリームへ書き込むことが可能になります。

reset メソッドは、ストリーム状態を、構築されたばかりの状態にリセットします。reset によって、ストリームにすでに書き込まれたオブジェクトの状態は破棄されます。ストリームの現在のポイントがリセットポイントとされるので、対応する ObjectInputStream が同じポイントでリセットされます。ストリームに前に書き込まれたオブジェクトは、そのストリームにすでに書き込まれているものとはみなされません。それらのオブジェクトは、ストリームに再び書き込まれます。このことは、1 つまたは複数のオブジェクトの内容を再び送る必要がある場合には便利です。オブジェクトが直列化されている間は、reset を呼び出すことはできません。誤った呼び出しを行うと、IOException がスローされます。

annotateClass メソッドは、Class が直列化されている間と、クラス記述子がストリームに書き込まれたあとに呼び出されます。サブクラスによってこのメソッドを拡張し、そのクラスに関する他の情報をストリームに書き込むことができます。この情報は、対応する ObjectInputStream サブクラスの resolveClass メソッドで読み込まなければなりません。

ObjectOutputStream サブクラスが replaceObject メソッドを実装すると、直列化の際にオブジェクトを監視または置換できます。オブジェクトの置換は、置き換える最初のオブジェクトで writeObject を呼び出す前に、enableReplaceObject を明示的に呼び出すことによってオンにされなければなりません。オブジェクトの置換がオンになると、各オブジェクトに対して、それが初めて直列化される直前に replaceObject が呼び出されます。replaceObject メソッドは、特別に処理されるクラスである Class および ObjectStreamClass に対しては呼び出されません。サブクラスの実装によっては、元のオブジェクトの代わりに、直列化される置換オブジェクトが返されることがあります。この置換オブジェクトは直列化可能でなければなりません。ストリームにおける元のオブジェクトへのすべての参照は、この置換オブジェクトによって置き換えられます。

このサブクラスでは、置換される際、オブジェクトは参照が格納されるすべてのフィールドと互換性がなければなりません。または、直列化復元で補足的な置換が行われなければなりません。オブジェクトは、そのタイプがフィールドまたは配列要素の型のサブクラスでないと、あとで、ClassCastException が発生されることによって直列化復元を中止します。参照は格納されません。

enableReplaceObject メソッドは ObjectOutputStream の信頼できるサブクラスによって呼び出されるもので、これにより直列化の際に、あるオブジェクトで別のオブジェクトを置き換えることが可能になります。オブジェクトの置換は、enableReplaceObjecttrue 値で呼び出されるまで使用できません。オブジェクトの置換は、そのあと、この値を false に設定すれば使用不能になります。前の設定が返されます。enableReplaceObject メソッドは、置換を要求しているそのストリームが信頼できるかどうかを調べます。オブジェクトの private 状態が意図せずに壊される危険のないように、信頼できるストリームサブクラスしか replaceObject を使用することはできません。信頼できるクラスとは、直列化可能な置換を有効にすることを認められたセキュリティ保護ドメインに属するクラスのことです。

ObjectOutputStream がシステムドメインの一部でないとみなされる場合は、セキュリティポリシーファイルに SerializablePermission "enableSubstitution" を追加する必要があります。ObjectInputStream のサブクラスの保護ドメインに、enableReplaceObject の呼び出しによる "enableSubstitution" の権限がない場合は、AccessControlException がスローされます。セキュリティモデルの詳細は、JavaTM セキュリティアーキテクチャ (JDK 1.2) のドキュメントを参照してください。

writeStreamHeader メソッドは、マジック番号とバージョンをストリームに書き込みます。この情報は、ObjectInputStreamreadStreamHeader メソッドで読み込まなければなりません。サブクラスは、ストリームの固有形式を識別するためにこのメソッドを実装しなければならない場合があります。

flush メソッドは、ストリームによって保持されているバッファを空にし、このフラッシュを基本ストリームに転送するために使用します。基本のストリームをフラッシュせずに ObjectOutputStream のバッファだけを空にする場合は、サブクラスによって drain メソッドを使用することができます。

プリミティブ型に対するすべての write メソッドは、DataOutputStream を使ってそれらを標準ストリーム形式に置くことによって、それらの値をコード化します。それらのバイトはブロックデータレコードにバッファリングされるので、オブジェクトのコード化とは区別できます。このバッファリングによって、プリミティブデータは、クラスのバージョン管理のために必要ならスキップされます。さらに、このバッファリングによって、ストリームは、クラス固有のメソッドを呼び出すことなく解析されます。

直列化の実装をオーバーライドするには、ObjectOutputStream のサブクラスは、保護された引数なしの ObjectOutputStream コンストラクタを呼び出す必要があります。SerializablePermission "enableSubclassImplementation" の引数なしのコンストラクタ内にはセキュリティチェックがあり、信頼できるクラスだけにデフォルトの実装のオーバーライドを許可することを保証します。このコンストラクタは、ObjectOutputStream に private なデータを割り当てません。このコンストラクタはまた、ファイナルの writeObject メソッドが writeObjectOverride メソッドを呼び出してから復帰することを示すフラグを設定します。ほかのすべての ObjectOutputStream メソッドはファイナルではないので、サブクラスによって直接オーバーライドされます。



目次 | 前の項目 | 次の項目
Copyright © 1997-1998 Sun Microsystems, Inc. All Rights Reserved.