Effective Java 第 2 版:第 4 章 項目 15

項目 14: 可変性を最小限にする

この項目では、不変クラスの作り方に関して説明されている。

不変クラスは、生成したインスタンスの状態を変更できないようなクラスのことである。 String, 基本データクラス(BigInteger なども)は不変クラスである。

例えば、

String str = "foobar";

のように String 型のインスタンス str は、文字列 "foobar" を状態として持っているといえる。 str が持つ文字列 "foobar" を変更して、新たな文字列を持たせることはできない。

不変クラスの利点

生成時からの状態を保ち、後から状態を変更できない不変クラスには、以下のような利点がある。

  1. 単純で扱いやすい
  2. スレッドセーフである
  3. 防御的コピーが必要ない
  4. 複数のオブジェクト間で状態を共有できる
  5. マップやセットなど、他のオブジェクトで利用しやすい

不変クラスの欠点

個々の異なる状態に対して、異なるオブジェクトを生成する必要があることが欠点である。 例えば、以下のような場合を考える。

String str1 = "a...(100個続く)...a";
String str2 = "a...(100個続く)...b";

このとき、一文字違いの str1str2 はそれぞれ異なるインスタンスとなる。

クラスを不変にするための五か条

  1. オブジェクトの状態を変更できるメソッドを提供しない
    • いわゆる setter など。このようなメソッドはミューテータと呼ばれる
  2. クラスを拡張できないようにする
    • サブクラスで不変性を破られることを防ぐ
  3. すべてのフィールドを final にする
  4. すべてのフィールドを private にする
  5. 可変オブジェクトを持つ場合、その不変クラスだけがアクセスできるようにする
    • クライアントの勝手な初期化、オブジェクト参照を返すメソッドはダメ

ここで、2 を実現する方法は 2 通りある。 一つ目は、単純にクラスに final を付け、拡張を禁止する方法である。 二つ目は、コンストラクタを private かパッケージプライベートにして、コンストラクタからオブジェクトを生成できないようにし、static ファクトリーメソッドを持たせる方法である。 項目 1 での議論より、二つ目の方がより柔軟である。

参考文献

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)