目次 | 前の項目 | 次の項目 | Java オブジェクト直列化仕様 バージョン 5.0 |
クラス ObjectInputStream
は、オブジェクトの直列化復元を実装するためのものです。このクラスは、すでに直列化復元されたオブジェクトセットなどのストリームの状態を管理します。このクラスのメソッドを使えば、ObjectOutputStream
によって書き込まれたストリームから、プリミティブ型やオブジェクトを読み込むことができます。このクラスは、それが参照するオブジェクトをストリームからの復元を管理します。
package java.io; public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants { public ObjectInputStream(InputStream in) throws StreamCorruptedException, IOException; public final Object readObject() throws OptionalDataException, ClassNotFoundException, IOException; public Object readUnshared() throws OptionalDataException, ClassNotFoundException, IOException; public void defaultReadObject() throws IOException, ClassNotFoundException, NotActiveException; public GetField readFields() throws IOException; public synchronized void registerValidation( ObjectInputValidation obj, int prio) throws NotActiveException, InvalidObjectException; protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException; protected Class resolveClass(ObjectStreamClass v) throws IOException, ClassNotFoundException; protected Object resolveObject(Object obj) throws IOException; protected boolean enableResolveObject(boolean enable) throws SecurityException; protected void readStreamHeader() throws IOException, StreamCorruptedException; public int read() throws IOException; public int read(byte[] data, int offset, int length) throws IOException public int available() throws IOException; public void close() throws IOException; public boolean readBoolean() throws IOException; public byte readByte() throws IOException; public int readUnsignedByte() throws IOException; public short readShort() throws IOException; public int readUnsignedShort() throws IOException; public char readChar() throws IOException; public int readInt() throws IOException; public long readLong() throws IOException; public float readFloat() throws IOException; public double readDouble() throws IOException; public void readFully(byte[] data) throws IOException; public void readFully(byte[] data, int offset, int size) throws IOException; public int skipBytes(int len) throws IOException; public String readLine() throws IOException; public String readUTF() throws IOException; // Class to provide access to serializable fields. static abstract public class GetField { public ObjectStreamClass getObjectStreamClass(); public boolean defaulted(String name) throws IOException, IllegalArgumentException; public char get(String name, char default) throws IOException, IllegalArgumentException; public boolean get(String name, boolean default) throws IOException, IllegalArgumentException; public byte get(String name, byte default) throws IOException, IllegalArgumentException; public short get(String name, short default) throws IOException, IllegalArgumentException; public int get(String name, int default) throws IOException, IllegalArgumentException; public long get(String name, long default) throws IOException, IllegalArgumentException; public float get(String name, float default) throws IOException, IllegalArgumentException; public double get(String name, double default) throws IOException, IllegalArgumentException; public Object get(String name, Object default) throws IOException, IllegalArgumentException; } protected ObjectInputStream() throws StreamCorruptedException, IOException; protected readObjectOverride() throws OptionalDataException, ClassNotFoundException, IOException; }
単一引数の ObjectInputStream
コンストラクタには InputStream
が必要です。このコンストラクタは、readStreamHeader
を呼び出して読み込み、対応する ObjectOutputStream.writeStreamHeader
メソッドによって書き込まれたヘッダとバージョンを検査します。セキュリティマネージャがインストールされている場合、このコンストラクタは、readFields
メソッドまたは readUnshared
メソッド、あるいはその両方をオーバーライドするサブクラスのコンストラクタによって直接または間接的に呼び出されたときに、"enableSubclassImplementation"
SerializablePermission
のチェックを行います。
ObjectInputStream
コンストラクタは、直列化ストリームヘッダの読み込みが完了するまでブロックされます。コードが ObjectInputStream
の構築を待機しているときに、直列化ストリームに対して対応する ObjectOutputStream
が作成されていない場合は、デッドロックが発生します。ObjectInputStream
コンストラクタは、ヘッダがそのストリームに書き込まれるまでブロックされ、ヘッダは ObjectOutputStream
コンストラクタが実行されるまでストリームに書き込まれないためです。この問題は、ObjectInputStream
が構築される前に ObjectOutputStream
を作成するか、ObjectInputStream
の構築の完了および ObjectOutputStream
の作成の間のタイミング依存関係を解除すると解決できます。
ストリームからオブジェクトを直列化復元するには、readObject
メソッドを使用します。このメソッドは、このストリームを読んで、オブジェクトを再構築します。
1.ObjectInputStream
サブクラスが実装をオーバーライドしている場合は、readObjectOverride
メソッドを呼び出し、戻します。実装し直す方法については、この節の最後で説明します。
2. ブロックデータレコードがストリームにあると、BlockDataException
をスローし、使用可能なバイト数を知らせます。
3. ストリームのオブジェクトが null であれば、null を返します。
4. ストリームのオブジェクトが前のオブジェクトに対するハンドルであれば、そのオブジェクトを返します。
5. ストリームのオブジェクトがClass
であれば、そのObjectStreamClass
記述子を読み、それとそのハンドルを、認識されているオブジェクトセットに追加し、対応するClass
オブジェクトを返します。
6. ストリームのオブジェクトがObjectStreamClass
であれば、4.3 節で説明する書式に従ってそのデータを読みます。そのオブジェクトとそのハンドルを、認識されているオブジェクトセットに追加します。バージョン 1.3 以降の Java TM 2 SDK, Standard Edition では、ObjectStreamClass
がストリームデータで示されたダイナミックプロキシクラス以外のクラスを表す場合、readClassDescriptor
メソッドが呼び出されてそのクラスを読み込みます。クラス記述子がダイナミックプロキシクラスを表すならば、ストリーム上でresolveProxyClass
メソッドを呼び出し、その記述子のローカルクラスを取得します。そうでない場合は、ストリーム上でresolveClass
メソッドを呼び出し、ローカルクラスを取得します。クラスが解決できない場合は、ClassNotFoundException をスローします。取得したObjectStreamClass
オブジェクトを返します。
7. ストリームのオブジェクトがString
の場合、その長さ情報を読み取ります。その長さ情報のあとに、変更後の UTF-8 で符号化された文字列の内容が続きます。詳細は、「6.2 ストリーム要素」を参照してください。String
とそのハンドルを、認識されているオブジェクトセットに追加して、手順 12 に進みます。
8. ストリームのオブジェクトが配列であれば、その ObjectStreamClass
と配列の長さを読みます。その配列を割り当て、そのオブジェクトとそのハンドルを、認識されているオブジェクトセットに追加します。型に適したメソッドを使って各要素を読み込み、配列に割り当てます。手順 12 に進みます。
9. ストリームのオブジェクトが enum 定数であれば、そのObjectStreamClass
と enum 定数名を読みます。ObjectStreamClass
が enum 型以外のクラスを表す場合、InvalidClassException
がスローされます。受け取ったObjectStreamClass
名とともにバインドされた enum 型を引数として渡してjava.lang.Enum.valueOf
メソッドを呼び出し、enum 定数への参照を取得します。valueOf
メソッドでIllegalArgumentException
がスローされる場合は、IllegalArgumentException
が原因としてInvalidObjectException
がスローされます。enum 定数とそのハンドルを、認識されているオブジェクトセットに追加して、手順 12 に進みます。
10. その他のオブジェクトの場合は、そのオブジェクトのObjectStreamClass
がストリームから読み込まれます。そのObjectStreamClass
のローカルクラスが取り出されます。このクラスは、直列化可能か外部化可能でなければなりません。また、enum 型以外でなければなりません。クラスがこの条件を満たさないと、InvalidClassException
がスローされます。
11. そのクラスのインスタンスが割り当てられます。そのインスタンスとそのハンドルが、認識されているオブジェクトセットに追加されます。内容が適切に復元されます。
readObject
メソッドか、これらが定義されていなければ、defaultReadObject
メソッドが呼び出されて、各クラスのフィールドが復元されます。直列化復元時には、直列化可能クラスに対して、フィールドの初期化子およびコンストラクタは実行されません。通常、このストリームを書き込んだクラスのバージョンは、このストリームを読み込むクラスと同じです。この場合、ストリームのオブジェクトのすべてのスーパータイプは、現在ロードされているクラスのスーパータイプと一致します。このストリームを書き込んだクラスのバージョンのスーパータイプが、ロードされているクラスのスーパータイプと異なる場合は、ObjectInputStream
で異なるクラスの状態を復元したり、初期化したりする際、一層の注意が必要です。この場合には、すべてのクラスを調べて、ストリームにあるデータと、復元するオブジェクトのクラスとを比較する必要があります。ストリームにはあるがオブジェクトにはないクラスのデータは破棄されます。オブジェクトにはあるがストリームにはないクラスの場合には、そのクラスのフィールドが、デフォルトの直列化によってデフォルト値に設定されます。readExternal
メソッドが呼び出され、そのオブジェクトの内容が復元されます。12. オブジェクトのクラスまたはObjectInputStream
:
のサブクラスによる潜在的な置換を処理します。
プリミティブ型を読むためのすべてのメソッドは、ストリームのブロックデータレコードからバイトだけを使用します。ストリームの次のアイテムがオブジェクトのときにプリミティブデータの読み込みが行われると、読み込みメソッドは -1 か EOFException
のうちで適切な方を返します。プリミティブ型の値は、DataInputStream
によってブロックデータレコードから読み込まれます。
スローされた例外は、そのトラバースの間に起きたエラーか、基本のストリームで起きた例外を反映したものです。例外がスローされた場合、基礎ストリームは不明で使用不能な状態のままです。
ストリームでリセットトークンが起こると、ストリームのすべての状態は破棄されます。認識されているオブジェクトセットはクリアされます。
ストリームで例外トークンが起こると、その例外が読み込まれ、新しい WriteAbortedException
がスローされます。このとき、停止を引き起こした例外が引数として指定されます。ストリームコンテキストは前に述べたようにリセットされます。
ストリームから非共有オブジェクトを読み込むには、readUnshared
メソッドを使用します。このメソッドは、後続の readObject
および readUnshared
の呼び出しが、元の readUnshared
の呼び出しによって返された直列化復元インスタンスへの追加参照を返すことができない点を除いては、readObject
と同じです。具体的には、次のようになります。
readUnshared
が呼び出された場合は、ObjectStreamException
がスローされる
readUnshared
が正常に返したあとで、readUnshared
によって直列化復元されたストリームハンドルへのバック参照を直列化復元しようとすると、ObjectStreamException
がスローされる
readUnshared
を介してオブジェクトの直列化復元を行うと、返されたオブジェクトに関連付けられたストリームハンドルが無効になります。このこと自体は、readUnshared
によって返された参照が一意であることを常に保証するものではありません。直列化復元されたオブジェクトは、readResolve
メソッドを定義して、ほかの組織が見ることができるオブジェクトを返すことがあります。また、readUnshared
が、ストリーム内のほかの場所や外部機関から取得可能な Class
オブジェクトまたは enum 定数を返すこともあります。ただし、オブジェクトが enum 定数または java.lang.Class
のインスタンスではなく、readResolve
メソッドを定義しない場合は、readUnshared
を使うことで、返されたオブジェクト参照が一意であること、および基になるデータストリームが処理済みであっても、それを作成した ObjectInputStream
から再度取得されないことが保証されます。この保証は、readUnshared
によって返される基本レベルのオブジェクトだけに適用され、返されたオブジェクトのグラフ内で一時的に参照されるサブオブジェクトには一切適用されません。
ストリームからフィールドおよびオブジェクトを読み込むには、defaultReadObject
メソッドを使用します。このメソッドは、ストリームのクラス記述子を使って、名前と型による標準の順序でストリームからそれらのフィールドを読み込みます。それらの値は、名前によって現行クラスの対応するフィールドに代入されます。バージョン管理機構の詳細については、「5.5 互換性のある JavaTM の型展開」を参照してください。ストリーム内にないオブジェクトのフィールドは、そのデフォルト値に設定されます。ストリームにあるがオブジェクトにない値は、破棄されます。このような状態は主に、前のバージョンにはなかったフィールドを、クラスのあとのバージョンに追加で書き込んだ場合に起こります。このメソッドは、クラスのフィールドを復元している間に readObject
メソッドからのみ呼び出すことができます。それ以外のときに呼び出すと、NotActiveException
がスローされます。
readFields
メソッドは、ストリームから直列化可能フィールドの値を読み取り、GetField
クラスを使ってその値を使用できるようにします。readFields
メソッドは、直列化可能クラスの readObject
メソッド内からしか呼び出すことができません。また、このメソッドは、1 回しか呼び出すことができず、defaultReadObject
がすでに呼び出されている場合は呼び出せません。GetFields
オブジェクトは、現在のオブジェクトである ObjectStreamClass
を使ってこのクラス用に取得できるフィールドを確認します。readFields
によって返される GetFields
オブジェクトは、そのクラスの readObject
メソッドへの呼び出しの間だけ有効です。フィールドは、任意の順序で取得できます。追加データの読み込みは、readFields
が呼び出されたあとに、ストリームから直接読み込む場合だけ可能です。
registerValidation
メソッドを呼び出すと、オブジェクトが readObject
の元の呼び出し側に返される前にグラフ全体が復元された場合に、コールバックを要求することができます。有効化コールバックの順序は、優先順次で制御することができます。高い値のコールバックは、低い値のものより前に呼び出されます。有効にされるオブジェクトは、ObjectInputValidation
インタフェースをサポートし、validateObject
メソッドを実装していなければなりません。有効化を登録するのは、クラスの readObject
メソッドを呼び出す間でなければなりません。そうでないと、NotActiveException
がスローされます。registerValidation
に指定されたコールバックオブジェクトが null の場合、InvalidObjectException
がスローされます。
JavaTM SDK, Standard Edition, v1.3 から、すべての ObjectStreamClass
オブジェクトを読み込むときに readClassDescriptor
メソッドが使用されています。直列化ストリーム内で ObjectInputStream
の次の項目がクラス記述子の場合は、readClassDescriptor
が呼び出されます。writeClassDescriptor
メソッドをオーバーライドした ObjectOutputStream
のサブクラスによって非標準形式で記述されたクラス記述子で読み込みを行うためのこのメソッドは、ObjectInputStream
のサブクラスによってオーバーライドされます。デフォルトでは、このメソッドは、「6.4 ストリーム形式の文法」で説明している形式に従ってクラス記述子を読み込みます。
resolveClass
メソッドは、直列化復元されている間と、そのクラス記述子が読み込まれたあとで呼び出されます。サブクラスは、このメソッドを拡張して、ObjectOutputStream
の対応するサブクラスによって書き込まれたクラスの他の情報を読むことができます。このメソッドは、与えられた名前と serialVersionUID
を持つクラスを見つけ、返さなければなりません。デフォルトの実装では、このクラスは、クラスローダを持つ readObject
の最も近い呼び出し側のクラスローダを呼び出すことによって、見つけることができます。このクラスが見つからないと、ClassNotFoundException
がスローされます。JDKTM 1.1.6 より前のバージョンでは、resolveClass
メソッドは、ストリーム内のクラス名と同じ、完全修飾されたクラス名を返す必要がありました。JDKTM 1.1.6 以降のバージョンでは、リリースごとにパッケージの名前を変更できるようにするために、resolveClass
メソッド
は、同じ基底クラス名および SerialVersionUID
を持つクラスを返すことだけが必要です。
resolveObject
メソッドは、直列化復元の際に、あるオブジェクトを別のオブジェクトの代わりにモニターしたり、あるオブジェクトと別のオブジェクトを置換したりするために、信頼できるサブクラスによって使用されます。解釈処理する最初のオブジェクトに対して readObject
を呼び出す前に、enableResolveObject
を呼び出して、オブジェクトの解析処理を明示的に使用可能にしなければなりません。オブジェクトの解析処理を使用可能にすると、それぞれの直列化可能オブジェクトが readObject
から最初に返される直前に、resolveObject
は一度だけ呼び出されます。resolveObject
メソッドは、特別に処理されるクラスである Class
、ObjectStreamClass
、String
、および配列のオブジェクトに対しては呼び出されません。サブクラスの resolveObject
の実装では、オリジナルの代わりに代入されたり返されたりする置換オブジェクトが返される場合があります。返されるオブジェクトは、一貫性があり、元のオブジェクトの参照に必ず代入できる型のものでなければなりません。そうでないと、ClassCastException
がスローされます。すべての代入では型の検査が行われます。ストリームにおける元のオブジェクトへのすべての参照は、置換オブジェクトへの参照によって置き換えられます。
enableResolveObject
メソッドは、直列化復元の際に、あるオブジェクトを別のオブジェクトの代わりにモニターしたり、あるオブジェクトで別のオブジェクトを置換することを可能にするために、ObjectOutputStream
の信頼できるサブクラスによって呼び出されます。オブジェクトの置換は、enableResolveObject
が true 値で呼び出されるまでは、使用不可になっています。また、使用可能にしたあとで、false に設定して、使用不可にされる場合があります。前の設定が返されます。enableResolveObject
メソッドは、直列化の際にストリームが置換を要求する権限があるかどうかを検査します。オブジェクトの private 状態が意図せずに変更されることのないように、信頼できるストリームだけしか resolveObject
を使用することはできません。信頼できるクラスとは、クラスローダが null に等しいか、置換を有効にすることを許可するセキュリティ保護ドメインに属するクラスのことです。
ObjectInputStream
のサブクラスがシステムドメインの一部でないとみなされる場合は、enableResolveObject
を呼び出すための許可を ObjectInputStream
のサブクラスに与える行を、セキュリティポリシーファイルに追加する必要があります。追加する SerializablePermission
は、"enableSubstitution"
です。ObjectStreamClass
のサブクラスの保護ドメインに、enableResolveObject
の呼び出しによる "enableSubstitution"
の権限がない場合は、AccessControlException
がスローされます。セキュリティモデルの詳細は、JavaTM セキュリティアーキテクチャ (JDKTM 1.2) のドキュメントを参照してください。
readStreamHeader
メソッドは、ストリームのマジック番号とバージョンを読み込み、検査します。それらが一致しないと、StreamCorruptedMismatch
がスローされます。
直列化復元の実装をオーバーライドするには、ObjectInputStream
のサブクラスは、保護された引数なしの ObjectInputStream
コンストラクタを呼び出す必要があります。SerializablePermission "enableSubclassImplementation"
の引数なしのコンストラクタ内にはセキュリティチェックがあり、信頼できるクラスだけにデフォルトの実装のオーバーライドを許可します。このコンストラクタは、ObjectInputStream
に private なデータを割り当てず、ファイナルの readObject
メソッドは readObjectOverride
メソッドを呼び出してから復帰することを示すフラグを設定します。ほかのすべての ObjectInputStream
メソッドは、ファイナルではないので、サブクラスによって直接オーバーライドされます。
ObjectInputStream.GetField
は、直列化可能フィールドの値を取得するための API を提供します。ストリームのプロトコルは、defaultReadObject
が使うプロトコルと同じです。readFields
の使用による直列化可能フィールドへのアクセスでは、ストリームの形式は変更されずに、値にアクセスするための代わりの API が提供されるだけです。この API は、クラスの各名前付き直列化可能フィールドに対し、対応する非 transient および非 static フィールドを必要としません。直列化可能フィールドは、serialPersistentFields
を使って宣言されたフィールドであるか、あるいはそのようなフィールドが宣言されていない場合は、オブジェクトの非 transient および非 static フィールドです。ストリームの読み込み時に利用できる直列化可能フィールドは、オブジェクトの直列化時にストリームに書き込まれたフィールドです。ストリームを書き込んだクラスのバージョンが異なる場合は、すべてのフィールドが現在のクラスの直列化可能フィールドに対応するわけではありません。利用可能なフィールドは、GetField
オブジェクトの ObjectStreamClass
から取得できます。
getObjectStreamClass
メソッドは、ストリーム内のクラスを表す ObjectStreamClass
オブジェクトを返します。これには、直列化可能フィールドの一覧が含まれています。
ストリーム内にフィールドが存在しない場合は、defaulted
メソッドが true を返します。要求されたフィールドが現在のクラスの直列化可能フィールドでない場合は、IllegalArgumentException
がスローされます。
各 get
メソッドは、指定された直列化可能フィールドをストリームから返します。基礎ストリームが例外をスローした場合は、入出力例外がスローされます。現在のクラスの直列化可能フィールドの名前および型に、名前または型が一致しない場合は、IllegalArgumentException
がスローされます。ストリームのそのフィールドに明示的な値が含まれていない場合は、デフォルトの値が返されます。
このインタフェースを使うと、オブジェクトの完全グラフ (オブジェクトが構成する完全グラフ) が直列化復元されたとき、オブジェクトが呼び出されます。オブジェクトを有効にできない場合、このインタフェースは通常 ObjectInvalidException
をスローします。validateObject
の呼び出しで例外が起こると、有効化処理は中止され、InvalidObjectException
がスローされます。
package java.io; public interface ObjectInputValidation { public void validateObject() throws InvalidObjectException; }
直列化可能なオブジェクトの場合、readObject
メソッドによって、クラスがそれ独自のフィールドの直列化復元を制御することができます。そのシグニチャーを次に示します。
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException;
直列化可能なオブジェクトの各サブクラスは、それ独自の readObject
メソッドを定義することができます。このメソッドがクラスに実装されていない場合は、defaultReadObject
によって与えられるデフォルトの直列化が使用されます。実装されている場合は、そのクラスは、そのスーパータイプやサブタイプのフィールドではなく、それ独自のフィールドだけを復元する責任があります。
クラスの readObject
メソッドが実装されていれば、そのメソッドはそのクラスの状態を復元する責任があります。transient または static かどうかには関係なく、オブジェクトのすべてのフィールドの値に、そのフィールド型のデフォルトの値が設定されます。ObjectInputStream
の defaultReadObject
メソッドまたは readFields
メソッドを一度 (一度だけ) 呼び出してからでないと、対応する writeObject
メソッドによって書き込まれた任意指定のデータを読み込むことはできません。任意指定のデータを読み込まない場合でも、defaultReadObject
または readFields
を一度呼び出す必要があります。クラスの readObject
メソッドが、このクラスのストリーム内に存在する任意指定部分よりも多くのデータを読み込もうとすると、バイトの読み込みでは -1
が返され、プリミティブデータの読み込み (readInt
、readFloat
など) では EOFException
がスローされ、オブジェクトの読み込みでは eof
フィールドが true
に設定された OptionalDataException
がスローされます。
この任意指定データの形式、構造、バージョン管理の責任のすべては、そのクラスにあります。任意指定データの形式および構造を文書化する場合は、readObject
メソッドに対する javadoc コメント内の @serialData
javadoc タグを使う必要があります。
復元するクラスが読み込みストリーム内に存在しない場合、readObjectNoData
メソッドが定義されていれば、(readObject
の代わりに) そのメソッドが呼び出され、定義されていなければ、フィールドは適切なデフォルト値に初期化されます。詳細は、「3.5 readObjectNoData メソッド」 を参照してください。
ObjectInputStream
からのオブジェクトの読み込みは、新しいオブジェクトの作成に似ています。新しいオブジェクトのコンストラクタがスーパークラスからサブクラスという順番で呼び出されるのと同様に、ストリームから読み込まれるオブジェクトは、スーパークラスからサブクラスに直列化復元されます。直列化復元中に、各 Serializable
サブクラスに対して、コンストラクタではなく readObject
または readObjectNoData
メソッドが呼び出されます。
コンストラクタと readObject
メソッドでもう 1 つ似ている点は、どちらも、完全に構築されていないオブジェクト上にメソッドを呼び出すことができる点です。オブジェクトの構築中に呼び出されるオーバーライド可能なメソッド (private、static、final のどれでもないもの) は、サブクラスによってオーバーライドされる可能性があります。オブジェクトの構築段階に呼び出されるメソッドは、コンストラクタか readObject
または readObjectNoData
メソッドによって現在初期化されている型ではなく、そのオブジェクトの実際の型によって解釈処理されます。したがって、readObject
または readObjectNoData
メソッド内からオーバーライド可能なメソッドを呼び出すと、スーパークラスが完全に初期化される前に意図しないサブクラスが呼び出される可能性があります。
直列化可能オブジェクトでは、サブクラスのインスタンスが直列化復元され、直列化ストリームがそのクラスを直列化復元されたオブジェクトのスーパークラスとしてリストしない場合、readObjectNoData
メソッドを使うと、クラスが自らのフィールドの初期化を制御することができます。これは、受け取り側が、送り側とは異なるバージョンの直列化復元されたインスタンスのクラスを使用し、受け取り側のバージョンが送り側のバージョンによって継承されないクラスを継承する場合に発生する可能性があります。また、直列化ストリームが改変された場合にも発生することがあります。したがって、readObjectNoData
は、「悪意のある」または不完全なソースストリームであっても、直列化復元されたオブジェクトを正しく初期化するのに役立ちます。
private void readObjectNoData() throws ObjectStreamException;
直列化可能クラスごとに、そのクラス独自の readObjectNoData
メソッドを定義することができます。直列化可能クラスが readObjectNoData
メソッドを定義しない場合、上記の状況では、クラスのフィールドはデフォルト値 (「JavaTM Language Specification, Second Edition」の 4.5.5 に記載) に初期化されます。この動作は、readObjectNoData
メソッドのサポートが導入された JavaTM 2 SDK, Standard Edition バージョン 1.4 以前の ObjectInputStream
の動作と一致します。直列化可能クラスが readObjectNoData
メソッドを定義する場合に前述の状況が発生すると、クラス定義の readObject
メソッドが呼び出されたときに、そのクラスがストリームによって直列化復元するインスタンスのスーパークラスとしてリストされていれば、直列化復元中のその時点で readObjectNoData
が呼び出されます。
java.io.Externalizable
を実装するオブジェクトは、readExternal
メソッドを実装して、そのオブジェクトの状態全体を復元しなければなりません。このオブジェクトは、そのスーパークラスと連携してそれらの状態を復元する必要があります。ObjectInput
のすべてのメソッドが、そのオブジェクトのプリミティブ型のフィールドとオブジェクトフィールドを復元するために使用できます。
public void readExternal(ObjectInput stream) throws IOException;
注 -readExternal
メソッドは public であるため、クライアントがストリームから既存オブジェクトを上書きしてしまう危険性があります。クラスで独自にチェックを追加して、適切なときにだけ呼び出されるようにすることもできます。
JDKTM 1.2 では、外部化可能
オブジェクトの問題を修正するために、新しいストリームプロトコルのバージョンが導入されました。外部化可能
オブジェクトの以前の定義では、ストリームから 外部化可能
オブジェクトを適切に読み込めるようにするために、ローカルの仮想マシンが readExternal
メソッドを探す必要がありました。新しい形式では、十分な情報がストリームプロトコルに追加されるので、ローカルの readExternal
メソッドが使えない場合は、直列化で 外部化可能
オブジェクトをスキップすることができます。クラスの展開規則により、ローカルクラスを使ったオブジェクトのマッピングがない場合は、入力ストリーム内の 外部化可能
オブジェクトはスキップできます。
また、新しい Externalizable
ストリーム形式では、ObjectInputStream
によって、利用可能な範囲を超える外部データの読み込み試行を検出し、readExternal
メソッドによって消費されていないデータをスキップできるという利点もあります。外部データの終端を過ぎた読み取りに応答する ObjectInputStream
の動作は、クラス定義の readObject
メソッドが任意指定データの終端を超えて読み込もうとするときの動作と同じです。バイトの読み込みでは -1
を返し、プリミティブの読み込みでは EOFException
をスローし、オブジェクトの読み込みでは、eof
フィールドを true
に設定した OptionalDataException
をスローします。
この形式の変更のため、JDKTM 1.1.6 以前のリリースでは、この新しい形式を読み込むことができません。JDKTM 1.1.6 以前で、PROTOCOL_VERSION_2
に書き込まれたストリームから Externalizable
オブジェクトを読み込もうとすると、StreamCorruptedException
がスローされます。互換性の問題については、「6.3 ストリームプロトコルのバージョン」を参照してください。
Serializable クラスと Externalizable クラスの場合、クラスは readResolve
メソッドを使うことによって、呼び出し側に返される前に、ストリームから読み込んだオブジェクトを置換または解釈処理できます。readResolve
メソッドを実装することによって、クラスは、クラス自体の直列化復元されているインスタンスの型およびインスタンスを直接制御できます。このメソッドは、次のように定義します。
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
readResolve
メソッドは、ObjectInputStream
がストリームからオブジェクトを読み込み、呼び出し側に返す準備をしているときに呼び出されます。ObjectInputStream
は、オブジェクトのクラスによって readResolve
メソッドが定義されるかどうかを確認します。このメソッドが定義される場合は、readResolve
メソッドが呼び出されて、ストリーム内のオブジェクトは、オブジェクトが返されるよう指定できるようになります。返されるオブジェクトは、すべての使用場面で互換性がある型でなければなりません。互換性がない場合は、型の不一致が発見された時点で ClassCastException
がスローされます。
たとえば、Symbol
クラスは、仮想マシン内で各シンボルバインディングにインスタンスが 1 つだけ存在する Symbol
クラスを生成することもできます。そのシンボルがすでに定義されているかどうか、およびアイデンティティの制約を守るために、以前から存在する Symbol
オブジェクトをそのシンボルに取り替えるかどうかを決定する readResolve
メソッドを実装します。このようにして、直列化における Symbol
オブジェクトの一意性を守ることができます。
readResolve
メソッドはオブジェクトに呼び出されないため、そのオブジェクトのオブジェクトグラフへの参照は、readResolve
によって指定された新しいオブジェクトに更新されません。しかし、writeReplace
メソッドによるオブジェクトの直列化の間に、置換オブジェクトのオブジェクトグラフにある元のオブジェクトへの参照はすべて、置換オブジェクトへの参照に置き換えられます。したがって、直列化されたオブジェクトが置換オブジェクトを指定し、その置換オブジェクトのオブジェクトグラフが元のオブジェクトへの参照を持つ場合、直列化復元を行うと、不正なオブジェクトグラフが作成されます。さらに、writeReplace
によって指定された読み込み対象のオブジェクトと元のオブジェクトの参照タイプに互換性がない場合、オブジェクトグラフを構築する際に ClassCastException
が発生します。
目次 | 前の項目 | 次の項目 | Java オブジェクト直列化仕様 バージョン 5.0 |
Copyright © 2004 Sun Microsystems, Inc. All rights reserved