ホームページ  >  記事  >  Java  >  Java におけるオブジェクトのシリアル化と逆シリアル化の詳細な説明

Java におけるオブジェクトのシリアル化と逆シリアル化の詳細な説明

高洛峰
高洛峰オリジナル
2017-01-18 11:22:161368ブラウズ

この記事の例では、Java でのオブジェクトのシリアル化と逆シリアル化について説明します。皆さんの参考に共有してください。詳細は次のとおりです:

1. はじめに

オブジェクトのシリアル化 (Serializable) はオブジェクトをバイト シーケンスに変換するプロセスを指し、逆シリアル化はバイト シーケンスに基づいてオブジェクトを復元するプロセスを指します。

シリアル化は通常、次のシナリオで使用されます:

1. オブジェクトを永続的に保存し、オブジェクトのバイト シーケンスをローカル ファイルに保存します。
3. シリアル化を通じてオブジェクトをネットワークに転送します。プロセス間でオブジェクトを渡します。

オブジェクトが属するクラスは、シリアル化するために Serializable または Externalizable インターフェイスを実装する必要があります。 Serializable インターフェイスを実装するクラスの場合、デフォルトのシリアル化メソッドがシリアル化と逆シリアル化に使用されます。デシリアライズ動作自体。

Java.io.ObjectOutputStream はオブジェクト出力ストリームを表し、そのメソッド writeObject(Object obj) はオブジェクトのシリアル化を実現し、取得したバイト シーケンスをターゲット出力ストリームに書き込むことができます。

Java.io.ObjectInputStream はオブジェクト入力ストリームを表し、その readObject() メソッドはソース入力ストリームからバイト シーケンスを読み取り、それをオブジェクトに逆シリアル化して返します。

2. いくつかのシリアル化メソッド

Customer がシリアル化を実装する方法に応じて、次のシリアル化メソッドが存在すると仮定します。

1. Serializable を実装し、readObject メソッドと writeObject メソッドは定義されていません。

ObjectOutputStream は、JDK のデフォルト メソッドを使用して、Customer オブジェクトの非一時的なインスタンス変数をシリアル化します。

ObjectInputStream は、JDK のデフォルト メソッドを使用して、Customer オブジェクトの非一時的なインスタンス変数を逆シリアル化します。

2. Serializable を実装し、readObject メソッドと writeObject メソッドを定義します。

ObjectOutputStream は Customer クラスの writeObject(ObjectOutputStream out) メソッドを呼び出し、Customer オブジェクトの非一時インスタンス変数をシリアル化します。

ObjectInputStream は readObject(ObjectInputStream in) を呼び出します。 Customer クラスの ) メソッドは、Customer オブジェクトの非一時的なインスタンス変数を逆シリアル化します。

3. 外部化可能を実装し、readExternal メソッドと writeExternal メソッドを定義します

ObjectOutputStream は、Customer クラスの非一時インスタンス変数をシリアル化するために、Customer クラスの writeInitial メソッドを呼び出します。

ObjectInputStream は、最初に Customer クラスのパラメーターなしのコンストラクターを通じてオブジェクトをインスタンス化します。 、次に、 readExternal メソッドを使用して、Customer オブジェクトの非一時的なインスタンス変数を逆シリアル化します。

3. Serializable インターフェイス

このクラスは、シリアル化機能を有効にするために java.io.Serializable インターフェイスを実装します。このインターフェイスを実装していないクラスは、その状態をシリアル化または逆シリアル化できません。直列化可能なクラスのすべてのサブタイプは、それ自体直列化可能です。シリアル化インターフェイスにはメソッドやフィールドがなく、シリアル化可能なセマンティクスを識別するためにのみ使用されます。

逆シリアル化プロセス中に、シリアル化不可能なクラスのフィールドは、クラスの public または protected パラメーターなしのコンストラクターを使用して初期化されます。直列化可能なサブクラスは、パラメーターなしのコンストラクターにアクセスできる必要があります。直列化可能なサブクラスのフィールドは、このストリームから復元されます。

クラス ビューを移動すると、Serializable インターフェイスをサポートしていないオブジェクトに遭遇する可能性があります。この場合、NotSerializableException がスローされ、シリアル化不可能なオブジェクトのクラスが特定されます。

1. 正確な署名

シリアル化および逆シリアル化中に特別な処理が必要なクラスは、次の正確な署名を使用して特別なメソッドを実装する必要があります。 io.ObjectInputStream in) throws IOException, ClassNotFoundException;

private void readObjectNoData() throws ObjectStreamException;

writeObject メソッドは、対応する readObject メソッドが復元できるように、特定のクラスのオブジェクトの状態を書き込む役割を果たします。オブジェクトのフィールドを保存するためのデフォルトのメカニズムは、out.defaultWriteObject を呼び出すことで呼び出すことができます。メソッド自体には、そのスーパークラスまたはサブクラスに属する状態が関与する必要はありません。状態は、writeObject メソッドを使用するか、プリミティブ データ型の DataOutput でサポートされるメソッドを使用して、個々のフィールドを ObjectOutputStream に書き込むことによって保存できます。

readObject メソッドは、ストリームからクラス フィールドを読み取り、復元する役割を果たします。 in.defaultReadObject を呼び出して、オブジェクトの非静的および非一時的なフィールドを復元するためのデフォルトのメカニズムを呼び出すことができます。 defaultReadObject メソッドは、ストリームからの情報を使用して、現在のオブジェクト内の対応する指定されたフィールドによって保持されるストリーム内のオブジェクトのフィールドを割り当てます。これは、クラスの進化後に新しいフィールドを追加する必要がある状況を処理するために使用されます。メソッド自体には、そのスーパークラスまたはサブクラスに属する状態が関与する必要はありません。状態は、writeObject メソッドを使用するか、プリミティブ データ型の DataOutput でサポートされるメソッドを使用して、個々のフィールドを ObjectOutputStream に書き込むことによって保存できます。

直列化ストリームが、逆直列化されるオブジェクトのスーパークラスとして指定されたクラスをリストしていない場合、readObjectNoData メソッドは、特定のクラスのオブジェクト状態を初期化する役割を果たします。これは、受信者が送信者とは異なるバージョンの逆シリアル化されたインスタンス クラスを使用し、受信者のバージョンが送信者のバージョンによって拡張されていないクラスを拡張する場合に発生します。これはシリアル化ストリームが改ざんされた場合にも発生するため、ソース ストリームが「敵対的」であるか不完全であるかに関係なく、readObjectNoData メソッドを使用して逆シリアル化されたオブジェクトを正しく初期化できます。

オブジェクトをストリームに書き込むときは、使用する置換オブジェクトの直列化可能クラスを指定する必要があり、この特別なメソッドを正確なシグネチャで実装する必要があります。

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
This writeReplace メソッド このメソッドが存在し、シリアル化されるオブジェクトのクラスで定義されたメソッドを通じてアクセスできる場合は、シリアル化によって呼び出されます。したがって、メソッドはプライベート、保護された、およびパッケージプライベートアクセスを持つことができます。サブクラスによるこのメソッドへのアクセスは、Java アクセス ルールに従います。

ストリームからクラスのインスタンスを読み取るときは、代替クラスがこの特別なメソッドを実装するために使用する正確なシグネチャを指定する必要があります。

ANY-ACCESS-MODIFIER オブジェクト readResolve() throws ObjectStreamException;
この readResolve メソッドは、writeReplace と同じ呼び出しルールとアクセス ルールに従います。
クラスで readResolve メソッドが定義されている場合、readResolve メソッドは逆シリアル化の最後に呼び出され、このメソッドによって返されるオブジェクトが逆シリアル化の最終結果になります。

2.serialVersionUID

シリアル化ランタイムは、serialVersionUID と呼ばれるバージョン番号を使用して各シリアル化可能なクラスに関連付けます。このシリアル番号は、シリアル化されたオブジェクトの送信者と受信者がシリアル化互換性があるかどうかを確認するために使用されます。このオブジェクト用にロードされました。受信側によってロードされたオブジェクトのクラスの SerialVersionUID が、送信側のクラスの対応するバージョン番号と異なる場合、逆シリアル化により InvalidClassException が発生します。シリアル化可能なクラスは、「serialVersionUID」という名前のフィールド (静的な、final long フィールドである必要があります) を宣言することによって、独自の SerialVersionUID を明示的に宣言できます。 SerialVersionUID を宣言すると、「Java(TM) オブジェクト シリアル化仕様」で説明されているように、シリアル化ランタイムはクラスのさまざまな側面に基づいてクラスのデフォルトの SerialVersionUID 値を計算します。ただし、すべてのシリアル化可能なクラスで、serialVersionUID 値を明示的に宣言することを強くお勧めします。その理由は、デフォルトの SerialVersionUID の計算はクラスの詳細に非常に敏感であり、コンパイラーの実装によって大きく異なる可能性があるためです。予期しない InvalidClassException が発生します。したがって、異なる Java コンパイラー実装間でのシリアルバージョンUID値の一貫性を確保するには、シリアル化クラスで明示的なシリアルバージョンUID値を宣言する必要があります。また、(可能であれば) private 修飾子を使用して、serialVersionUID を明示的に宣言することを強くお勧めします。その理由は、そのような宣言はクラスを直接宣言する場合にのみ使用する必要があるためです。serialVersionUID フィールドは、継承されたメンバーとしては役に立ちません。配列クラスは明示的にserialVersionUIDを宣言できないため、常にデフォルトの計算値を持ちますが、配列クラスがserialVersionUID値と一致する必要はありません。

3.Externalizable インターフェイス

Externalizable は、Serailizable の拡張機能であり、Initializable インターフェイスを実装するクラスのシリアル化には、次の特徴があります:

クラスの writeExternal メソッドはシリアル化中に呼び出され、readExternal メソッドは逆シリアル化中に呼び出されます。 ;

逆シリアル化を実行する場合 まず、デフォルトの逆シリアル化とは異なり、クラスのパラメーターなしのコンストラクターを呼び出します。そのため、シリアル化を実装するために Externalizable インターフェイスを実装するクラスには、パブリックのパラメーターなしのコンストラクターを提供する必要があります。そうしないと逆シリアル化で例外が発生します。

4. 概要

デフォルトのシリアル化メソッドを使用する場合、クラスが Serializable インターフェイスを実装している限り、そのインスタンスはシリアル化できます。一般に、継承専用に設計されたクラスは、親クラスが Serializable インターフェイスを実装すると、そのすべてのサブクラスもシリアル化可能になるため、Serializable インターフェイスを実装しないようにする必要があります。

デフォルトのシリアル化メソッドの欠点:

1. 公開に適していないオブジェクトの機密データを直接シリアル化することは安全ではありません。

2. オブジェクトのメンバー変数が正しいかどうかをチェックしません。制約によりデータが改ざんされ、異常な動作が発生する可能性があります。

3. オブジェクト グラフが非常に複雑な場合、大量のリソースを消費し、設定によりスタック オーバーフローが発生します。 Java 仮想マシンの
4. クラスの作成 インターフェイスはクラスの内部実装によって制約され、クラスのアップグレードとメンテナンスが制限されます。

Serializable インターフェイスのプライベート型 writeObject() および readObject() を実装するか、または Externalizable インターフェイスを実装して writeExternal() メソッドと readExternal() メソッドを実装し、パブリック型のパラメーターなしのコンストラクターを提供することによって、シーケンスを制御します。このプロセスにより、デフォルトのシリアル化メソッドの欠点を効果的に回避できます。

この記事が皆さんの Java プログラミング設計に役立つことを願っています。

Java でのオブジェクトのシリアル化と逆シリアル化の詳細な説明に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。