目次 | 前の項目 | 次の項目 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 void writeClassDescriptor(ObjectStreamClass desc)
        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 で置換オブジェクトを使った処理が再開されます。

  1. オブジェクトが java.lang.String の場合、文字列は UTF (Universal Transfer Format) 形式、また長い文字列は UTF の異形式 (詳細は 「6.2 ストリーム要素」を参照) で書き込まれます。ハンドルが文字列に割り当てられ、writeObject が返されます。
  2. オブジェクトが配列の場合、writeObject が再帰的に呼び出されて、配列の ObjectStreamClass が書き込まれます。配列用のハンドルが割り当てられます。その直後に、配列の長さの分だけ続きます。 その後、配列の各要素がストリームに書き込まれて、writeObject が返されます。
  3. 正規オブジェクトの場合、writeObject を再帰的に呼び出すことにより、オブジェクトのクラスの ObjectStreamClass が書き込まれます。この、ストリームへの書き込みは、オブジェクトの最初の参照時だけです。このオブ ジェクト用のハンドルが割り当てられます。JavaTM 2 SDK, Standard Edition, v1.3 から、writeObjectwriteClassDescriptor を呼び出して ObjectStreamClass オブジェクトを出力するようになりました。
  4. オブジェクトの内容が、ストリームに書き込まれます。
    1. 直列化可能オブジェクトの場合、最上位の直列化可能クラスが配置されます。そのクラス、およびそのク ラスから派生したクラスごとに、クラスのフィールドが書き込まれます。クラスが writeObject メソッドを保持しない場合、defaultWriteObject メソッドが呼び出されて、直列化可能フィールドのストリームへの書き込みが行われます。クラスが writeObject メソッドを保持する場合、このメソッドが呼び出されます。defaultWriteObjectputFields のどちらか、および writeFields を呼び出してオブジェクトの状態を保存し、その後、他の情報をストリームに書き込むことができます。
    2. オブジェクトが外部化可能な場合、オブジェクトの writeExternal メソッドが呼び出されます。
    3. オブジェクトが直列化可能でも、外部化可能でもない場合、NotSerializableException がスローされます。
例外は、トラバーサル中に発生する場合も、基礎ストリーム内で発生する場合もあります。IOExce ption のすべてのサブクラスで、例外プロトコルを使って例外がストリームに書き込まれ、ストリーム状態が破 棄されます。最初の例外をストリームに書き込んでいる間に 2 番目の IOException がスローされると、ストリームの状態は不明のままで、writeObject から StreamCorruptedException がスローされます。その他の例外の場合、ストリームは中止され、不明で使用不能な状態のままになりま す。

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

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

reset メソッドは、ストリーム状態を再設定して、構成時の状態に戻します。Reset により、それまでストリームに書き込まれたすべてのオブジェクト状態は破棄されます。ストリーム内の 現在位置に再設定のマークが付けられるため、対応する ObjectInputStream も同じ位置で再設定されます。以前にストリームに書き込まれたオブジェクトが、ストリームに書き込み 済みのオブジェクトとして記憶されることはありません。これらのオブジェクトは、ストリームに再度書 き込まれます。これは、オブジェクトの内容やオブジェクトを再送信しなければならない場合に有用です 。オブジェクトの直列化時に Reset が呼び出されない場合もあります。不正な仕方で呼び出されると、IOException がスローされます。

JavaTM 2 SDK, Standard Edition, v1.3 から、ObjectStreamClass の直列化が必要になると、writeClassDescriptor が呼び出されるようになりました。writeClassDescriptor は、ObjectStreamClass 表現の直列化ストリームへの書き込みを担当します。サブクラスでこのメソッドをオーバーライドするこ とにより、クラス記述子の直列化ストリームへの書き込み方法をカスタマイズできます。このメソッドを オーバーライドする場合は、ObjectInputStream 内の対応する readClassDescriptor メソッドもオーバーライドして、カスタムストリーム表現からクラス記述子を再構成する必要があります 。デフォルトでは、writeClassDescriptor は、「6.4 ストリーム形式の文法」で指定された形式に従ってクラス記述子を書き込みます。このメソッドは、 ObjectOutputStream が以前の直列化ストリーム形式を使用していない場合にのみ、呼び出し可能である点に留意してください (「6.3 ストリームプロトコルのバージョン」を参照)。直列化ストリームに以前の形式 (ObjectStreamConstants.PROTOCOL_VERSION_1) が使用されている場合、クラス記述子はオーバーライドまたはカスタマイズ不可能な方法で内部に書き込 まれます。

Class の直列化中、かつクラス記述子のストリームへの書き込み後に、annotateClass メソッドが呼び出されます。サブクラスがこのメソッドを継承して、クラスに関する他の情報をストリー ムに書き込むことも可能です。この情報の読み取りは、対応する ObjectInputStream サブクラスの resolveClass メソッドを使って実行する必要があります。

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

オブジェクトの置換中に、サブクラスは、代替オブジェクトと参照の格納される全フィールドとの互換性 が保たれていること、または直列化復元時に相補置換が行われることを保証する必要があります。オブジ ェクトのタイプがフィールドまたは配列要素のタイプのサブクラスではない場合、そのオブジェクトは、 ClassCastException をスローすることにより直列化復元を中止します。参照は格納されません。

enableReplaceObject メソッドは、信頼できる ObjectOutputStream のサブクラスが、直列化の際に、あるオブジェクトで別のオブジェクトを代用することを可能にするため に、呼び出します。オブジェクトの置換は、enableReplaceObjecttrue 値で呼び出されるまでは、使用不可になっています。また、使用可能にしたあとで、false に設定して、使用不可にされる場合があります。前の設定が返されます。enableReplaceObject は、置換を要求するストリームを信頼できるかどうかを調べます。オブジェクトの private 状態が意図せずに公開されないことを保証するために、信頼できるストリームサブクラスだけが replaceObject を使用することを許可されます。信頼されるクラスは、Serializable 置換を有効にする権限を保持する、セキュリティ保護ドメインに属するクラスです。

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

writeStreamHeader メソッドは、マジック番号とバージョンをストリームに書き込みます。この情報は、ObjectInputS treamreadStreamHeader メソッドを使って読み取る必要があります。ストリームの一意な形式を識別するために、サブクラスがこ のメソッドを実装することが必要な場合があります。

flush メソッドを使用して、ストリームが保持するバッファを空にして、基礎ストリームにフラッシュを転送し ます。基礎ストリームのフラッシュを強制せずに ObjectOutputStream のバッファだけを空にする場合、サブクラスから drain メソッドを使用できます。

プリミティブ型の書き込みメソッドはすべて、DataOutputStream を使って値を符号化して、標準ストリーム形式にします。バイトがブロックデータレコードにバッファリ ングされることにより、オブジェクトのエンコーディングとの区別が可能になります。このバッファリン グにより、クラスのバージョン管理が必要な場合、プリミティブデータのスキップも可能になります。ま た、クラス固有のメソッドを呼び出すことなく、ストリームの構文解析を行うことも可能になります。

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



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