Javaのオブジェクトシリアライゼーションについて説明します。
オブジェクトシリアライゼーションは、オブジェクトをバイトシーケンスに変換することです。これらのバイトシーケンスにはオブジェクトのデータと情報が含まれており、ファイルやデータベースに保存したり、ネットワークを介して送信したりするために使用されます。キャッシュやリモートプロシージャコールなどの用途で、エンティティクラスをSerializableインターフェースを実装させることでシリアライズ可能にしています。
シリアライズの最終的な目的は、元のJavaオブジェクトに戻すことです。このプロセスはデシリアライズと呼ばれ、シリアライズされたバイトシーケンスから元のオブジェクトを復元できます。
transientキーワードについて
transientキーワードは、修飾されたメンバー変数がシリアライズされないようにする機能を持っています。
あるオブジェクトの特定のフィールドがシリアライズされないべきである場合、以下のような状況があります:
- 他のフィールドから推測できる値である場合。例えば、長方形クラスがあり、そのフィールドが長さ、幅、面積を持っているとすると、面積は長さと幅から計算できるため、シリアライズする必要はありません。
- ビジネスロジックによって特定のフィールドをシリアライズしたくない場合。
HashMapのソースコードを見ると、modCountというフィールドがtransientで修飾されています。これは意味があります。modCountはHashMapが変更された回数を追跡するために使用されますが、これはシリアライズする必要はありません。なぜなら、最初は0や他の任意の値でも問題ありません。
/**
* このHashMapが構造的に変更された回数
* 構造的な変更とは、HashMap内のマッピングの数を変更したり、内部構造を変更したりすること(再ハッシュなど)です。
* このフィールドは、HashMapのコレクションビューに対するイテレータのfail-fast動作を可能にします(ConcurrentModificationException参照)。
*/
transient int modCount;
transientを使用することで、ストレージスペースを節約できます。
例
以下のコードは、transientキーワードの使用例です。
package example;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Box implements Serializable {
private static final long serialVersionUID = 123456789L;
private Integer length;
private Integer width;
private transient Integer area;
public Box(Integer length, Integer width) {
this.length = length;
this.width = width;
this.area = length * width;
}
public void calculateArea() {
this.area = this.length * this.width;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("length: ").append(this.length).append("\n");
sb.append("width: ").append(this.width).append("\n");
sb.append("area: ").append(this.area).append("\n");
return sb.toString();
}
}
public class TransientDemo {
public static void main(String[] args) throws Exception {
Box box = new Box(5, 10);
System.out.println("1. オリジナルオブジェクト:\n" + box);
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("box"))) {
out.writeObject(box);
}
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("box"))) {
Box deserializedBox = (Box) in.readObject();
System.out.println("2. デシリアライズ後のオブジェクト:\n" + deserializedBox);
deserializedBox.calculateArea();
System.out.println("3. 元のオブジェクトに復元:\n" + deserializedBox);
}
}
}
結果:
1. オリジナルオブジェクト: length: 5 width: 10 area: 50 2. デシリアライズ後のオブジェクト: length: 5 width: 10 area: null 3. 元のオブジェクトに復元: length: 5 width: 10 area: 50