W jaki sposób można uczynić niezmienną klasę Javy, jaka jest potrzeba niezmienności i czy jest jakaś korzyść z jej używania?
java
string
immutability
JavaUser
źródło
źródło
@Immutable
adnotację z jcabi-Odpowiedzi:
Co to jest niezmienny obiekt?
Niezmienny obiekt to taki, który nie zmieni stanu po utworzeniu wystąpienia.
Jak uczynić obiekt niezmiennym?
Ogólnie rzecz biorąc, niezmienny obiekt można utworzyć, definiując klasę, która nie ma ujawnionego żadnego ze swoich elementów członkowskich i nie ma żadnych metod ustawiających.
Następująca klasa utworzy niezmienny obiekt:
class ImmutableInt { private final int value; public ImmutableInt(int i) { value = i; } public int getValue() { return value; } }
Jak widać w powyższym przykładzie, wartość the
ImmutableInt
można ustawić tylko wtedy, gdy obiekt jest tworzony, a mając tylko metodę getter (getValue
), stan obiektu nie może zostać zmieniony po utworzeniu instancji.Należy jednak uważać, aby wszystkie obiekty, do których odwołuje się obiekt, również były niezmienne, w przeciwnym razie może istnieć możliwość zmiany stanu obiektu.
Na przykład zezwolenie na odwołanie do tablicy lub
ArrayList
uzyskanie go za pomocą metody pobierającej pozwoli na zmianę stanu wewnętrznego przez zmianę tablicy lub kolekcji:class NotQuiteImmutableList<T> { private final List<T> list; public NotQuiteImmutableList(List<T> list) { // creates a new ArrayList and keeps a reference to it. this.list = new ArrayList(list); } public List<T> getList() { return list; } }
Problem z powyższym kodem polega na tym, że
ArrayList
można go uzyskaćgetList
i manipulować nim, co prowadzi do zmiany stanu samego obiektu, a zatem nie jest niezmienny.// notQuiteImmutableList contains "a", "b", "c" List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c")); // now the list contains "a", "b", "c", "d" -- this list is mutable. notQuiteImmutableList.getList().add("d");
Jednym ze sposobów obejścia tego problemu jest zwrócenie kopii tablicy lub kolekcji po wywołaniu z metody pobierającej:
public List<T> getList() { // return a copy of the list so the internal state cannot be altered return new ArrayList(list); }
Jaka jest zaleta niezmienności?
Zaletą niezmienności jest współbieżność. Trudno jest zachować poprawność w obiektach zmiennych, ponieważ wiele wątków może próbować zmienić stan tego samego obiektu, co prowadzi do tego, że niektóre wątki widzą inny stan tego samego obiektu, w zależności od czasu odczytów i zapisów do wspomnianego obiekt.
Mając niezmienny obiekt, można zapewnić, że wszystkie wątki, które patrzą na obiekt, będą widzieć ten sam stan, ponieważ stan niezmiennego obiektu nie ulegnie zmianie.
źródło
return Collections.unmodifiableList(list);
zwrócić na liście widok tylko do odczytu.final
. W przeciwnym razie można go rozszerzyć o metodę ustawiającą (lub inne rodzaje metod mutujących i pól mutowalnych).final
jeśli klasa ma tylkoprivate
pola, ponieważ nie można uzyskać do nich dostępu z podklas.Oprócz odpowiedzi już udzielonych, polecam przeczytanie o niezmienności w Effective Java, wyd. 2, ponieważ jest kilka szczegółów, które łatwo przeoczyć (np. Kopie obronne). Dodatkowo Effective Java 2nd Ed. to lektura obowiązkowa dla każdego programisty Java.
źródło
Tworzysz niezmienną klasę w następujący sposób:
public final class Immutable { private final String name; public Immutable(String name) { this.name = name; } public String getName() { return this.name; } // No setter; }
Poniżej przedstawiono wymagania, aby uczynić niezmienną klasę Javy:
final
(aby nie można było tworzyć klas podrzędnych)final
(abyśmy nie mogli zmienić jej wartości po utworzeniu obiektu)Niezmienne klasy są przydatne, ponieważ
- są bezpieczne dla wątków.
- Wyrażają również coś głębokiego w Twoim projekcie: „Nie można tego zmienić”. Kiedy ma zastosowanie, jest dokładnie tym, czego potrzebujesz.
źródło
Niezmienność można osiągnąć głównie na dwa sposoby:
final
atrybutów instancji, aby uniknąć ponownego przypisaniaZaletami niezmienności są założenia, które możesz poczynić na tym obiekcie:
źródło
Niezmienne klasy nie mogą ponownie przypisać wartości po utworzeniu instancji. Konstruktor przypisuje wartości do swoich prywatnych zmiennych. Dopóki obiekt nie stanie się pusty, wartości nie mogą być zmieniane z powodu niedostępności metod ustawiających.
być niezmiennym powinno spełniać następujące,
/** * Strong immutability - by making class final */ public final class TestImmutablity { // make the variables private private String Name; //assign value when the object created public TestImmutablity(String name) { this.Name = name; } //provide getters to access values public String getName() { return this.Name; } }
Zalety: Niezmienne obiekty zawierają zainicjalizowane wartości, dopóki nie umrą.
java-immutable-classes-short-note
źródło
Niezmienne klasy to takie, których obiektów nie można zmienić po utworzeniu.
Niezmienne klasy są przydatne dla
Przykład
Klasa ciągów
Przykład kodu
public final class Student { private final String name; private final String rollNumber; public Student(String name, String rollNumber) { this.name = name; this.rollNumber = rollNumber; } public String getName() { return this.name; } public String getRollNumber() { return this.rollNumber; } }
źródło
W jaki sposób można uczynić niezmienną klasę Javy?
Z JDK 14+, który ma JEP 359 , możemy użyć "
records
". Jest to najprostszy i bezproblemowy sposób tworzenia klasy Immutable.Klasa rekordu to płytko niezmienny , przezroczysty nośnik dla ustalonego zestawu pól, zwanego rekordem,
components
który zawierastate
opis rekordu. Każda z nichcomponent
daje początekfinal
polu, które przechowuje podaną wartość iaccessor
metodę pobierania wartości. Nazwa pola i nazwa akcesorium są zgodne z nazwą komponentu.Rozważmy przykład tworzenia niezmiennego prostokąta
record Rectangle(double length, double width) {}
Nie ma potrzeby deklarowania żadnego konstruktora, nie ma potrzeby implementowania metod equals i hashCode. Dowolne rekordy wymagają nazwy i opisu stanu.
var rectangle = new Rectangle(7.1, 8.9); System.out.print(rectangle.length()); // prints 7.1
Jeśli chcesz sprawdzić poprawność wartości podczas tworzenia obiektu, musimy jawnie zadeklarować konstruktora.
public Rectangle { if (length <= 0.0) { throw new IllegalArgumentException(); } }
Treść rekordu może deklarować metody statyczne, pola statyczne, inicjatory statyczne, konstruktory, metody wystąpień i typy zagnieżdżone.
Metody instancji
record Rectangle(double length, double width) { public double area() { return this.length * this.width; } }
pola statyczne, metody
Ponieważ stan powinien być częścią komponentów, nie możemy dodawać pól instancji do rekordów. Ale możemy dodać statyczne pola i metody:
record Rectangle(double length, double width) { static double aStaticField; static void aStaticMethod() { System.out.println("Hello Static"); } }
jaka jest potrzeba niezmienności i czy jest jakaś korzyść z jej używania?
Wcześniej opublikowane odpowiedzi są wystarczająco dobre, aby uzasadnić potrzebę niezmienności i są to zalety
źródło
Innym sposobem na stworzenie niezmiennego obiektu jest użycie biblioteki Immutables.org :
package info.sample; import java.util.List; import java.util.Set; import org.immutables.value.Value; @Value.Immutable public abstract class FoobarValue { public abstract int foo(); public abstract String bar(); public abstract List<Integer> buz(); public abstract Set<Long> crux(); }
package info.sample; import java.util.List; public class FoobarValueMain { public static void main(String... args) { FoobarValue value = ImmutableFoobarValue.builder() .foo(2) .bar("Bar") .addBuz(1, 3, 4) .build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}} int foo = value.foo(); // 2 List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4) } }
źródło
Niezmienna klasa to po prostu klasa, której instancji nie można modyfikować.
Wszystkie informacje zawarte w każdej instancji są ustalone przez cały okres istnienia obiektu, więc nie można zaobserwować żadnych zmian.
Niezmienne klasy są łatwiejsze do projektowania, implementowania i używania niż klasy mutowalne.
Aby uczynić klasę niezmienną, przestrzegaj pięciu zasad:
Nie podawaj metod modyfikujących stan obiektu
Upewnij się, że klasa nie może zostać przedłużona.
Spraw, aby wszystkie pola były ostateczne.
Ustaw wszystkie pola jako prywatne.
Zapewnij wyłączny dostęp do wszelkich zmiennych komponentów.
Niezmienne obiekty są z natury bezpieczne dla wątków; nie wymagają synchronizacji.
Niezmienne obiekty można swobodnie udostępniać.
Niezmienne obiekty są świetnymi cegiełkami do budowania innych obiektów
źródło
@Jack, Posiadanie końcowych pól i seterów w klasie nie spowoduje, że klasa będzie niezmienna. końcowe słowo kluczowe zapewnia tylko, że zmienna nigdy nie zostanie ponownie przypisana. Musisz zwrócić głęboką kopię wszystkich pól w metodach pobierających. Zapewni to, że po pobraniu obiektu z metody getter stan wewnętrzny obiektu nie zostanie zakłócony.
źródło
Jako osoba, dla której angielski nie jest językiem ojczystym, nie podoba mi się powszechna interpretacja istoty „niezmiennej klasy”, „skonstruowane obiekty klas są niezmienne”; raczej skłaniam się do interpretowania tego jako „sam obiekt klasy jest niezmienny”.
To powiedziawszy, „niezmienna klasa” jest rodzajem niezmiennego obiektu. Różnica polega na udzieleniu odpowiedzi na pytanie, jakie są korzyści. Zgodnie z moją wiedzą / interpretacją, niezmienna klasa zapobiega modyfikacjom zachowania swoich obiektów w czasie wykonywania.
źródło
Większość odpowiedzi tutaj jest dobrych, a niektórzy wspominali o zasadach, ale czuję, że dobrze jest opisać słowami, dlaczego i kiedy musimy ich przestrzegać. Więc podaję poniższe wyjaśnienie
I oczywiście, jeśli spróbujemy użyć Setterów dla tych końcowych zmiennych, kompilator zgłosi błąd.
public class ImmutableClassExplored { public final int a; public final int b; /* OR Generally we declare all properties as private, but declaring them as public will not cause any issues in our scenario if we make them final public final int a = 109; public final int b = 189; */ ImmutableClassExplored(){ this. a = 111; this.b = 222; } ImmutableClassExplored(int a, int b){ this.a = a; this.b= b; } }
Czy musimy zadeklarować klasę jako „ostateczną”?
1. Posiadanie tylko prymitywów: nie mamy problemu Jeśli klasa ma tylko prymitywne składowe, to nie musimy deklarować klasy jako ostatecznej.
2.Mając obiekty jako zmienne składowe: Jeśli mamy obiekty jako zmienne składowe, to musimy uczynić składowe tych obiektów również ostatecznymi. Oznacza to, że musimy przejść głęboko w drzewo i uczynić wszystkie obiekty / prymitywy ostatecznymi, co może nie być możliwe za każdym razem. Tak więc obejściem jest uczynienie klasy ostateczną, co zapobiega dziedziczeniu. Nie ma więc kwestii przesłaniania metod pobierających przez podklasy.
źródło
Adnotacja @Value Lombok może służyć do generowania niezmiennych klas. To tak proste, jak poniższy kod.
@Value public class LombokImmutable { int id; String name; }
Zgodnie z dokumentacją na stronie Lombok:
W pełni działający przykład można znaleźć tutaj.
źródło
record
można używać Javy ?