Како направити непроменљиву класу у Јави?

У Јави непроменљивост значи да када се објекат креира, његово унутрашње стање не може да се промени. Непроменљиве класе у Јави пружају многе предности као што је сигурност нити, лако отклањање грешака и све остало. У Јави све класе омотача (као Интегер Боолеан Бите Схорт) и класа Стринг је непроменљива. Можемо креирати и сопствену непроменљиву класу.

У овом чланку ћемо научити:

  • Шта значи непроменљивост
  • Зашто је корисно
  • Како да створимо сопствену непроменљиву класу
  • Зашто је дубоко копирање важно
  • Која ограничења имају типови Јава записа

Шта је непроменљива класа?

Непроменљива класа је класа чији објекти се не могу мењати када се једном креирају. Ако урадимо било какву модификацију, то резултира новим објектом. Овај метод се користи у истовременим апликацијама.

Правила за креирање непроменљиве класе

  • Класа мора бити декларисана као коначни тако да се дечје класе не могу креирати.
  • Чланови података у класи морају бити декларисани приватни тако да директан приступ није дозвољен.
  • Чланови података у класи морају бити декларисани као коначни тако да не можемо да променимо њихову вредност након креирања објекта.
  • Параметризовани конструктор треба да иницијализује сва поља која изводе а дубока копија тако да чланови података не могу да се мењају помоћу референце објекта.
  • Дубинско копирање објеката требало би да се изврши у методама геттера да би се вратила копија уместо да се врати стварна референца објекта.

Напомена : Не би требало да постоје сеттери или једноставније речено не би требало да постоји опција за промену вредности променљиве инстанце.


Пример: имплементација непроменљиве класе

Студент.јава

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

У овом примеру смо креирали коначну класу под називом Студент. Има три коначна члана података, параметризовани конструктор и методе добијања. Имајте на уму да овде не постоји метода подешавања. Такође имајте на уму да не морамо да вршимо дубинско копирање или клонирање чланова података типова омота јер су они већ непроменљиви.

Геекс.јава:

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

Чак и након измене оригиналне или враћене мапе унутрашње стање студентског објекта остаје непромењено. Ово потврђује концепт непроменљивости.

Излаз:

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


Ограничење Јава записа са променљивим пољима

Представљена је Јава 14 рекорд . Ово је јасан и концизан начин да дефинишете непроменљиве попут класа:

запис Студент(име стринга инт регНо Мап метаподаци) {}


Али ово нуди само плитку непроменљивост. Ако је мапа измењена споља, интерно стање записа се мења:

Мапа мап = нова ХасхМап <>();

мап.пут('1' 'први');


Студент с = нови Студент('АБЦ' 101 мапа);


// Мења унутрашње стање — НИЈЕ безбедно

мап.пут('2' 'други');

с.метадата().пут('3' 'трећи');

Напомена : Користите запис само ако су сва поља непроменљиви типови као што су Стринг инт или други записи.