| 目次 | 前の項目 | 次の項目 | Java オブジェクト直列化仕様 | 
クラス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メソッドを使用します。このメソッドは、このストリームを読んで、オブジェクトを再構築します。
ObjectInputStream サブクラスが実装をオーバーライドしている場合は、readObjectOverride メソッドを呼び出し、戻します。実装し直す方法については、この節の最後で説明します。
Class であれば、その ObjectStreamClass 記述子を読み、それとそのハンドルを、認識されているオブジェクトセットに追加し、対応する Class オブジェクトを返します。
ObjectStreamClass であれば、その名前と serialVersionUID とフィールドを読み、そのオブジェクトとそのハンドルを、認識されているオブジェクトセットに追加します。このストリームに対し resolveClass メソッドを呼び出して、この記述子のローカルクラスを入手し、そのクラスが見つからないときは例外をスローします。ObjectStreamClass オブジェクトを返します。  
ObjectStreamClass と配列の長さを読みます。その配列を割り当て、そのオブジェクトとそのハンドルを、認識されているオブジェクトセットに追加します。型に適したメソッドを使って各要素を読み込み、配列に割り当てます。手順 11 に進みます。
ObjectStreamClass がストリームから読み込まれます。その ObjectStreamClass のローカルクラスが取り出されます。このクラスは、直列化可能か外部化可能でなければなりません。
readObject メソッドか、これらが定義されていなければ、defaultReadObject メソッドが呼び出されて、各クラスのフィールドが復元されます。直列化復元時には、直列化可能クラスに対して、フィールドの初期化子およびコンストラクタは実行されません。通常、このストリームを書き込んだクラスのバージョンは、このストリームを読み込むクラスと同じです。この場合、ストリームのオブジェクトのすべてのスーパータイプは、現在ロードされているクラスのスーパータイプと一致します。このストリームを書き込んだクラスのバージョンのスーパータイプが、ロードされているクラスのスーパータイプと異なる場合は、ObjectInputStream で異なるクラスの状態を復元したり、初期化したりする際、いっそうの注意が必要です。この場合には、すべてのクラスを調べて、ストリームにあるデータと、復元するオブジェクトのクラスとを比較する必要があります。ストリームにはあるがオブジェクトにはないクラスのデータは破棄されます。オブジェクトにはあるがストリームにはないクラスの場合には、そのクラスのフィールドが、デフォルトの直列化によってデフォルト値に設定されます。
readExternal メソッドが呼び出され、そのオブジェクトの内容が復元されます。
ObjectInputStream のサブクラスによって、置換を処理します。
置換が行われた場合、認識されているオブジェクトのテーブルが更新されるので、置換オブジェクトがハンドルに関連付けられます。そのあと、置換オブジェクトがreadObjectから返されます。プリミティブ型を読むためのすべてのメソッドは、ストリームのブロックデータレコードからバイトだけを使用します。ストリームの次のアイテムがオブジェクトのときにプリミティブデータの読み込みが行われると、読み込みメソッドは -1 か EOFException のうちで適切な方を返します。プリミティブ型の値は、
DataInputStreamによってブロックデータレコードから読み込まれます。スローされた例外は、そのトラバースの間に起きたエラーか、基本のストリームで起きた例外を反映したものです。例外がスローされた場合、基本のストリームは不明で使用不能な状態のままです。
ストリームでリセットトークンが起こると、ストリームのすべての状態は破棄されます。認識されているオブジェクトセットはクリアされます。
ストリームで例外トークンが起こると、その例外が読み込まれ、新しい WriteAbortedException がスローされます。このとき、停止を引き起こした例外が引数として指定されます。ストリームコンテキストは前に述べたようにリセットされます。
ストリームから非共有オブジェクトを読み込むには、
readUnsharedメソッドを使用します。このメソッドは、後続のreadObjectおよびreadUnsharedの呼び出しが、元のreadUnsharedの呼び出しによって返された直列化復元インスタンスへの追加参照を返すことができない点を除いては、readObjectと同じです。具体的には、次のようになります。
readUnsharedを介してオブジェクトの直列化復元を行うと、返されたオブジェクトに関連付けられたストリームハンドルが無効になります。このこと自体は、readUnsharedによって返された参照が一意であることを常に保証するものではありません。直列化復元されたオブジェクトは、readResolveメソッドを定義して、ほかの組織が見ることができるオブジェクトを返すことがあります。また、readUnsharedが、ストリーム内のほかの場所や外部機関から取得可能なClassオブジェクトを返すこともあります。ただし、オブジェクトが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メソッドは、ストリーム内のクラス名と同じ、完全指定されたクラス名を返す必要がありました。JDK 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メソッドは、ファイナルではないので、サブクラスによって直接オーバーライドされます。