Hur man skapar oföränderlig klass i Java?

I Java betyder oföränderlighet att när ett objekt väl har skapats kan dess interna tillstånd inte ändras. Oföränderliga klasser i Java ger många fördelar som trådsäkerhet enkel felsökning och allt. I Java alla omslagsklasser (som Integer Boolean Byte Short) och klassen String är oföränderlig. Vi kan också skapa vår egen oföränderliga klass.

I den här artikeln ska vi lära oss:

  • Vad oföränderlighet betyder
  • Varför det är användbart
  • Hur man skapar vår egen oföränderliga klass
  • Varför djupkopiering är viktigt
  • Vilka är begränsningarna Java-posttyper har

Vad är en oföränderlig klass?

En oföränderlig klass är en klass vars objekt inte kan ändras när de väl har skapats. Om vi ​​gör någon modifiering resulterar det i ett nytt objekt. Denna metod används i samtidiga applikationer.

Regler för att skapa en oföränderlig klass

  • Klassen måste deklareras som slutlig så att barnklasser inte kan skapas.
  • Datamedlemmar i klassen måste deklareras privat så att direktåtkomst inte är tillåten.
  • Datamedlemmar i klassen måste deklareras som slutlig så att vi inte kan ändra deras värde efter att objekt skapats.
  • En parametriserad konstruktor bör initiera alla fält som utför a djup kopia så att datamedlemmar inte kan modifieras med en objektreferens.
  • Deep Copy av objekt bör utföras i getter-metoderna för att returnera en kopia snarare än att returnera den faktiska objektreferensen.

Notera : Det ska inte finnas några sättare eller i enklare termer bör det inte finnas något alternativ för att ändra värdet på instansvariabeln.


Exempel: Implementering av oföränderlig klass

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

I det här exemplet har vi skapat en sista klass med namnet Student. Den har tre slutliga datamedlemmar, en parametriserad konstruktor och gettermetoder. Observera att det inte finns någon sättermetod här. Observera också att vi inte behöver utföra djupkopiering eller kloning av datamedlemmar av omslagstyper eftersom de redan är oföränderliga.

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

Även efter att ha ändrat den ursprungliga eller returnerade kartan förblir det interna tillståndet för Studentobjektet oförändrat. Detta bekräftar oföränderlighetskonceptet.

Produktion:

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


Begränsning av Java-post med föränderliga fält

Java 14 introduceras spela in . Detta är ett tydligt och kortfattat sätt att definiera oföränderliga liknande klasser:

post Student(Strängnamn int regNo Map metadata) {}


Men detta erbjuder bara ytlig oföränderlighet. Om kartan ändras externt ändras postens interna tillstånd:

Karta karta = ny HashMap <>();

map.put('1' 'först');


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


// Ändrar internt tillstånd — INTE säkert

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

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

Notera : Använd endast post om alla fält är oföränderliga typer som String int eller andra poster.