Hvordan lage uforanderlig klasse i Java?

I Java betyr uforanderlighet at når et objekt er opprettet, kan dets interne tilstand ikke endres. Uforanderlige klasser i Java gir mange fordeler som trådsikkerhet enkel feilsøking og alt. I Java alle innpakningsklasser (som Integer Boolean Byte Short) og String-klassen er uforanderlig. Vi kan også lage vår egen uforanderlige klasse.

I denne artikkelen skal vi lære:

  • Hva uforanderlighet betyr
  • Hvorfor det er nyttig
  • Hvordan lage vår egen uforanderlige klasse
  • Hvorfor dypkopiering er viktig
  • Hva er begrensningene Java-posttyper har

Hva er en uforanderlig klasse?

En uforanderlig klasse er en klasse hvis objekter ikke kan endres når de først er opprettet. Hvis vi gjør noen modifikasjon, resulterer det i et nytt objekt. Denne metoden brukes i samtidige applikasjoner.

Regler for å opprette en uforanderlig klasse

  • Klassen skal erklæres som endelig slik at barneklasser ikke kan opprettes.
  • Datamedlemmer i klassen må deklareres privat slik at direkte tilgang ikke er tillatt.
  • Datamedlemmer i klassen må deklareres som endelig slik at vi ikke kan endre verdien etter objektoppretting.
  • En parameterisert konstruktør bør initialisere alle feltene som utfører en dyp kopi slik at datamedlemmer ikke kan endres med en objektreferanse.
  • Deep Copy av objekter bør utføres i getter-metodene for å returnere en kopi i stedet for å returnere den faktiske objektreferansen.

Note : Det skal ikke være noen settere, eller i enklere termer bør det ikke være noe alternativ for å endre verdien av instansvariabelen.


Eksempel: Implementering av uforanderlig klasse

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 dette eksemplet har vi laget en siste klasse kalt Student. Den har tre endelige datamedlemmer, en parameterisert konstruktør og gettermetoder. Vær oppmerksom på at det ikke er noen settermetode her. Vær også oppmerksom på at vi ikke trenger å utføre dypkopiering eller kloning av datamedlemmer av innpakningstyper siden de allerede er uforanderlige.

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

Selv etter modifisering av det originale eller returnerte kartet forblir den interne tilstanden til Student-objektet uendret. Dette bekrefter uforanderlighetskonseptet.

Produksjon:

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


Begrensning av Java-post med Mutable Fields

Java 14 introdusert rekord . Dette er en klar og kortfattet måte å definere uforanderlige som klasser:

post Student(Strengnavn int regNo Map metadata) {}


Men dette gir bare grunn uforanderlighet. Hvis kartet endres eksternt, endres den interne tilstanden til posten:

Kart kart = nytt HashMap <>();

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


Student s = ny Student('ABC' 101 kart);


// Endrer intern tilstand — IKKE trygt

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

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

Note : Bruk post bare hvis alle felt er uforanderlige typer som String int eller andre poster.