Cum se creează o clasă imuabilă în Java?

În Java, imuabilitatea înseamnă că odată ce un obiect este creat, starea sa internă nu poate fi schimbată. Clasele imuabile în Java oferă multe avantaje, cum ar fi siguranța firelor de depanare ușoară și toate. În Java toate clase de ambalare (cum ar fi Integer Boolean Byte Short) și clasa String este imuabilă. Ne putem crea și propria noastră clasă imuabilă.

În acest articol vom învăța:

  • Ce înseamnă imuabilitate
  • De ce este util
  • Cum să ne creăm propria noastră clasă imuabilă
  • De ce este importantă copierea profundă
  • Care sunt limitările pe care le au tipurile de înregistrări Java

Ce este o clasă imuabilă?

O clasă imuabilă este o clasă ale cărei obiecte nu pot fi modificate odată create. Dacă facem vreo modificare, rezultă un obiect nou. Această metodă este utilizată în aplicații concurente.

Reguli pentru crearea unei clase imuabile

  • Clasa trebuie declarată ca final astfel încât să nu poată fi create clase de copii.
  • Membrii datelor din clasă trebuie să fie declarați privat astfel încât să nu fie permis accesul direct.
  • Membrii datelor din clasă trebuie să fie declarați ca final astfel încât să nu le putem schimba valoarea după crearea obiectului.
  • Un constructor parametrizat ar trebui să inițializeze toate câmpurile efectuând a copie adâncă astfel încât membrii datelor să nu poată fi modificați cu o referință la obiect.
  • Copierea profundă a obiectelor ar trebui să fie efectuată în metodele getter pentru a returna o copie, mai degrabă decât a returna referința obiectului real.

Nota : Nu ar trebui să existe setări sau, în termeni mai simpli, nu ar trebui să existe nicio opțiune de modificare a valorii variabilei de instanță.


Exemplu: implementarea clasei imuabile

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  ;      }   }   

În acest exemplu, am creat o clasă finală numită Student. Are trei membri de date finali, un constructor parametrizat și metode getter. Vă rugăm să rețineți că aici nu există o metodă de setare. De asemenea, rețineți că nu este nevoie să efectuăm copierea profundă sau clonarea membrilor de date ai tipurilor de wrapper, deoarece acestea sunt deja imuabile.

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  ());         }   }   

Chiar și după modificarea hărții originale sau returnate, starea internă a obiectului Student rămâne neschimbată. Aceasta confirmă conceptul de imuabilitate.

Ieșire:

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


Limitarea înregistrării Java cu câmpuri mutabile

S-a introdus Java 14 înregistra . Acesta este un mod clar și concis de a defini clasele imuabile:

record Student(String name int regNo Map metadate) {}


Dar aceasta oferă doar o imuabilitate superficială. Dacă Harta este modificată extern, starea internă a înregistrării se modifică:

Hartă hartă = nou HashMap <>();

map.put('1' 'primul');


Student s = new Student(harta 'ABC' 101);


// Schimbă starea internă — NU este sigur

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

s.metadata().put('3' 'al treilea');

Nota : Folosiți înregistrarea numai dacă toate câmpurile sunt tipuri imuabile, cum ar fi String int sau alte înregistrări.