public interface Serializable
非直列化可能クラスのサブタイプを直列化可能にするために、スーパー・タイプのpublicフィールド、protectedフィールド、およびアクセス可能な場合はpackageフィールドの状態を保存および復元する役割をサブタイプが担うことができます。ただし、サブタイプがこの役割を担うことができるのは、サブタイプによって拡張されるクラスに、クラスの状態を初期化するための引数なしのアクセス可能なコンストラクタがある場合だけです。そうでない場合に直列化可能クラスを宣言するとエラーになります。エラーは実行時に検出されます。
直列化復元の際は、非直列化可能クラスのフィールドは、そのクラスのpublicまたはprotectedの引数なしのコンストラクタを使って初期化されます。引数なしのコンストラクタは、直列化可能サブクラスからアクセス可能である必要があります。直列化可能サブクラスのフィールドは、ストリームから復元されます。
グラフの巡回中に、直列化可能インタフェースをサポートしていないオブジェクトに遭遇することがあります。この場合は、NotSerializableExceptionがスローされ、この例外によって非直列化可能オブジェクトのクラスが特定されます。
直列化と直列化復元の際に特殊な扱いが必要なクラスでは、正確に次のようなシグネチャを持つ特殊なメソッドを実装する必要があります。
private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; private void readObjectNoData() throws ObjectStreamException;
writeObjectメソッドは、その特定のクラスのオブジェクトの状態を書き込んで、対応するreadObjectメソッドがオブジェクトの状態を復元できるようにする役割を担います。out.defaultWriteObjectを呼び出せば、オブジェクトのフィールドを保存するためのデフォルトのメカニズムを呼び出すことができます。そのメソッド自身は、そのスーパー・クラスまたはサブクラスに属する状態に関与する必要はありません。状態を保存するには、writeObjectメソッドを使って個々のフィールドをObjectOutputStreamに書き込むか、またはDataOutputがサポートするプリミティブ・データ型用のメソッドを使用します。
readObjectメソッドは、ストリームからの読み込みとクラス・フィールドの復元を行う役割を担います。このメソッドは、in.defaultReadObjectメソッドを呼び出して、オブジェクトの非staticフィールドおよび非transientフィールドを復元するためのデフォルトのメカニズムを呼び出すことができます。defaultReadObjectメソッドは、ストリームの情報を使用して、現在のオブジェクト内で対応するように指定されたフィールドとともに、ストリームに保存されているオブジェクトのフィールドを割り当てます。これで、新しいフィールドを追加できるようにクラスが拡張されるケースが処理されます。このメソッドは、そのスーパー・クラスやサブクラスに属する状態に関与する必要はありません。状態を保存するには、writeObjectメソッドを使って個々のフィールドをObjectOutputStreamに書き込むか、またはDataOutputがサポートするプリミティブ・データ型用のメソッドを使用します。
readObjectNoDataメソッドは、あるクラスが直列化復元されるオブジェクトのスーパー・クラスとして直列化ストリームに指定されていないときに、そのクラスについてそのオブジェクトの状態を初期化します。これは、受け取り側が、送り側とは異なるバージョンの直列化復元されたインスタンスのクラスを使用し、受け取り側のバージョンが送り側のバージョンによって継承されないクラスを継承する場合に発生する可能性があります。また、直列化ストリームが改変された場合にも発生することがあります。したがって、readObjectNoDataは、「悪意のある」または不正なソース・ストリームであっても、直列化復元されたオブジェクトを正しく初期化するのに役立ちます。
ストリームにオブジェクトを書き込むときに使う代替オブジェクトを指定する必要がある直列化可能クラスでは、次のシグネチャを正確に指定して、この特別なメソッドを実装する必要があります。
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
このwriteReplaceメソッドが直列化によって呼び出されるのは、存在していて、しかも直列化されるオブジェクトのクラス内で定義されているメソッドからアクセス可能な場合です。そのため、このメソッドでは、private、protected、およびpackage-privateでアクセスすることができます。このメソッドに対するサブクラスのアクセスは、javaのアクセス可能性ルールに準拠します。
代替オブジェクトのインスタンスをストリームから読み込むときにそのオブジェクトを指定する必要のあるクラスでは、次のシグネチャを正確に指定して、この特別なメソッドを実装する必要があります。
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
このreadResolveメソッドは、writeReplaceと同じ呼び出しルールとアクセス可能性ルールに準拠します。
直列化ランタイムは、各直列化可能クラスにバージョン番号serialVersionUIDを関連付けます。これは、直列化復元中に、直列化オブジェクトの送信側と受信側が、直列化に関して互換性のあるオブジェクトのクラスをロードしたかどうかを確認するために使われます。対応する送信側のクラスとは異なるserialVersionUIDを持つオブジェクトのクラスを受信側がロードした場合、直列化復元ではInvalidClassException
が発生します。フィールド名"serialVersionUID"
を宣言することによって、直列化可能クラスは独自のserialVersionUIDを明示的に宣言できます。このフィールド名は、次のようにstatic、final、およびlong
型である必要があります。
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;直列化可能クラスがserialVersionUIDを明示的に宣言しない場合、直列化ランタイムは「Java(TM)オブジェクト直列化仕様」で説明されているように、クラスのさまざまな側面に基づいて、クラスのserialVersionUIDのデフォルト値を計算します。ただし、すべての直列化可能クラスがserialVersionUID値を明示的に宣言することを強くお薦めします。これは、デフォルトのserialVersionUIDの計算が、コンパイラの実装によって異なる可能性のあるクラスの詳細にきわめて影響を受けやすく、直列化復元中に予期しない
InvalidClassException
が発生する可能性があるためです。したがって、javaコンパイラの実装が異なってもserialVersionUID値の一貫性を確保にするには、直列化可能クラスがserialVersionUID値を明示的に宣言しなければいけません。また、serialVersionUIDの明示的な宣言ではprivate
修飾子を使用することを強くお薦めします。このような宣言は直接的に宣言するクラスにのみ適用されるためです。つまり、serialVersionUIDフィールドは継承されるメンバーのように使いやすくありません。配列クラスはserialVersionUIDを明示的に宣言できないため、常にデフォルトの計算値を持ちますが、配列クラスに関してはserialVersionUID値の一致要件は適用されません。ObjectOutputStream
、ObjectInputStream
、ObjectOutput
、ObjectInput
、Externalizable
バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright© 1993, 2014, Oracle and/or its affiliates. All rights reserved.