Java-serialization
Java-シリアル化
Javaには、オブジェクトのデータと、オブジェクトの型とオブジェクトに格納されているデータの型に関する情報を含むバイトシーケンスとしてオブジェクトを表すことができるオブジェクトシリアル化と呼ばれるメカニズムがあります。
シリアル化されたオブジェクトは、ファイルに書き込まれた後、ファイルから読み取られて逆シリアル化されます。つまり、オブジェクトとそのデータを表す型情報とバイトを使用して、オブジェクトをメモリに再作成できます。
最も印象的なのは、プロセス全体がJVMに依存しないことです。つまり、オブジェクトを1つのプラットフォームでシリアル化し、完全に異なるプラットフォームで逆シリアル化できます。
クラス ObjectInputStream および ObjectOutputStream は、オブジェクトをシリアライズおよびデシリアライズするためのメソッドを含む高レベルのストリームです。
ObjectOutputStreamクラスには、さまざまなデータ型を書き込むための多くの書き込みメソッドが含まれていますが、特に1つのメソッドが際立っています-
public final void writeObject(Object x) throws IOException
上記のメソッドはオブジェクトをシリアル化し、出力ストリームに送信します。 同様に、ObjectInputStreamクラスには、オブジェクトをデシリアライズするための次のメソッドが含まれています-
public final Object readObject() throws IOException, ClassNotFoundException
このメソッドは、ストリームから次のオブジェクトを取得し、逆シリアル化します。 戻り値はオブジェクトなので、適切なデータ型にキャストする必要があります。
Javaでシリアル化がどのように機能するかを示すために、本書の早い段階で説明したEmployeeクラスを使用します。 Serializableインターフェイスを実装する次のEmployeeクラスがあるとします-
例
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 拡張子を付けます。
例
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プログラムは、SerializeDemoプログラムで作成されたEmployeeオブジェクトを逆シリアル化します。 プログラムを研究し、その出力を決定しようとする-
例
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
ここで注意すべき重要な点は次のとおりです-
- try/catchブロックは、readObject()メソッドによって宣言されたClassNotFoundExceptionをキャッチしようとします。 JVMがオブジェクトをデシリアライズできるようにするには、クラスのバイトコードを見つけられる必要があります。 JVMは、オブジェクトの逆シリアル化中にクラスを見つけられない場合、ClassNotFoundExceptionをスローします。
- readObject()の戻り値がEmployee参照にキャストされることに注意してください。
- SSNフィールドの値は、オブジェクトがシリアル化されたときは11122333でしたが、このフィールドは一時的なため、この値は出力ストリームに送信されませんでした。 デシリアライズされたEmployeeオブジェクトのSSNフィールドは0です。