Java シリアライゼーション

Java シリアライゼーションは、オブジェクトをバイトストリームに変換するプロセスです。これにより、オブジェクトをディスクに保存したり、ネットワーク経由で転送したり、メモリ内に保存したりし、後でデシリアライズしてバイトストリームを再びオブジェクトに変換できます。

Java でのシリアライゼーションは、java.io.Serializableインターフェースを実装することによって行われます。このインターフェースにはメソッドがなく、クラスがシリアライズ可能であることを識別するための単なるマーカーインターフェースです。

オブジェクトをシリアライズするときは、それを特別なファイルにラップして、保存、転送、または格納できます。デシリアライズは、そのファイルを開き、シリアライズされたデータを読み取り、それをオブジェクトに復元してプログラムで使用できるようにします。

シリアライゼーションは、オブジェクトを保存、転送、復元するための方法であり、オブジェクトを異なるコンピュータ間で移動・共有できるようにします。これは、分散システム、データストレージ、クロスプラットフォーム通信に非常に役立ちます。

以下は、Java シリアライゼーションの基本的な概念と使い方です。

Serializable インターフェースの実装: クラスをシリアライズ可能にするには、そのクラスに java.io.Serializable インターフェースを実装させる必要があります。これにより、Java コンパイラにそのクラスがシリアライズ可能であることが伝わります。例:

例

import java.io.Serializable;

public class MyClass implements Serializable {
    // クラスのメンバーとメソッド
}

オブジェクトのシリアライズ:ObjectOutputStream クラスを使用してオブジェクトをバイトストリームにシリアライズします。以下は簡単な例です:

例

MyClass obj = new MyClass();
try {
    FileOutputStream fileOut = new FileOutputStream("object.ser");
    ObjectOutputStream out = new ObjectOutputStream(fileOut);
    out.writeObject(obj);
    out.close();
    fileOut.close();
} catch (IOException e) {
    e.printStackTrace();
}

上記のコードは、"object.ser" という名前のファイル内の obj オブジェクトをシリアライズします。

オブジェクトのデシリアライズ:ObjectInputStream クラスを使用してバイトストリームからオブジェクトをデシリアライズします。以下は簡単な例です:

例

MyClass obj = null;
try {
    FileInputStream fileIn = new FileInputStream("object.ser");
    ObjectInputStream in = new ObjectInputStream(fileIn);
    obj = (MyClass) in.readObject();
    in.close();
    fileIn.close();
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

上記のコードは、"object.ser" ファイルからバイトストリームを読み取り、それを MyClass オブジェクトにデシリアライズします。

ObjectInputStream クラスと ObjectOutputStream クラスは高レベルのデータストリームであり、オブジェクトのデシリアライズとシリアライズのメソッドを含みます。

ObjectOutputStream クラスには、さまざまなデータ型を書き込むための多くの書き込みメソッドが含まれていますが、特別なメソッドが 1 つあります:

public final void writeObject(Object x) throws IOException

上記のメソッドはオブジェクトをシリアライズし、それを出力ストリームに送信します。同様に、ObjectInputStream クラスには、オブジェクトをデシリアライズする次のメソッドが含まれています:

public final Object readObject() throws IOException, ClassNotFoundException

このメソッドはストリームから次のオブジェクトを取得し、オブジェクトをデシリアライズします。戻り値は Object 型なので、適切なデータ型にキャストする必要があります。

例

Java でシリアライゼーションがどのように機能するかを示すために、前のチュートリアルで説明した Employee クラスを使用します。次のような Employee クラスを定義したと仮定します。このクラスは Serializable インターフェースを実装しています。

Employee.java ファイルコード:

public class Employee implements java.io.Serializable { public String name; public String address; public transient int SSN; public int number; public void mailCheck() { System.out.println("Mailing a check to " + name + " " + address); } }

クラスのオブジェクトをシリアライズするには、次の 2 つの条件を満たす必要があることに注意してください:

クラスは java.io.Serializable インターフェースを実装する必要があります。

クラスのすべてのプロパティはシリアライズ可能である必要があります。シリアライズ不可能なプロパティがある場合は、そのプロパティを一時的 (transient) としてマークする必要があります。

Java 標準クラスがシリアライズ可能かどうかを確認したい場合は、そのクラスのドキュメントを参照してください。クラスのインスタンスがシリアライズ可能かどうかを調べるのは非常に簡単で、そのクラスが java.io.Serializable インターフェースを実装しているかどうかを確認するだけです。


オブジェクトのシリアライズ

ObjectOutputStream クラスはオブジェクトをシリアライズするために使用されます。次の SerializeDemo の例では、Employee オブジェクトをインスタンス化し、そのオブジェクトをファイルにシリアライズします。

このプログラムを実行すると、employee.ser という名前のファイルが作成されます。このプログラムには出力はありませんが、コードを調べることでプログラムの動作を理解できます。

注意:オブジェクトをファイルにシリアライズするとき、Java の標準的な慣例では、ファイルに .ser 拡張子を付けます。

SerializeDemo.java ファイルコード:

import java.io.*; public class SerializeDemo { public static void main(String [] args) { Employee e = new Employee(); e.name = "Reyan Ali"; e.address = "Phokka Kuan, Ambehta Peer"; e.SSN = 11122333; e.number = 101; try { FileOutputStream fileOut = new FileOutputStream("/tmp/employee.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(e); out.close(); fileOut.close(); System.out.printf("Serialized data is saved in /tmp/employee.ser"); }catch(IOException i) { i.printStackTrace(); } } }

オブジェクトのデシリアライズ

次の DeserializeDemo プログラムはデシリアライズの例です。/tmp/employee.ser には Employee オブジェクトが格納されています。

DeserializeDemo.java ファイルコード:

import java.io.*; public class DeserializeDemo { public static void main(String [] args) { Employee e = null; try { FileInputStream fileIn = new FileInputStream("/tmp/employee.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); e = (Employee) in.readObject(); in.close(); fileIn.close(); }catch(IOException i) { i.printStackTrace(); return; }catch(ClassNotFoundException c) { System.out.println("Employee class not found"); c.printStackTrace(); return; } System.out.println("Deserialized Employee..."); System.out.println("Name: " + e.name); System.out.println("Address: " + e.address); System.out.println("SSN: " + e.SSN); System.out.println("Number: " + e.number); } }

上記のプログラムをコンパイルして実行した結果は次のとおりです:

Deserialized Employee...
Name: Reyan Ali
Address:Phokka Kuan, Ambehta Peer
SSN: 0
Number:101

ここで注意すべき点は次のとおりです:

readObject() メソッド内の try/catch コードブロックは、ClassNotFoundException 例外をキャッチしようとします。JVM がオブジェクトをデシリアライズできるためには、バイトコードを見つけられるクラスである必要があります。JVM がオブジェクトのデシリアライズ中にそのクラスを見つけられない場合、ClassNotFoundException 例外がスローされます。

readObject() メソッドの戻り値が Employee 参照にキャストされることに注意してください。

オブジェクトがシリアライズされるとき、SSN プロパティの値は 111222333 ですが、このプロパティは一時的 (transient) であるため、その値は出力ストリームに送信されません。したがって、デシリアライズ後の Employee オブジェクトの SSN プロパティは 0 になります。

その他の拡張