Sök…


Introduktion

Oändliga objekt är fall vars tillstånd inte ändras efter det har initialiserats. Till exempel är String en oföränderlig klass och en gång instanserad förändras dess värde aldrig.

Anmärkningar

Några oföränderliga klasser i Java:

  1. java.lang.String
  2. Omslagsklasserna för de primitiva typerna: 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. De flesta klasser i enum är oföränderliga, men det beror faktiskt på det konkreta fallet.
  4. java.math.BigInteger och java.math.BigDecimal (åtminstone objekt från de klasserna själva)
  5. java.io.File. Observera att detta representerar ett objekt som är externt för VM (en fil i det lokala systemet), som kanske eller inte kan existera, och har några metoder som modifierar och frågar tillståndet för detta externa objekt. Men File-objektet i sig förblir oföränderligt.

Regler för att definiera oföränderliga klasser

Följande regler definierar en enkel strategi för att skapa oföränderliga objekt.

  1. Ange inte "setter" -metoder - metoder som modifierar fält eller objekt som hänvisas till av fält.
  2. Gör alla fält slutgiltiga och privata.
  3. Låt inte underklasser åsidosätta metoder. Det enklaste sättet att göra detta är att förklara klassen som slutlig. Ett mer sofistikerat tillvägagångssätt är att göra konstruktören privata och konstruera instanser i fabriksmetoder.
  4. Om instansfälten innehåller referenser till muterbara objekt, låt inte dessa objekt ändras:
  5. Ange inte metoder som modifierar de muterbara objekten.
  6. Dela inte referenser till de muterbara objekten. Förvara aldrig referenser till externa, muterbara objekt som skickas till konstruktören. skapa vid behov kopior och lagra referenser till kopiorna. På samma sätt kan du skapa kopior av dina interna muterbara objekt när det är nödvändigt för att undvika att returnera originalen i dina metoder.

Exempel utan muterbara refs

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

Exempel med muterbara refs

I det här fallet är punkten förändrad och en del användare kan ändra objektets tillstånd för denna klass.

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

Vad är fördelen med oföränderlighet?

Fördelen med oföränderlighet kommer med samtidighet. Det är svårt att bibehålla riktigheten i muterbara objekt, eftersom flera trådar kan försöka ändra tillståndet för samma objekt, vilket leder till att vissa trådar ser ett annat tillstånd för samma objekt, beroende på tidpunkten för läsningarna och skriver till nämnda objekt objekt.

Genom att ha ett immutable-objekt kan man säkerställa att alla trådar som tittar på objektet ser samma tillstånd, eftersom tillståndet för ett immutable-objekt inte kommer att förändras.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow