Java Language
Niezmienna klasa
Szukaj…
Wprowadzenie
Niezmienne obiekty to instancje, których stan nie zmienia się po zainicjowaniu. Na przykład String jest niezmienną klasą i po utworzeniu instancji jego wartość nigdy się nie zmienia.
Uwagi
Niektóre niezmienne klasy w Javie:
- java.lang.String
- Klasy opakowań dla typów pierwotnych: java.lang.Integer, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Boolean, java.lang.Long, java.lang.Double, java.lang.Float
- Większość klas wyliczania jest niezmienna, ale tak naprawdę zależy to od konkretnego przypadku.
- java.math.BigInteger i java.math.BigDecimal (przynajmniej obiekty samych klas)
- java.io.File. Zauważ, że reprezentuje to obiekt zewnętrzny w stosunku do maszyny wirtualnej (plik w systemie lokalnym), który może, ale nie musi istnieć, i ma pewne metody modyfikujące i sprawdzające stan tego obiektu zewnętrznego. Ale sam obiekt File pozostaje niezmienny.
Reguły definiujące niezmienne klasy
Poniższe zasady definiują prostą strategię tworzenia niezmiennych obiektów.
- Nie udostępniaj metod „ustawiających” - metod modyfikujących pola lub obiekty, do których odnoszą się pola.
- Uczyń wszystkie pola ostatecznymi i prywatnymi.
- Nie pozwól, aby podklasy zastępowały metody. Najprostszym sposobem na to jest zadeklarowanie klasy jako ostatecznej. Bardziej wyrafinowanym podejściem jest uczynienie konstruktora prywatnym i konstruowanie instancji metodami fabrycznymi.
- Jeśli pola instancji zawierają odniesienia do obiektów zmiennych, nie zezwalaj na ich zmianę:
- Nie udostępniaj metod modyfikujących zmienne obiekty.
- Nie udostępniaj odniesień do zmiennych obiektów. Nigdy nie przechowuj odniesień do zewnętrznych, zmiennych obiektów przekazywanych do konstruktora; w razie potrzeby utwórz kopie i przechowuj odniesienia do kopii. Podobnie, w razie potrzeby utwórz kopie wewnętrznych obiektów podlegających mutacji, aby uniknąć zwracania oryginałów metodami.
Przykład bez modyfikowalnych referencji
public final class Color {
final private int red;
final private int green;
final private int blue;
private void check(int red, int green, int blue) {
if (red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) {
throw new IllegalArgumentException();
}
}
public Color(int red, int green, int blue) {
check(red, green, blue);
this.red = red;
this.green = green;
this.blue = blue;
}
public Color invert() {
return new Color(255 - red, 255 - green, 255 - blue);
}
}
Przykład ze zmiennymi referencjami
W tym przypadku klasa Point jest zmienna i niektórzy użytkownicy mogą modyfikować stan obiektu tej klasy.
class Point {
private int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
//...
public final class ImmutableCircle {
private final Point center;
private final double radius;
public ImmutableCircle(Point center, double radius) {
// we create new object here because it shouldn't be changed
this.center = new Point(center.getX(), center.getY());
this.radius = radius;
}
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, prowadząc 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 obiektu 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 się nie zmieni.