- ObjectOutputStreamクラス
- ObjectOutputStream.PutFieldクラス
- writeObjectメソッド
- writeExternalメソッド
- writeReplaceメソッド
- useProtocolVersionメソッド
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 writeUnshared(Object obj)
throws IOException;
public void defaultWriteObject()
throws IOException, NotActiveException;
public PutField putFields()
throws IOException;
public void writeFields()
throws IOException;
public void reset() throws IOException;
protected void annotateClass(Class<?> cl) throws IOException;
protected void annotateProxyClass(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.
public abstract static class PutField
{
public void put(String name, boolean value)
throws IllegalArgumentException;
public void put(String name, char data)
throws IllegalArgumentException;
public void put(String name, byte data)
throws IllegalArgumentException;
public void put(String name, short data)
throws IllegalArgumentException;
public void put(String name, int data)
throws IllegalArgumentException;
public void put(String name, long data)
throws IllegalArgumentException;
public void put(String name, float data)
throws IllegalArgumentException;
public void put(String name, double data)
throws IllegalArgumentException;
public void put(String name, Object data)
throws IllegalArgumentException;
}
public void useProtocolVersion(int version) throws IOException;
protected ObjectOutputStream()
throws IOException;
protected writeObjectOverride()
throws NotActiveException, IOException;
}
単一引数のObjectOutputStream
コンストラクタは、指定されたOutputStream
にオブジェクトを直列化するObjectOutputStream
を作成します。 このコンストラクタは、writeStreamHeader
を呼び出して、マジック番号とバージョンをストリームに書き込みます。このストリームは、単一引数のObjectInputStream
コンストラクタの対応するreadStreamHeader
呼出しによって読み取られ、検査されます。 セキュリティ・マネージャがインストールされている場合、このコンストラクタは、"enableSubclassImplementation"
SerializablePermission
がputFields
メソッドまたはwriteUnshared
メソッド、あるいはその両方をオーバーライドするサブクラスのコンストラクタによって直接または間接に呼び出されたときに、これをチェックします。
writeObject
メソッドは、オブジェクトをストリームに直列化するために使用します。 オブジェクトは、次のように直列化されます。
サブクラスが実装をオーバーライドする場合は、
writeObjectOverride
メソッドを呼び出してから、復帰します。 実装のオーバーライドは、このセクションの最後で説明します。ブロック・データ・バッファにデータがあれば、それがストリームに書き込まれ、バッファがリセットされます。
オブジェクトがnullであれば、nullがストリームに置かれ、
writeObject
は復帰します。ステップ8で説明されているように、オブジェクトが以前に置き換えられていれば、置換えのハンドルをストリームに書き込み、
writeObject
は復帰します。オブジェクトがストリームにすでに書き込まれていれば、そのハンドルがストリームに書き込まれ、
writeObject
は復帰します。オブジェクトが
Class
であれば、対応するObjectStreamClass
がストリームに書き込まれ、そのクラスのハンドルが割り当てられ、writeObject
は復帰します。オブジェクトが
ObjectStreamClass
の場合、オブジェクトにハンドルが割り当てられ、その後、「セクション4.3、"直列化されたフォーム"」で説明されているクラス記述子形式の1つを使用してストリームに書き込まれます。 Version 1.3以降のJava 2 SDK, Standard Editionでは、writeClassDescriptor
メソッドがObjectStreamClass
(ダイナミック・プロキシ・クラス以外のクラスを表す場合。関連付けられたClass
オブジェクトをjava.lang.reflect.Proxy
のisProxyClass
メソッドに渡すことによって判別される)を出力するために呼び出されます。 その後、表されるクラスの注釈が書き込まれます。クラスがダイナミック・プロキシ・クラスであれば、annotateProxyClass
メソッドが呼び出され、そうでない場合はannotateClass
メソッドが呼び出されます。writeObject
メソッドが戻ります。オブジェクトのクラスまたは
ObjectInputStream
のサブクラス(あるいはその両方)による潜在的な置換を処理します。オブジェクトのクラスがenum型でなく、また適切な
writeReplace
メソッドを定義する場合は、そのメソッドが呼び出されます。 置換オブジェクトを戻して直列化することもできます。enableReplaceObject
メソッドの呼出しによりreplaceObject
メソッドが有効に設定されている場合、このメソッドを呼び出すことにより、直列化中のオブジェクトをObjectOutputStream
のサブクラスで置換できます。 前のステップで元のオブジェクトを置き換えた場合は、置換オブジェクトでreplaceObject
メソッドが呼び出されます。
上記の一方または両方のステップで元のオブジェクトを置き換えた場合、元のオブジェクトから置換オブジェクトへのマッピングが(ステップ4で利用するために)記録されます。 その後、新規オブジェクトに対し、ステップ3から7が繰り返されます。
置換オブジェクトが、ステップ3から7を適用できない型の場合、ステップ10で置換オブジェクトを使った処理が再開されます。
オブジェクトが
java.lang.String,
の場合、文字列は長さの情報として書き込まれ、その情報のあとにModified UTF-8でエンコードされた文字列の内容が続きます。 詳細は、「セクション6.2、"ストリーム要素"」を参照してください。 ハンドルが文字列に割り当てられ、writeObject
が戻ります。オブジェクトが配列の場合、
writeObject
が再帰的に呼び出されて、配列のObjectStreamClass
が書き込まれます。 配列用のハンドルが割り当てられます。 そのあとに配列の長さが続きます。 その後、配列の各要素がストリームに書き込まれて、writeObject
が戻ります。オブジェクトがenum定数であれば、
writeObject
を再帰的に呼び出すことによって、enum型の定数のObjectStreamClass
が書き込まれます。 ストリーム内では、はじめて参照されるときのみ出現します。 enum定数のハンドルが割り当てられます。 次に、ステップ9で説明したように、enum定数のname
メソッドで返された値がString
オブジェクトとして書き込まれます。 ストリーム内にすでに同じ名前の文字列が出現した場合には、それへの逆参照が書き込まれます。writeObject
メソッドが戻ります。オブジェクトがレコード・オブジェクトの場合、レコード・オブジェクトのクラスの
ObjectStreamClass
は、writeObject
を再帰的に呼び出すことによって記述されます。 ストリーム内では、はじめて参照されるときのみ出現します。 レコード・オブジェクトのハンドルが割り当てられます。レコード・オブジェクトのコンポーネントがストリームに書き込まれます。
a. If the record object is serializable or externalizable, the record components are written, as if by invoking the `defaultWriteObject` method. b. If the object is neither serializable or externalizable, the `NotSerializableException` is thrown.
writeObject
メソッドが戻ります。正規オブジェクトの場合、
writeObject
を再帰的に呼び出すことによって、オブジェクトのクラスのObjectStreamClass
が書き込まれます。 ストリーム内では、はじめて参照されるときのみ出現します。 このオブジェクト用のハンドルが割り当てられます。オブジェクトの内容が、ストリームに書き込まれます。
a. If the object is serializable, the highest serializable class is located. For that class, and each derived class, that class's fields are written. If the class does not have a `writeObject` method, the `defaultWriteObject` method is called to write the serializable fields to the stream. If the class does have a `writeObject` method, it is called. It may call `defaultWriteObject` or `putFields` and `writeFields` to save the state of the object, and then it can write other information to the stream. b. If the object is externalizable, the `writeExternal` method of the object is called. c. If the object is neither serializable or externalizable, the `NotSerializableException` is thrown.
例外は、トラバーサル中に発生する場合も、基になるストリーム内で発生する場合もあります。 IOException
のサブクラスの場合、例外プロトコルを使って例外がストリームに書き込まれ、ストリーム状態が破棄されます。 最初の例外をストリームに書き込んでいる間に2番目のIOException
がスローされた場合、ストリームは不明状態のままになり、writeObject
からStreamCorruptedException
がスローされます。 その他の例外の場合、ストリームは中止され、不明で使用不能な状態のままになります。
writeUnshared
メソッドは、「非共有」オブジェクトをObjectOutputStream
に書き込みます。 このメソッドはwriteObject
と同様ですが、指定されたオブジェクトを常にストリーム内で一意な新しいオブジェクトとして書き込みます(以前に直列化されたインスタンスを指す逆参照としてではなく)。 具体的には、次のようになります。
writeUnshared
を使用して書き込まれたオブジェクトは、そのオブジェクトが以前に書き込まれているかどうかにかかわらず、常に新しく出現するオブジェクト(ストリームにまだ書き込まれたことがないオブジェクト)として同じ方法で直列化されます。writeUnshared
によって以前に書き込まれたオブジェクトを書き込む際にwriteObject
を使用すると、以前のwriteUnshared
操作は、別のオブジェクトの書き込みとして扱われます。 つまり、ObjectOutputStream
は、writeUnshared
呼出しによって書き込まれたオブジェクト・データへの逆参照を生成しません。
writeUnshared
を介してオブジェクトを記述するのは、オブジェクトを直列化復元する際にオブジェクトへの一意の参照を保証するものではありません。ストリーム内で複数のオブジェクトを定義することができるので、レシーバによるObjectInputStream.readUnshared
メソッド(「セクション3.1、"ObjectInputStreamクラス"」を参照してください)は競合しません。 ここで説明した規則は、writeUnshared
によって書き込まれた基本レベルのオブジェクトだけに適用され、直列化されるオブジェクト・グラフ内で推移的に参照されるサブオブジェクトには適用されません。
defaultWriteObject
メソッドは、現在のクラスに対するデフォルト直列化メカニズムを実装します。 このメソッドの呼出しは、クラスのwriteObject
メソッドからのみ可能です。 このメソッドは、現在のクラスのすべての直列化可能フィールドをストリームに書き込みます。 writeObject
メソッドの外部からこのメソッドが呼び出されると、NotActiveException
がスローされます。
putFields
メソッドは、ストリーム内の直列化可能フィールドの値を設定する際に呼出し側が使用するPutField
オブジェクトを返します。 フィールドは、任意の順序で設定できます。 すべてのフィールドの設定が完了したら、writeFields
を呼び出して、フィールド値を正規の順序でストリームに書き込む必要があります。 フィールドが設定されていない場合、その型に適したデフォルト値がストリームに書き込まれます。 このメソッドは、直列化可能クラスのwriteObject
メソッド内からしか呼び出すことができません。 また、このメソッドは、1回しか呼び出すことができず、defaultWriteObject
がすでに呼び出されている場合は呼び出せません。 writeFields
を呼び出したあとでないと、ほかのデータをストリームに書き込むことはできません。
reset
メソッドは、ストリーム状態をリセットして、構築時の状態に戻します。 Reset
は、すでにストリームに書き込まれたオブジェクトの状態を破棄します。 ストリーム内の現在位置にリセットのマークが付けられるので、対応するObjectInputStream
も同じ位置でリセットされます。 以前にストリームに書き込まれたオブジェクトが、ストリームに書込み済みのオブジェクトとして記憶されることはありません。 これらのオブジェクトは、ストリームに再度書き込まれます。 これは、オブジェクトの内容やオブジェクトを再送信しなければいけない場合に有用です。 Reset
は、オブジェクトの直列化中は呼び出されない場合もあります。 不正に呼び出されると、IOException
がスローされます。
Java 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
メソッドは、特別に処理されるクラスであるClass
およびObjectStreamClass
のオブジェクトに対しては呼び出されません。 サブクラスの実装が、元のオブジェクトではなく直列化される代替オブジェクトを返す場合があります。 代替オブジェクトは、直列化可能でなければいけません。 ストリームにおける元のオブジェクトへのすべての参照は、置換オブジェクトによって置き換えられます。
サブクラスはオブジェクトが置換されているときに、置換されるオブジェクトが参照を保存するすべてのフィールドと互換性が持つこと、つまり直列化復元時に補完的な置換が行われることを保証する必要があります。 型がフィールドまたは配列要素の型のサブクラスでないオブジェクトは、あとでClassCastException
をスローして直列化復元を中止することになり、参照は保存されません。
enableReplaceObject
メソッドは、直列化の際にあるオブジェクトを別のオブジェクトで置換するために、ObjectOutputStream
の信頼できるサブクラスで呼び出すことができます。 オブジェクトの置換は、enableReplaceObject
がtrue
値で呼び出されるまでは、無効になっています。 それ以降は、false
に設定することで無効にできます。 前の設定が返されます。 enableReplaceObject
メソッドは、置換を要求するストリームを信頼できるかどうかを調べます。 オブジェクトのprivate状態が意図せずに公開されないことを保証するために、信頼できるストリーム・サブクラスだけがreplaceObject
を使用できます。 信頼されるクラスとは、Serializable置換を有効にする権限を保持する、セキュリティ保護ドメインに属するクラスのことです。
ObjectOutputStream
のサブクラスがシステム・ドメインの一部とはみなされない場合、SerializablePermission "enableSubstitution"
をセキュリティ・ポリシー・ファイルに追加する必要があります。 ObjectInputStream
のサブクラスの保護ドメインに、enableReplaceObject
呼出しによる"enableSubstitution"
の権限がない場合は、AccessControlException
がスローされます。 セキュリティ・モデルの詳細は、Javaセキュリティ・アーキテクチャ(JDK1.2)のドキュメントを参照してください。
writeStreamHeader
メソッドは、マジック番号とバージョンをストリームに書き込みます。 この情報は、ObjectInputStream
のreadStreamHeader
メソッドを使って読み取る必要があります。 ストリームの一意形式を識別するために、サブクラスがこのメソッドを実装することが必要な場合があります。
flush
メソッドは、ストリームが保持するバッファを空にして基になるストリームにフラッシュを転送するために、使用されます。 基になるストリームのフラッシュを強制せずにObjectOutputStream
のバッファだけを空にするために、サブクラスからdrain
メソッドを使用できます。
プリミティブ型用のすべてのwriteメソッドは、DataOutputStream
を使って値をエンコードして、標準ストリーム形式にします。 バイトがブロック・データ・レコードにバッファリングされることにより、オブジェクトのエンコーディングとの区別が可能になります。 このバッファリングにより、クラスのバージョン管理が必要な場合、プリミティブ・データのスキップも可能になります。 また、クラス固有のメソッドを呼び出すことなく、ストリームの構文解析を行うことも可能になります。
直列化の実装をオーバーライドするときは、ObjectOutputStream
のサブクラスは引数なしのprotected ObjectOutputStream
コンストラクタを呼び出すことをお勧めします。 SerializablePermission "enableSubclassImplementation"
用の引数なしコンストラクタ内では、信頼できるクラスだけがデフォルト実装のオーバーライドを許可されるようにセキュリティ・チェックがあります。 このコンストラクタは、ObjectOutputStream
にprivateなデータを割り当てず、final writeObject
メソッドがwriteObjectOverride
メソッドを呼び出してから復帰するべきことを示すフラグを設定します。 ほかのすべてのObjectOutputStream
メソッドは、finalではないので、サブクラスによって直接オーバーライドできます。
2.2 ObjectOutputStream.PutFieldクラス
クラスPutField
は、あるクラスがデフォルト直列化を使わない場合に、そのクラスの直列化可能フィールドの値を設定するためのAPIを提供します。 各メソッドは、指定された名前付き値をストリームに置きます。 name
が、フィールドが書き込まれているクラスの直列化可能フィールドの名前と一致しない場合、または指定されたフィールドの型が、呼び出された特定のput
メソッドの2番目のパラメータの型と一致しない場合、IllegalArgumentException
がスローされます。
2.3 writeObjectメソッド
直列化可能オブジェクトの場合、writeObject
メソッドによって、クラスは独自のフィールドの直列化を制御できます。 そのシグニチャを次に示します。
private void writeObject(ObjectOutputStream stream)
throws IOException;
直列化可能オブジェクトの各サブクラスは、独自のwriteObject
メソッドを定義できます。 クラスがメソッドを実装しない場合は、defaultWriteObject
によって与えられるデフォルト直列化が使用されます。 実装されている場合、クラスには、そのスーパー・タイプやサブタイプのフィールドではなく、独自のフィールドを書き込む責任だけがあります。
クラスのwriteObject
メソッドには、実装されている場合、クラスの状態を保存する責任があります。 ObjectOutputStream
のdefaultWriteObject
メソッドまたはwriteFields
メソッドを一度(一度のみ)呼び出してからでないと、対応するreadObject
メソッドがオブジェクトの状態を復元するために必要なオプション・データを書き込むことはできません。オプション・データを書き込まない場合でも、defaultWriteObject
またはwriteFields
を一度呼び出す必要があります。 オプション・データ(ある場合)の書込みの前にdefaultWriteObject
かwriteFields
が呼び出されなければ、ObjectInputStream
がそのwriteObject
メソッドを定義したクラスを解決できない場合に、インスタンス直列化復元の動作は未定義になります。
オプション・データの形式、構造体、バージョン管理の責任は、完全にクラスにあります。
2.4 writeExternalメソッド
java.io.Externalizable
を実装するオブジェクトは、writeExternal
メソッドを実装して、オブジェクトの状態全体を保存する必要があります。 このオブジェクトは、そのスーパー・クラスと協調して、それらの状態を保管しなければいけません。 ObjectOutput
のすべてのメソッドを、オブジェクトのプリミティブ型フィールドとオブジェクト・フィールドを保存するために使用できます。
public void writeExternal(ObjectOutput stream)
throws IOException;
JDK 1.2で、Externalizableデータを書き込むための新しいデフォルト形式が導入されました。 新しい形式は、プリミティブ・データがwriteExternal
メソッドによってブロック・データ・モードで書き込まれるように指定します。 さらに、writeExternal
メソッドから戻ったあとに、外部オブジェクトの末尾を示すタグがストリームに付加されます。 このフォーマット変更の利点については、「セクション3.6、"readExternalメソッド"」で説明しています。 この変更によって生じる互換性の問題については、「セクション2.6、"useProtocolVersionメソッド"」で説明しています。
2.5 writeReplaceメソッド
SerializableおよびExternalizableクラスの場合には、writeReplace
メソッドは、オブジェクトが書き込まれる前に、オブジェクトのクラスがストリーム内で独自の置換を指定することを許可します。 writeReplace
メソッドを実装することにより、クラスは、直列化されている独自のインスタンスの型およびインスタンスを直接制御できます。
このメソッドは、次のように定義します。
ANY-ACCESS-MODIFIER Object writeReplace()
throws ObjectStreamException;
ObjectOutputStream
がストリームにオブジェクトを書き込む準備をしているとき、writeReplace
メソッドが呼び出されます。 ObjectOutputStream
は、クラスがwriteReplace
メソッドを定義しているかどうかをチェックします。 このメソッドが定義されている場合は、オブジェクトがストリーム内で置換を指定することを許可するためにwriteReplace
メソッドが呼び出されます。 返されるオブジェクトは、渡されるオブジェクトと同じ型であるか、または読み込まれて解釈されたオブジェクトが、オブジェクトへのすべての参照と互換性を持つ型のオブジェクトであるべきです。 そうでない場合、型の不一致が検出されたときに、ClassCastException
が発生します。
2.6 useProtocolVersionメソッド
下位互換性がなかったストリーム・プロトコルの変更によって、現在の仮想マシンが以前のリリースが読取り可能な直列化ストリームを書き込めるメカニズムが追加されました。 ただし、下位互換性のあるプロトコルを使う場合は、新しいストリーム形式では修正されている問題が発生します。
ストリーム・プロトコルのバージョンについては、「セクション6.3、"ストリーム・プロトコル・バージョン"」で説明しています。