ホームページ  >  記事  >  Java  >  Java チュートリアルでオブジェクトのシリアル化を使用する基本的な例の詳細な説明

Java チュートリアルでオブジェクトのシリアル化を使用する基本的な例の詳細な説明

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

このプロセスはネットワーク経由で実装することもできます。まず Windows マシンでオブジェクトを作成し、シリアル化してから、ネットワーク経由で Unix マシンに送信し、そこで正確に「アセンブル」することができます。その 1 つである RMI、ソケット、JMS、EJB が Java オブジェクトを相互に転送できる理由は、もちろんオブジェクトのシリアル化メカニズムによるものです。

Java オブジェクトのシリアル化メカニズムには、一般に 2 つの用途があります。

Java の JavaBeans: Bean の状態情報は通常、設計時に構成されます。Bean の状態情報は、プログラムの実行時に復元できるように保存する必要があります。これには、状態情報が必要です。オブジェクトの状態をファイルに保存し、オブジェクトの状態を読み取ることでオブジェクトを再構築し、プログラムの状態を復元できます。
RMI を使用すると、リモート マシン上のオブジェクトをローカル マシン上にあるかのように操作できます。また、ソケットを使用してネットワーク経由でオブジェクトを送信するプログラムの場合は、シリアル化メカニズムの実装が必要です。
クラスに Java.io.Serializable インターフェースを実装させることで、クラスをシリアル化できます。このインターフェースはマーカーインターフェースです。つまり、インターフェイスは、クラスがインターフェイスを実装するためにメソッドを実装する必要がありません。これは主に、オブジェクトをシリアル化する必要があることを Java 仮想マシン (JVM) に通知するために使用されます。

このために、いくつかの点を明確にしておく必要があります:

すべてのクラスをシリアル化できるわけではありません。実際に、cmd で、serialver Java.net.Socket を入力して、ソケットがシリアル化できるかどうかに関する情報を取得します。 、ソケットをシリアル化できません。
Java には、文字列、ベクトルなどのシリアル化可能なインターフェイスを実装した多くの基本クラスがあります。ただし、たとえば、hashtable はシリアル化可能なインターフェイスを実装していません。オブジェクトをストリームに読み書きするための 2 つの主要なクラスがあります。ObjectOutputStream と ObjectInputStream は、出力ストリームにオブジェクトを書き込むための writeObject メソッドを提供し、ObjectInputStream は、入力ストリームからオブジェクトを読み取るための readObject メソッドを提供します。これらのメソッドを使用するオブジェクトは、すでにシリアル化されている必要があります。つまり、Serializable インターフェイスが実装されている必要があります。 writeobject をハッシュテーブル オブジェクトにしたい場合は、例外が発生します。
シリアル化のプロセスは、オブジェクトをバイト ストリームに書き込み、バイト ストリームからオブジェクトを読み取ることです。オブジェクトの状態をバイト ストリームに変換した後、Java.io パッケージのさまざまなバイト ストリーム クラスを使用して、オブジェクトの状態をファイルに保存したり、別のスレッドにパイプしたり、ネットワーク接続経由​​で別のホストにオブジェクト データを送信したりできます。オブジェクトのシリアル化機能は非常にシンプルかつ強力で、RMI、Socket、JMS、および EJB にアプリケーションがあります。オブジェクトのシリアル化の問題は、ネットワーク プログラミングにおいて最も興味深いトピックではありませんが、非常に重要であり、多くの実用的な意味を持っています。
オブジェクトのシリアル化により分散オブジェクトを実装できます。主なアプリケーションは次のとおりです。 RMI はオブジェクトのシリアル化を使用して、ローカル マシンでオブジェクトを実行するときと同じようにリモート ホストでサービスを実行します。
Java オブジェクトのシリアル化は、1 つのオブジェクトのデータを保存するだけでなく、そのオブジェクトが参照する各オブジェクトのデータも再帰的に保存します。オブジェクト階層全体をバイト ストリームに書き込むことができ、ファイルに保存したり、ネットワーク接続を介して渡すことができます。オブジェクトのシリアル化を使用すると、オブジェクトの「ディープ コピー」、つまりオブジェクト自体と参照されるオブジェクト自体をコピーできます。オブジェクトをシリアル化すると、オブジェクト シーケンス全体が作成される場合があります。
Java のシリアル化は比較的単純で、通常、オブジェクトの状態を保存および復元するためのカスタム コードを記述する必要はありません。 Java.io.Serializable インターフェイスを実装するクラス オブジェクトは、クラスにコードを追加せずに、バイト ストリームに変換したり、バイト ストリームから復元したりできます。オブジェクトの状態を保存または復元するためにカスタム コードが必要になるのはまれなケースです。ここで注意してください: すべてのクラスがシリアル化できるわけではなく、一部のクラスはシリアル化できません。たとえば、スレッドを含むクラスは特定の JVM と非常に複雑な関係を持っています。

シリアル化メカニズム:

シリアル化は、シリアル化と逆シリアル化の 2 つの部分に分かれています。シリアル化はプロセスの最初の部分であり、データをバイト ストリームに分割して、ファイルに保存したり、ネットワーク経由で送信したりできるようにします。逆シリアル化とは、バイト ストリームを開いてオブジェクトを再構築することです。オブジェクトのシリアル化は、基本的なデータ型をバイト表現に変換するだけでなく、場合によってはデータを復元することもできます。データを復元するには、復元されたデータのオブジェクト インスタンスが必要です。 ObjectOutputStream のシリアル化プロセスは、オブジェクト タイプとバージョン情報を含むバイト ストリームに接続されます。逆シリアル化する場合、JVM はヘッダー情報を使用してオブジェクト インスタンスを生成し、オブジェクト バイト ストリーム内のデータをオブジェクト データ メンバーにコピーします。以下では 2 つの部分に分けて説明します:

オブジェクト ストリームの処理: (シリアル化プロセスと逆シリアル化プロセス)
Java.io パッケージには、オブジェクトをシリアル化するための 2 つのクラスがあります。 ObjectOutputStream はオブジェクトをバイト ストリームに書き込む役割を果たし、ObjectInputStream はバイト ストリームからオブジェクトを再構築します。
まず ObjectOutputStream クラスを理解しましょう。 ObjectOutputStream クラスは DataOutput インターフェイスを拡張します。
writeObject() メソッドは、オブジェクトのシリアル化に使用される最も重要なメソッドです。オブジェクトに他のオブジェクトへの参照が含まれている場合、writeObject() メソッドはそれらのオブジェクトを再帰的にシリアル化します。各 ObjectOutputStream は、同じオブジェクトの複数のコピーが送信されるのを防ぐために、シリアル化されたオブジェクト参照テーブルを維持します。 (これは重要です) writeObject() は相互参照オブジェクトのセット全体をシリアル化できるため、同じオブジェクトをシリアル化するために同じ ObjectOutputStream インスタンスが誤って要求される可能性があります。このとき、オブジェクトのバイトストリームを再度書き込むのではなく、逆参照シリアル化が実行されます。

それでは、例から ObjectOutputStream クラスについて学びましょう。

// 序列化 today's date 到一个文件中.  
FileOutputStream  f = new  FileOutputStream ("tmp" );  
ObjectOutputStream  s = new  ObjectOutputStream (f);  
s.writeObject("Today" );  
s.writeObject(new  Date ());  
s.flush();

それでは、ObjectInputStream クラスについて理解しましょう。これは ObjectOutputStream に似ています。 DataInput インターフェイスを拡張します。 ObjectInputStream のメソッドは、Java の基本データ型を読み取るための DataInputStream のパブリック メソッドを反映しています。 readObject() メソッドは、バイト ストリームからオブジェクトを逆シリアル化します。 readObject() メソッドが呼び出されるたびに、ストリーム内の次のオブジェクトが返されます。オブジェクト バイト ストリームはクラスのバイトコードを送信しませんが、クラス名とその署名が含まれます。 readObject() がオブジェクトを受け取ると、JVM はヘッダーで指定されたクラスをロードします。このクラスが見つからない場合、readObject() は ClassNotFoundException をスローします。オブジェクト データとバイトコードを送信する必要がある場合は、RMI フレームワークを使用できます。 ObjectInputStream の残りのメソッドは、逆シリアル化プロセスをカスタマイズするために使用されます。
例は次のとおりです:

//从文件中反序列化 string 对象和 date 对象  
FileInputStream  in = new  FileInputStream ("tmp" );  
ObjectInputStream  s = new  ObjectInputStream (in);  
String  today = (String )s.readObject();  
Date  date = (Date )s.readObject();
カスタムシリアル化プロセス:
シリアル化は通常自動的に実行できますが、場合によってはプロセスの制御が必要になる場合があります。 Java はクラスをシリアル化可能として宣言できますが、静的または一時的として宣言されたデータ メンバーを手動で制御することもできます。

例: 非常に単純なシリアル化クラス。

public  class  simpleSerializableClass implements  Serializable {  
String  sToday="Today:" ;  
transient  Date  dtToday=new  Date ();  
}

シリアル化する場合、一時的または静的として宣言されたメンバーを除き、クラスのすべてのデータ メンバーがシリアル化可能である必要があります。変数を一時変数として宣言すると、変数をシリアル化する責任があることが JVM に伝えられます。データ メンバーが一時的として宣言された後は、シリアル化プロセスでそのデータ メンバーをオブジェクト バイト ストリームに追加できません。一時的なデータ メンバーから送信されるデータはありません。後でデータを逆シリアル化する場合、データ メンバーを再構築する必要があります (データ メンバーはクラス定義の一部であるため)。ただし、このデータ メンバーはストリームにデータを書き込まないため、データは含まれません。オブジェクト ストリームは静的オブジェクトや一時的なオブジェクトをシリアル化しないことに注意してください。私たちのクラスは、writeObject() メソッドと readObject() メソッドを使用して、これらのデータ メンバーを処理します。 writeObject() メソッドと readObject() メソッドを使用する場合は、これらのデータ メンバーを書き込まれた順序で読み取るようにしてください。
カスタム シリアル化の使用方法に関するコードの一部は次のとおりです

//重写writeObject()方法以便处理transient的成员。  
public  void  writeObject(ObjectOutputStream  outputStream) throws  IOException {  
outputStream.defaultWriteObject();//使定制的writeObject()方法可以  
//利用自动序列化中内置的逻辑。  
outputStream.writeObject(oSocket.getInetAddress());  
outputStream.writeInt(oSocket.getPort());  
}  
//重写readObject()方法以便接收transient的成员。  
private  void  readObject(ObjectInputStream  inputStream) throws IOException ,  
ClassNotFoundException {  
inputStream.defaultReadObject();//defaultReadObject()补充自动序列化  
InetAddress  oAddress=(InetAddress )inputStream.readObject();  
int  iPort =inputStream.readInt();  
oSocket = new  Socket (oAddress,iPort);  
iID=getID();  
dtToday =new  Date ();  
}

完全にカスタマイズされたシリアル化プロセス:
クラスが独自のシリアル化を完全に担当する場合は、Serializable インターフェイスの代わりに Externalizable インターフェイスを実装します。外部化可能なインターフェイス定義には、writeExternal() と readExternal() という 2 つのメソッドが含まれています。これらのメソッドは、オブジェクト データ メンバーがバイト ストリームに書き込まれる方法を制御するために使用できます。クラスが Externalizable を実装すると、ヘッダーがオブジェクト ストリームに書き込まれ、その後、データ メンバーのシリアル化と復元が完全にクラスに行われます。ヘッダーの場合、自動シリアル化はまったく行われません。ここで注意すべき点があります。 Initializable インターフェイスを実装するクラスを宣言すると、重大なセキュリティ リスクが生じます。 writeExternal() メソッドと readExternal() メソッドは public として宣言されており、悪意のあるクラスはこれらのメソッドを使用してオブジェクト データの読み取りと書き込みを行うことができます。オブジェクトに機密情報が含まれている場合は、細心の注意を払ってください。これには、安全なソケットの使用やバイト ストリーム全体の暗号化が含まれます。ここまでで、シリアル化の基本を学習しました。

Java チュートリアルおよび関連記事でのオブジェクトのシリアル化の基本的な例の詳細な説明については、PHP 中国語 Web サイトに注目してください。

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