読者です 読者をやめる 読者になる 読者になる

うさがにっき

読書感想文とプログラムのこと書いてきます

シリアライズ、デシリアライズについて

Android Java

概要

Preferenceなどに保存するときにオブジェクトがシリアライズしてある必要がある
このシリアライズが実際に何をしているかを説明する

詳細

シリアライズ(Serialize)とは、オブジェクトのような構造データをバイト単位で読み書きできるバイト配列に変換することを言う
オブジェクトをファイルに保存したり、ネットワーク経由でオブジェクトを交換する際などに利用する
シリアライズされたバイト列を元のオブジェクトに戻すことをデシリアライズという

シリアライズの条件

  • Serializableインタフェースを実装していること
  • インタンスフィールドは基本型、もしくはシリアライズ可能な型であること
  • (基底クラスがシリアライズ不可の場合)基底クラスが引数のないpublicコンストラクタを持っていること

Serializableインタフェースは、マーカインタフェースとも呼ばれ、シリアライズが可能であることを明示的に示すことをだけを目的としている
そのため、実装すべきメソッドは持っていない

public class Book implements Serializable {
    private static fianl long serialVersionUID = xxxxxxxxxxxxxxxxL;
    private String title;
    private int price;
    private transient boolean deleted;     // Serializeから除外

特定のフィールドをシリアライズの対象から外したいときには、transient修飾子を付与する
また、シリアルバージョンUIDがシリアライズ側とデシリアライズ側で異なるバージョンのクラスを利用している場合に例外を発生させることができる
このためクラスの構造を変更するためにシリアルバージョンUIDは更新すべき

逆にシリアルバージョンをを管理しない場合には以下のように記載すべき

@SuppressWarnings("serial")
public class Bokks implements Sereializable {

シリアライズ形式のカスタマイズ

シリアライズは便利な仕組みで、デフォルトの挙動にそうだけであれば、ごく簡単に実装できる
しかし、シリアライズを行うとパッケージプライベート,privateのインスタンスフィールドまで含めて内部実装がそのまま「公開」扱いになる
内部実装を公開するということは、諸般の内部実装を将来的に変更しないという責任を負うことになる
オブジェクトの内部実装が将来的に変更になる可能性があり、その中でシリアライズ形式の一貫性を維持したいならば、シリアライズ対象のクラスに対してreadObject/writeObjectを実装する

// 対象オブジェクトをシリアライズ処理から除外
private transient Object[] elementData;

private void writeObject(java.io.ObjectOutputStream s) 
	throws java.io.IOException{

	// デフォルトのシリアライズ処理を実施
	s.defaltWriteObject;

	s.writeInt(elementData.length);

	for(int i = 0; i<size; i++) {
		s.writeObject(elementData[i]);
	}

}

private void readObject(java.io.ObjectOutputStream s) 
	throws java.io.IOException, ClassNotFoundException {

	// デフォルトのデシリアライズ処理を実施
	s.defaltReadObject();

	int arrayLength = s.readInt();
	Object[] a = elementData = new Object[arrayLength];

	for(int i = 0; i<size; i++) {
		a[i] = s.readObject();
	}
}

参考

AndroidエンジニアのためのモダンJava

AndroidエンジニアのためのモダンJava