シリアライズ
コンピュータプログラミングにおいて、シリアライズ、もしくはシリアル化 (serialize) という用語は、次のような異なる2つの意味を有する。
- ある一つの資源を、複数の主体が利用しようとするときに、それを調整(同期)して、一つの時点では一つの主体だけがそれを利用するようにすること。この意味では逐次化という訳語が用いられる。対義語は並列化である。
- ある環境に存在しているオブジェクトをバイト列やXMLフォーマットに変換すること。この意味では直列化という訳語が用いられる。同義語にMarshallingがある。対義語は直列化復元ないしデシリアライズである。
シリアライズの名詞形はシリアライゼーション (serialization)である。
目次
概要
逐次化
第一の意味の逐次化(ちくじか)は、主としてマルチスレッドプログラミングにおいて使われる用語で、この場合、ある資源が複数のスレッドから同時にアクセスを受け付けられるようになっていないとき、つまりマルチスレッド対応でないときに、マルチスレッド環境からもその資源を利用できるようにするために、同時のアクセス要求が起こったときには、それぞれのスレッドが順番にその資源を利用するように調整することをいう。一般には、これはその資源をロックできたひとつのスレッドのみがその資源の利用権を得、ロック中には他のスレッドはその資源をロックできない機構(排他制御)を用いるか、要求をキューに入れ、順次取り出して処理することにより実現される。 テンプレート:Main
直列化
第二の意味の直列化(ちょくれつか)は、オブジェクト指向プログラミングにおいて使われる用語で、ある環境において存在しているオブジェクトを、バイト列やXMLフォーマットに変換することをいう。より具体的には、そのオブジェクトの状態を表す変数(フィールド)と、場合によってはオブジェクトの種類(クラス)を表すなんらかの識別子を、ファイル化できるようなバイト列やXMLフォーマットの形に書き出すことをいう。これにより、オブジェクトの表すデータを、ファイルとしてセーブしたり、ネットワークで送信したりすることができるようになる。このようにして得られたバイト列やXMLフォーマットは、直列化復元ないしデシリアライズによって、元のオブジェクトに復元される。
また、オブジェクトを直列化してファイルなどの永続記憶に保存することを永続化という。
Javaにおけるシリアライズ(直列化)
Javaのシリアライズは直列化(第二の意味)で用いられる。
このシリアライズは、デザインパターンのひとつMemento パターンによる状態のスナップショット取得のほかJava RMIでネットワーク越しの外部メソッド呼び出しを行うときなどに使われている。
シリアライズは、SFなどに登場する転送装置に喩えられることがある。物質を一旦量子に変換してから遠隔地に転送し再び物質に戻すというテレポーテーションがシリアライズに似ていることからそう喩えられた。これはまさに、他のネットワーク上にあるシリアライズされたオブジェクトをファイルとしてリモートから転送してからデシリアライズして外部メソッドを自分のネットワーク上で呼び出すために利用されるJava RMIの動作原理にも似ている。
シリアライズ可能なクラスの実装
Java言語では直列化したいクラスにテンプレート:Javadoc:SEまたはテンプレート:Javadoc:SEインタフェースを実装することで、そのクラスのオブジェクトは直列化できるクラスを作ることができる。これらのインタフェースのうち、テンプレート:Javadoc:SEはマーカーインタフェースと呼ばれる、メソッド宣言がないものである。
テンプレート:Javadoc:SEを実装しているクラスのフィールドは、transient, static指定が無い限り、自動的にシリアライズによる保存対象にされる。テンプレート:Javadoc:SEを実装しているクラスでは、テンプレート:Javadoc:SE , テンプレート:Javadoc:SEメソッドをオーバーライドして手動で保存したいフィールドを指定する必要がある。
Serializable
import java.io.Serializable; public class SerializableObject implements Serializable { private String name; //シリアライズのとき保存される。 static String staticField; //クラス変数は無視される。 private transient int hashCode; //transientキーワードが付いたフィールドは無視される。 //シリアライズしたいクラスの実装... }
Externalizable
import java.io.Externalizable;
import java.io.ObjectOutput;
import java.io.ObjectInput;
public class SerializableObject implements Externalizable {
private String name; //writeExternal(ObjectOutput)で指定されているため保存されるフィールド。
private int id; //無視される。
private int hashCode; //writeExternal(ObjectOutput)で指定されているため保存されるフィールド。
//Externalizableで定義されているメソッドを[[オーバーライド]]。
//保存したいフィールドを指定する。
@Override public void writeExternal(ObjectOutput out) {
out.writeChars(this.name);
out.writeInt(this.hashCode);
}
//復元したいフィールドを指定する。
@Override public void readExternal(ObjectInput in) {
this.name = in.readLine();
this.hashCode = in.readInt();
}
//シリアライズしたいクラスの実装
}
ストリーム固有識別子
private static final long serialVersionUID = 3487495895819393L;
のように、ストリーム固有識別子を宣言することにより、クラスの実装が変わった場合でも、同一のストリーム固有識別子を持つクラスは、互換性があることを意味する。ストリーム固有識別子を明示的に宣言していない時は、バイトストリームのシグニチャー(SHA-1)から自動生成される。
シリアライズする方法
バイナリファイルにシリアライズ
これらのオブジェクトをテンプレート:Javadoc:SEやテンプレート:Javadoc:SEによりファイルなどに出力する。
import java.io.FileOutputStream; import java.io.OutputStream; import java.io.ObjectOutputStream; //... SerializableObject object = new SerializableObject(); OutputStream outputStream = new FileOutputStream("serializableObject.obj"); ObjectOutputStream objectOutputStream= new ObjectOutputStream(outputStream); objectOutputStream.writeObject(object);
XMLフォーマットにシリアライズ
import java.io.FileOutputStream; import java.io.OutputStream; import java.beans.XMLEncoder; //... SerializableObject object = new SerializableObject(); OutputStream outputStream = new FileOutputStream("serializableObject.xml"); XMLEncoder xmlEncoder= new XMLEncoder(outputStream); xmlEncoder.writeObject(object);
デシリアライズする方法
これらを再びオブジェクトに復元(デシリアライズ)するにはテンプレート:Javadoc:SEやテンプレート:Javadoc:SEを用いる。
バイナリファイルから復元
import java.io.FileInputStream; import java.io.InputStream; import java.io.ObjectInputStream; //... InputStream inputStream = new FileInputStream("serializableObject.obj"); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); SerializableObject object = (SerializableObject) objectInputStream.readObject();
XMLフォーマットファイルから復元
import java.io.FileInputStream; import java.io.InputStream; import java.beans.XMLDecoder; //... InputStream fileInputStream = new FileInputStream("serializableObject.xml"); XMLDecoder decoder = new XMLDecoder(fileInputStream); SerializableObject object = (SerializableObject) decoder.readObject();
transientキーワード
Javaにはtransientというキーワードを用いて、オブジェクト内でシリアライズしたくないフィールドをシリアライズするときに除外することができる。これにより無駄な情報によってシリアライズされたファイルの肥大化を押さえ軽量化し、シリアライズ、デシリアライズを高速化することができる。
public class SerializableObject implements Serializable { private String name; //シリアライズするときに保存されるフィールド。 private transient int hashCode; //シリアライズするときに無視されるフィールド。 }