Javaクラスを不変にするにはどうすればよいですか?不変性の必要性は何ですか?これを使用する利点はありますか?
Javaクラスを不変にするにはどうすればよいですか?不変性の必要性は何ですか?これを使用する利点はありますか?
回答:
不変オブジェクトとは何ですか?
不変オブジェクトとは、インスタンス化された後も状態が変化しないオブジェクトです。
オブジェクトを不変にする方法は?
一般に、不変オブジェクトは、メンバーが公開されておらず、セッターも含まれていないクラスを定義することで作成できます。
次のクラスは不変オブジェクトを作成します。
class ImmutableInt {
private final int value;
public ImmutableInt(int i) {
value = i;
}
public int getValue() {
return value;
}
}
上記の例に見られるように、ImmutableInt
canの値はオブジェクトがインスタンス化されたときにのみ設定でき、ゲッター(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);
}
不変性の利点は何ですか?
不変性の利点は同時実行性にあります。複数のスレッドが同じオブジェクトの状態を変更しようとしている可能性があるため、可変オブジェクトの正確性を維持することは困難です。これにより、一部のスレッドは、そのオブジェクトへの読み取りと書き込みのタイミングに応じて、同じオブジェクトの異なる状態を認識します。オブジェクト。
不変オブジェクトを使用することで、不変オブジェクトの状態が変化しないため、オブジェクトを参照しているすべてのスレッドに同じ状態が表示されるようにすることができます。
return Collections.unmodifiableList(list);
の読み取り専用ビューを返すこともできます。
final
ません。それ以外の場合は、setterメソッド(または他の種類の変更メソッドと変更可能フィールド)を使用して拡張できます。
final
、クラスにprivate
フィールドしかない場合は、そうである必要はありません。
すでに与えられた答えに加えて、Effective Java、第2版の不変性について読むことをお勧めします。これは、見落としがちな詳細(防御コピーなど)があるためです。さらに、Effective Java 2ndEd。すべての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になるまで値を変更できません。
不変であるためには、次の条件を満たす必要があります。
/**
* 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;
}
}
利点:不変オブジェクトには、消滅するまで初期化された値が含まれます。
不変クラスは、作成後にオブジェクトを変更できないです。
不変クラスは
例
文字列クラス
コード例
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;
}
}
どうすればJavaクラスを不変にすることができますか?
JEP359を搭載したJDK14 +からは、「records
」を使用できます。これは、Immutableクラスを作成するための最も簡単で手間のかからない方法です。
レコードクラスは、レコードの説明を提供するレコードと呼ばれる固定されたフィールドセットの、浅く不変で透過的なキャリアです。それぞれを生じさせる提供された値とANを保持するフィールドcomponents
state
component
final
accessor
、値を取得するためのメソッドを生成します。フィールド名とアクセサー名は、コンポーネントの名前と一致します。
不変の長方形を作成する例を考えてみましょう
record Rectangle(double length, double width) {}
コンストラクターを宣言する必要はなく、equals&hashCodeメソッドを実装する必要もありません。すべてのレコードには、名前と状態の説明が必要です。
var rectangle = new Rectangle(7.1, 8.9);
System.out.print(rectangle.length()); // prints 7.1
オブジェクトの作成中に値を検証する場合は、コンストラクターを明示的に宣言する必要があります。
public Rectangle {
if (length <= 0.0) {
throw new IllegalArgumentException();
}
}
レコードの本体は、静的メソッド、静的フィールド、静的初期化子、コンストラクター、インスタンスメソッド、およびネストされた型を宣言できます。
インスタンスメソッド
record Rectangle(double length, double width) {
public double area() {
return this.length * this.width;
}
}
静的フィールド、メソッド
状態はコンポーネントの一部である必要があるため、インスタンスフィールドをレコードに追加することはできません。ただし、静的フィールドとメソッドを追加することはできます。
record Rectangle(double length, double width) {
static double aStaticField;
static void aStaticMethod() {
System.out.println("Hello Static");
}
}
不変性の必要性とは何ですか?これを使用する利点はありますか?
以前に投稿された回答は、不変性の必要性を正当化するのに十分であり、それは長所です
不変オブジェクトを作成する別の方法は、Immutables.orgライブラリを使用することです。
必要な依存関係が追加されたと仮定して、抽象アクセサーメソッドを使用して抽象クラスを作成します。インターフェイスまたはアノテーション(@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)
}
}
不変クラスは、インスタンスを変更できないクラスです。
各インスタンスに含まれるすべての情報はオブジェクトの存続期間中固定されているため、変更を確認することはできません。
不変クラスは、可変クラスよりも設計、実装、および使用が簡単です。
クラスを不変にするには、次の5つのルールに従います。
オブジェクトの状態を変更するメソッドを提供しないでください
クラスを拡張できないことを確認してください。
すべてのフィールドを最終的にします。
すべてのフィールドを非公開にします。
変更可能なコンポーネントへの排他的アクセスを確保します。
不変オブジェクトは本質的にスレッドセーフです。それらは同期を必要としません。
不変オブジェクトは自由に共有できます。
不変オブジェクトは、他のオブジェクトの優れた構成要素になります
ここでの答えのほとんどは良いものであり、ルールについて言及しているものもありますが、これらのルールに従う必要がある理由と時期を言葉で表現するのは良いことだと思います。だから以下の説明をしています
そしてもちろん、これらの最終変数にSetterを使用しようとすると、コンパイラーはエラーをスローします。
public class ImmutableClassExplored {
public final int a;
public final int b;
/* OR
Generally we declare all properties as private, but declaring them as public
will not cause any issues in our scenario if we make them final
public final int a = 109;
public final int b = 189;
*/
ImmutableClassExplored(){
this. a = 111;
this.b = 222;
}
ImmutableClassExplored(int a, int b){
this.a = a;
this.b= b;
}
}
クラスを「final」として宣言する必要がありますか?
1.プリミティブメンバーのみを持つ:問題はありませんクラスにプリミティブメンバーしかない場合、クラスをfinalとして宣言する必要はありません。
2.オブジェクトをメンバー変数として持つ:オブジェクトをメンバー変数として持つ場合、それらのオブジェクトのメンバーも最終的なものにする必要があります。つまり、ツリーの奥深くをトラバースし、すべてのオブジェクト/プリミティブを最終的なものにする必要がありますが、これは常に可能であるとは限りません。したがって、回避策は、継承を防ぐクラスをfinalにすることです。したがって、サブクラスがゲッターメソッドをオーバーライドすることに疑問の余地はありません。
Lombokの@Valueアノテーションを使用して、不変のクラスを生成できます。以下のコードと同じくらい簡単です。
@Value
public class LombokImmutable {
int id;
String name;
}
ロンボクのサイトのドキュメントによると:
@Valueは@Dataの不変のバリアントです。デフォルトでは、すべてのフィールドがプライベートおよびファイナルになり、セッターは生成されません。不変性はサブクラスに強制できるものではないため、クラス自体もデフォルトでfinalになります。@Dataと同様に、便利なtoString()、equals()、hashCode()メソッドも生成され、各フィールドはgetterメソッドを取得し、すべての引数(フィールド宣言で初期化される最終フィールドを除く)をカバーするコンストラクターも生成されます。 。
完全に機能する例はここにあります。
record
使用するのですか?