logo

Javaで不変クラスを作成するには?

Java では、不変性とは、オブジェクトが作成されると、その内部状態を変更できないことを意味します。 Java の不変クラスには、スレッドの安全性、デバッグの容易さなど、多くの利点があります。 Javaではすべて ラッパークラス (Integer Boolean Byte Short と同様)、String クラスは不変です。独自の不変クラスを作成することもできます。

この記事では次のことを学びます。



  • 不変性の意味
  • なぜ役に立つのか
  • 独自の不変クラスを作成する方法
  • ディープコピーが重要な理由
  • Java レコード タイプにはどのような制限がありますか

不変クラスとは何ですか?

不変クラスは、オブジェクトが一度作成されると変更できないクラスです。何らかの変更を加えると、新しいオブジェクトが作成されます。この方法は、同時アプリケーションで使用されます。

不変クラスを作成するためのルール

  • クラスは次のように宣言する必要があります ファイナル 子クラスを作成できないようにします。
  • クラス内のデータ メンバーは宣言する必要があります プライベート そのため、直接アクセスは許可されません。
  • クラス内のデータ メンバーは次のように宣言する必要があります。 ファイナル そのため、オブジェクトの作成後に値を変更することはできません。
  • パラメーター化されたコンストラクターは、次の処理を実行するすべてのフィールドを初期化する必要があります。 ディープコピー そのため、オブジェクト参照を使用してデータ メンバーを変更することはできません。
  • オブジェクトのディープ コピーは、実際のオブジェクト参照を返すのではなく、ゲッター メソッドで実行してコピーを返す必要があります。

注記 : セッターがあってはなりません。簡単に言えば、インスタンス変数の値を変更するオプションがあってはなりません。

CSVファイルをJavaから読み込む




例: 不変クラスの実装

Student.java

Java
// Java Program to Create An Immutable Class import java.util.HashMap; import java.util.Map; // declare the class as final final class Student {  // make fields private and final  private final String name;  private final int regNo;  private final Map<String String> metadata;  // initialize all fields via constructor  public Student(String name int regNo Map<String String> metadata) {  this.name = name;  this.regNo = regNo;  // deep copy of mutable object (Map)  Map<String String> tempMap = new HashMap<>();  for (Map.Entry<String String> entry : metadata.entrySet()) {  tempMap.put(entry.getKey() entry.getValue());  }  this.metadata = tempMap;  }  // only provide getters (no setters)  public String getName() {  return name;  }  public int getRegNo() {  return regNo;  }  // return deep copy to avoid exposing internal state  public Map<String String> getMetadata() {  Map<String String> tempMap = new HashMap<>();  for (Map.Entry<String String> entry : this.metadata.entrySet()) {  tempMap.put(entry.getKey() entry.getValue());  }  return tempMap;  } } 

この例では、という名前の最終クラスを作成しました。 学生。 これには、パラメーター化されたコンストラクターとゲッター メソッドという 3 つの最終データ メンバーがあります。ここには setter メソッドがないことに注意してください。また、ラッパー型のデータ メンバーはすでに不変であるため、ディープ コピーやクローン作成を実行する必要がないことにも注意してください。



Geeks.java:

Java
import java.util.HashMap; import java.util.Map; public class Geeks {  public static void main(String[] args) {  // create a map and adding data  Map<String String> map = new HashMap<>();  map.put('1' 'first');  map.put('2' 'second');  // create an immutable Student object  Student s = new Student('GFG' 101 map);  // accessing data  System.out.println(s.getName());   System.out.println(s.getRegNo());   System.out.println(s.getMetadata());   // try to modify the original map  map.put('3' 'third');  System.out.println(s.getMetadata());   // try to modify the map returned by getMetadata()  s.getMetadata().put('4' 'fourth');  System.out.println(s.getMetadata());   } } 

元の Map または返された Map を変更した後でも、Student オブジェクトの内部状態は変更されません。これは不変性の概念を裏付けています。

出力:

GFG  
101
{1=first 2=second}
{1=first 2=second}
{1=first 2=second}


可変フィールドを含む Java レコードの制限

Java 14の導入 記録 。これはクラスのような不変を定義する明確かつ簡潔な方法です。

レコード Student(String name int regNo Mapメタデータ) {}


プログラムとスクリプトの違い

しかし、これは浅い不変性しか提供しません。マップが外部から変更されると、レコードの内部状態が変わります。

地図マップ = 新しいハッシュマップ<>();

map.put('1' '最初');


Student s = new Student('ABC' 101 マップ);


// 内部状態を変更します — 安全ではありません

map.put('2' '秒');

s.metadata().put('3' '3 番目');

JavaScriptのトリム

注記 : すべてのフィールドが String int または他のレコードのような不変型である場合にのみ、レコードを使用します。