Javaのtransientキーワードについて

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

タグ: Java シリアライズ transient オブジェクト デシリアライズ

10月3日 18:06 投稿