logo

Jak utworzyć niezmienną klasę w Javie?

W Javie niezmienność oznacza, że ​​po utworzeniu obiektu nie można zmienić jego stanu wewnętrznego. Niezmienne klasy w Javie zapewniają wiele korzyści, takich jak łatwe debugowanie bezpieczeństwa wątków i tak dalej. W Javie wszystko klasy wrapperów (jak Integer Boolean Byte Short), a klasa String jest niezmienna. Możemy również stworzyć własną, niezmienną klasę.

W tym artykule dowiemy się:



  • Co oznacza niezmienność
  • Dlaczego jest to przydatne
  • Jak stworzyć własną, niezmienną klasę
  • Dlaczego głębokie kopiowanie jest ważne
  • Jakie są ograniczenia typów rekordów Java

Co to jest klasa niezmienna?

Klasa niezmienna to klasa, której obiektów nie można zmieniać po utworzeniu. Jeśli dokonamy jakiejkolwiek modyfikacji, efektem będzie nowy obiekt. Ta metoda jest używana w aplikacjach współbieżnych.

Zasady tworzenia klasy niezmiennej

  • Klasę należy zadeklarować jako finał tak, że nie można tworzyć klas podrzędnych.
  • Elementy danych w klasie muszą zostać zadeklarowane prywatny tak, że bezpośredni dostęp nie jest dozwolony.
  • Elementy danych w klasie muszą być zadeklarowane jako finał abyśmy nie mogli zmienić ich wartości po utworzeniu obiektu.
  • Sparametryzowany konstruktor powinien zainicjować wszystkie pola wykonujące a głęboka kopia tak, że elementy danych nie mogą być modyfikowane za pomocą odwołania do obiektu.
  • Głębokie kopiowanie obiektów powinno zostać wykonane w metodach pobierających, aby zwrócić kopię, zamiast zwracać rzeczywiste odwołanie do obiektu.

Notatka : Nie powinno być żadnych elementów ustawiających lub, mówiąc prościej, nie powinna istnieć możliwość zmiany wartości zmiennej instancji.




mylivecricket w grze w krykieta na żywo

Przykład: Implementacja klasy niezmiennej

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

W tym przykładzie utworzyliśmy końcową klasę o nazwie Student. Ma trzech końcowych elementów danych, sparametryzowanego konstruktora i metody pobierające. Należy pamiętać, że nie ma tutaj metody ustawiającej. Należy również pamiętać, że nie musimy wykonywać głębokiego kopiowania ani klonowania elementów danych typów opakowań, ponieważ są one już niezmienne.



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

Nawet po modyfikacji oryginalnej lub zwróconej Mapy, stan wewnętrzny obiektu Studenta pozostaje niezmieniony. Potwierdza to koncepcję niezmienności.

Wyjście:

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


Ograniczenie rekordu Java za pomocą zmiennych pól

Wprowadzono Javę 14 nagrywać . Jest to jasny i zwięzły sposób definiowania niezmiennych klas podobnych:

record Student(String name int regNo Mapmetadane) {}


Ale to zapewnia tylko płytką niezmienność. Jeżeli Mapa zostanie zmodyfikowana zewnętrznie, stan wewnętrzny rekordu ulegnie zmianie:

Mapamapa = nowa HashMap<>();

map.put('1' 'pierwszy');


Student s = nowy Student(mapa 'ABC' 101);


// Zmienia stan wewnętrzny — NIE jest bezpieczny

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

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

Notatka : Użyj rekordu tylko wtedy, gdy wszystkie pola są typami niezmiennymi, takimi jak String int lub inne rekordy.

obrazy przecen