Jak vytvořit neměnnou třídu v Javě?

V Javě neměnnost znamená, že jakmile je objekt vytvořen, jeho vnitřní stav nelze změnit. Neměnné třídy v Javě poskytují mnoho výhod, jako je bezpečnost vláken, snadné ladění a tak dále. V Javě všechny obalové třídy (jako Integer Boolean Byte Short) a třída String je neměnná. Můžeme si také vytvořit vlastní neměnnou třídu.

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

  • Co znamená neměnnost
  • Proč je to užitečné
  • Jak vytvořit vlastní neměnnou třídu
  • Proč je hluboké kopírování důležité
  • Jaká jsou omezení typů záznamů Java

Co je neměnná třída?

Neměnná třída je třída, jejíž objekty nelze po vytvoření změnit. Pokud provedeme jakoukoli úpravu, výsledkem je nový objekt. Tato metoda se používá v souběžných aplikacích.

Pravidla pro vytvoření neměnné třídy

  • Třída musí být deklarována jako finále aby nebylo možné vytvářet dětské třídy.
  • Datové členy ve třídě musí být deklarovány soukromé takže přímý přístup není povolen.
  • Datové členy ve třídě musí být deklarovány jako finále abychom po vytvoření objektu nemohli změnit jejich hodnotu.
  • Parametrizovaný konstruktor by měl inicializovat všechna pole provádějící a hluboká kopie takže datové členy nelze upravit pomocí odkazu na objekt.
  • Hluboké kopírování objektů by se mělo provádět v metodách získávání, aby se vrátila kopie spíše než vracení skutečného odkazu na objekt.

Poznámka : Neměli by existovat žádné nastavovače nebo jednodušeji řečeno, neměla by existovat možnost změnit hodnotu proměnné instance.


Příklad: Implementace neměnné třídy

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

V tomto příkladu jsme vytvořili finální třídu s názvem Student. Má tři koncové datové členy, parametrizovaný konstruktor a metody getru. Vezměte prosím na vědomí, že zde neexistuje žádná metoda nastavení. Všimněte si také, že nemusíme provádět hluboké kopírování nebo klonování datových členů typů wrapperů, protože jsou již neměnné.

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

I po úpravě původní nebo vrácené mapy zůstává vnitřní stav objektu Student nezměněn. To potvrzuje koncept neměnnosti.

výstup:

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


Omezení záznamu Java s proměnlivými poli

Představena Java 14 záznam . Toto je jasný a stručný způsob, jak definovat neměnné podobné třídy:

record Student(název řetězce int regNo Map metadata) {}


To ale nabízí pouze mělkou neměnnost. Pokud je mapa upravena externě, vnitřní stav záznamu se změní:

Mapa mapa = nová HashMap <>();

map.put('1' 'první');


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


// Změní vnitřní stav — NENÍ bezpečný

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

s.metadata().put('3' 'třetí');

Poznámka : Použijte záznam pouze v případě, že všechna pole jsou neměnného typu, jako je String int nebo jiné záznamy.