Ako vytvoriť nemennú triedu v jazyku Java?

V Jave nemennosť znamená, že akonáhle je objekt vytvorený, jeho vnútorný stav sa nedá zmeniť. Nemenné triedy v Jave poskytujú mnoho výhod, ako je bezpečnosť vlákien, jednoduché ladenie a podobne. V Jave všetky obalové triedy (ako Integer Boolean Byte Short) a trieda String je nemenná. Môžeme si vytvoriť aj vlastnú nemennú triedu.

V tomto článku sa naučíme:

  • Čo znamená nemennosť
  • Prečo je to užitočné
  • Ako vytvoriť vlastnú nemennú triedu
  • Prečo je hlboké kopírovanie dôležité
  • Aké sú obmedzenia typov záznamov Java

Čo je to nemenná trieda?

Nemenná trieda je trieda, ktorej objekty sa po vytvorení nedajú zmeniť. Ak vykonáme akúkoľvek úpravu, výsledkom bude nový objekt. Táto metóda sa používa v súbežných aplikáciách.

Pravidlá pre vytvorenie nemennej triedy

  • Trieda musí byť deklarovaná ako konečná aby nebolo možné vytvárať detské triedy.
  • Dátové členy v triede musia byť deklarované súkromné takže priamy prístup nie je povolený.
  • Dátové členy v triede musia byť deklarované ako konečná aby sme po vytvorení objektu nemohli zmeniť ich hodnotu.
  • Parametrizovaný konštruktor by mal inicializovať všetky polia vykonávajúce a hlboká kópia aby údajové členy nebolo možné upravovať pomocou odkazu na objekt.
  • Hlboká kópia objektov by sa mala vykonávať v metódach getra, aby sa vrátila kópia, a nie vrátenie skutočného odkazu na objekt.

Poznámka : Nemali by existovať žiadne nastavovače alebo jednoduchšie povedané, nemala by existovať možnosť zmeniť hodnotu premennej inštancie.


Príklad: Implementácia nemennej triedy

Študent.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  ;      }   }   

V tomto príklade sme vytvorili konečnú triedu s názvom Študent. Má tri konečné dátové členy, parametrizovaný konštruktor a metódy getra. Upozorňujeme, že tu neexistuje žiadna metóda nastavenia. Všimnite si tiež, že nemusíme vykonávať hlboké kopírovanie alebo klonovanie údajových členov typov wrapperov, pretože sú už nemenné.

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

Aj po úprave pôvodnej alebo vrátenej mapy zostáva vnútorný stav objektu Študent nezmenený. To potvrdzuje koncept nezmeniteľnosti.

výstup:

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


Obmedzenie záznamu Java s meniteľnými poliami

Predstavená Java 14 záznam . Toto je jasný a stručný spôsob, ako definovať nemenné podobné triedy:

record Student(String name int regNo Map metadáta) {}


To však ponúka len plytkú nemennosť. Ak je mapa upravená externe, vnútorný stav záznamu sa zmení:

Mapa mapa = nová HashMap <>();

map.put('1' 'prvý');


Študent s = new Student('ABC' 101 map);


// Zmení interný stav — NIE JE bezpečné

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

s.metadata().put('3' 'tretia');

Poznámka : Použite záznam len vtedy, ak sú všetky polia nemenného typu, ako napríklad String int alebo iné záznamy.