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:

  1. java.lang.String
  2. 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
  3. Większość klas wyliczania jest niezmienna, ale tak naprawdę zależy to od konkretnego przypadku.
  4. java.math.BigInteger i java.math.BigDecimal (przynajmniej obiekty samych klas)
  5. 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.

  1. Nie udostępniaj metod „ustawiających” - metod modyfikujących pola lub obiekty, do których odnoszą się pola.
  2. Uczyń wszystkie pola ostatecznymi i prywatnymi.
  3. 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.
  4. Jeśli pola instancji zawierają odniesienia do obiektów zmiennych, nie zezwalaj na ich zmianę:
  5. Nie udostępniaj metod modyfikujących zmienne obiekty.
  6. 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.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow