どうすればJavaクラスを不変にすることができますか、不変の必要性は何ですか?これを使用する利点はありますか?
不変オブジェクトとは?
不変オブジェクトとは、インスタンス化された後に状態を変更しないオブジェクトです。
オブジェクトを不変にする方法
一般に、不変オブジェクトは、メンバーを公開せず、セッターを持たないクラスを定義することで作成できます。
次のクラスは、不変オブジェクトを作成します。
class ImmutableInt {
private final int value;
public ImmutableInt(int i) {
value = i;
}
public int getValue() {
return value;
}
}
上記の例からわかるように、ImmutableInt
の値はオブジェクトがインスタンス化されたときにのみ設定でき、ゲッター(getValue
)のみを持つことでオブジェクトの状態を変更することはできませんインスタンス化。
ただし、オブジェクトによって参照されるすべてのオブジェクトも不変でなければならないことに注意する必要があります。そうしないと、オブジェクトの状態を変更できる可能性があります。
たとえば、配列またはArrayList
への参照をゲッターから取得できるようにすると、配列またはコレクションを変更することで内部状態を変更できます。
class NotQuiteImmutableList<T> {
private final List<T> list;
public NotQuiteImmutableList(List<T> list) {
// creates a new ArrayList and keeps a reference to it.
this.list = new ArrayList(list);
}
public List<T> getList() {
return list;
}
}
上記のコードの問題は、ArrayList
をgetList
から取得して操作できるため、オブジェクト自体の状態が変更されるため、不変ではないことです。
// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));
// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");
この問題を回避する1つの方法は、ゲッターから呼び出されたときに配列またはコレクションのコピーを返すことです。
public List<T> getList() {
// return a copy of the list so the internal state cannot be altered
return new ArrayList(list);
}
不変性の利点は何ですか?
不変性の利点は並行性にあります。複数のスレッドが同じオブジェクトの状態を変更しようとする可能性があるため、可変オブジェクトの正確性を維持することは困難であり、一部のスレッドは、上記の読み取りおよび書き込みのタイミングに応じて、同じオブジェクトの異なる状態を見るオブジェクト。
不変オブジェクトを持つことにより、不変オブジェクトの状態は変わらないので、オブジェクトを見ているすべてのスレッドが同じ状態を確実に見ることができます。
すでに与えられた答えに加えて、見逃しやすい詳細(防御コピーなど)があるため、Effective Javaの不変性について読むことをお勧めします。さらに、Effective Java 2nd Ed。は、すべてのJava開発者。
次のようにクラスを不変にします:
public final class Immutable
{
private final String name;
public Immutable(String name)
{
this.name = name;
}
public String getName() { return this.name; }
// No setter;
}
Javaクラスを不変にするための要件は次のとおりです。
final
として宣言する必要があります(子クラスを作成できないように)final
として宣言する必要があります(オブジェクトの作成後にその値を変更できないようにするため)不変クラスは便利です
-スレッドセーフです。
-彼らはまた、あなたのデザインについて何か深いことを表現しています:「これを変更することはできません。」.
不変性は、主に2つの方法で実現できます。
final
インスタンス属性を使用して再割り当てを回避する不変性の利点は、これらのオブジェクトに対して行える仮定です。
不変クラスは、インスタンス化された後は値を再割り当てできません。コンストラクタは、プライベート変数に値を割り当てます。オブジェクトがnullになるまで、setterメソッドが使用できないため、値を変更できません。
不変であるためには、次の条件を満たす必要があります。
/**
* Strong immutability - by making class final
*/
public final class TestImmutablity {
// make the variables private
private String Name;
//assign value when the object created
public TestImmutablity(String name) {
this.Name = name;
}
//provide getters to access values
public String getName() {
return this.Name;
}
}
利点:不変オブジェクトには、死ぬまで初期化された値が含まれます。
Immutable classは、作成後にオブジェクトを変更できないオブジェクトです。
不変クラスは
例
文字列クラス
コード例
public final class Student {
private final String name;
private final String rollNumber;
public Student(String name, String rollNumber) {
this.name = name;
this.rollNumber = rollNumber;
}
public String getName() {
return this.name;
}
public String getRollNumber() {
return this.rollNumber;
}
}
私は英語を母国語としない人として、「不変クラス」が「構築されたクラスオブジェクトは不変」であるという一般的な解釈を嫌います。むしろ、私自身はそれを「クラスオブジェクト自体は不変である」と解釈したいと思っています。
つまり、「不変クラス」は不変オブジェクトの一種です。違いは、利益とは何かに答えるときです。私の知る限り、不変クラスは、そのオブジェクトが実行時の動作を変更するのを防ぎます。
不変オブジェクトを作成する別の方法は、 Immutables.org libraryを使用することです:
必要な依存関係が追加されたと仮定して、抽象アクセサーメソッドで抽象クラスを作成します。インターフェイスまたはアノテーション(@interface)で注釈を付けることでも同じことができます。
package info.sample;
import Java.util.List;
import Java.util.Set;
import org.immutables.value.Value;
@Value.Immutable
public abstract class FoobarValue {
public abstract int foo();
public abstract String bar();
public abstract List<Integer> buz();
public abstract Set<Long> crux();
}
生成された不変の実装を生成して使用できるようになりました。
package info.sample;
import Java.util.List;
public class FoobarValueMain {
public static void main(String... args) {
FoobarValue value = ImmutableFoobarValue.builder()
.foo(2)
.bar("Bar")
.addBuz(1, 3, 4)
.build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}}
int foo = value.foo(); // 2
List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4)
}
}