Hvordan opretter man uforanderlig klasse i Java?

I Java betyder uforanderlighed, at når først et objekt er oprettet, kan dets interne tilstand ikke ændres. Uforanderlige klasser i Java giver mange fordele som trådsikkerhed nem fejlfinding og det hele. I Java alle indpakningsklasser (som Integer Boolean Byte Short) og String-klassen er uforanderlig. Vi kan også skabe vores egen uforanderlige klasse.

I denne artikel vil vi lære:

  • Hvad uforanderlighed betyder
  • Hvorfor det er nyttigt
  • Hvordan man skaber vores egen uforanderlige klasse
  • Hvorfor dyb kopiering er vigtig
  • Hvilke begrænsninger har Java-posttyper

Hvad er en uforanderlig klasse?

En uforanderlig klasse er en klasse, hvis objekter ikke kan ændres, når de først er oprettet. Hvis vi foretager en ændring, resulterer det i et nyt objekt. Denne metode bruges i samtidige applikationer.

Regler for oprettelse af en uforanderlig klasse

  • Klassen skal erklæres som endelig så der ikke kan oprettes børneklasser.
  • Datamedlemmer i klassen skal deklareres privat så direkte adgang ikke er tilladt.
  • Datamedlemmer i klassen skal erklæres som endelig så vi ikke kan ændre deres værdi efter objektskabelse.
  • En parametriseret konstruktør bør initialisere alle de felter, der udfører en dyb kopi så datamedlemmer ikke kan ændres med en objektreference.
  • Dyb kopi af objekter bør udføres i getter-metoderne for at returnere en kopi i stedet for at returnere den faktiske objektreference.

Note : Der bør ikke være nogen sættere, eller i enklere vendinger bør der ikke være nogen mulighed for at ændre værdien af ​​instansvariablen.


Eksempel: Implementering af 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 eksempel har vi lavet en sidste klasse med navnet Studerende. Den har tre endelige datamedlemmer, en parameteriseret konstruktør og getter-metoder. Bemærk venligst, at der ikke er nogen sættermetode her. Bemærk også, at vi ikke behøver at udføre dyb kopiering eller kloning af datamedlemmer af indpakningstyper, da 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 efter ændring af det originale eller returnerede kort forbliver den interne tilstand af Student-objektet uændret. Dette bekræfter uforanderlighedsbegrebet.

Produktion:

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


Begrænsning af Java-record med Mutable Fields

Java 14 introduceret optage . Dette er en klar og kortfattet måde at definere uforanderlige lignende klasser:

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


Men dette giver kun overfladisk uforanderlighed. Hvis kortet ændres eksternt, ændres registreringens interne tilstand:

Kort kort = nyt HashMap <>();

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


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


// Ændrer intern tilstand — IKKE sikker

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

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

Note : Brug kun post, hvis alle felter er uforanderlige typer som String int eller andre poster.