Was ist mit unveränderlich gemeint?


400

Dies könnte die dümmste Frage sein, die jemals gestellt wurde, aber ich denke, dass es für einen Java-Neuling ziemlich verwirrend ist.

  1. Kann jemand klarstellen, was unter unveränderlich zu verstehen ist ?
  2. Warum ist ein Stringunveränderlicher?
  3. Was sind die Vor- und Nachteile der unveränderlichen Objekte?
  4. Warum sollte ein veränderliches Objekt wie StringBuilderString gegenüber String bevorzugt werden und umgekehrt?

Ein schönes Beispiel (in Java) wird sehr geschätzt.


73
Sehen Sie, es war keine so dumme Frage. Schön, dass du gefragt hast!
DOK

2
Übrigens denke ich nicht, dass es die dümmste Frage überhaupt ist :) Ich denke, es ist ein ziemlich wichtiges Konzept zu verstehen
Jason Coco

1
Als Sie StringBuilder sagten, meinten Sie nicht die veränderbare Klasse StringBuffer? String und StringBuffer sind in ihrer Funktion ähnlicher als String und StringBuilder. StringBuffer ist effektiv eine veränderbare Zeichenfolge.
Derek Mahar

3
Darf ich vorschlagen, dass wir das "Anfänger" -Tag dieser Frage hinzufügen, damit Programmierer, die neu in Java sind, es bei der Suche nach anderen einführenden Fragen finden können?
Derek Mahar

Antworten:


268

Unveränderlich bedeutet, dass diese Instanz nicht geändert werden kann, sobald der Konstruktor für ein Objekt die Ausführung abgeschlossen hat.

Dies ist nützlich, da Sie Verweise auf das Objekt weitergeben können, ohne befürchten zu müssen, dass jemand anderes seinen Inhalt ändert. Insbesondere beim Umgang mit Parallelität treten bei Objekten, die sich nie ändern, keine Sperrprobleme auf

z.B

class Foo
{
     private final String myvar;

     public Foo(final String initialValue)
     {
         this.myvar = initialValue;
     }

     public String getValue()
     {
         return this.myvar;
     }
}

FooSie müssen sich keine Sorgen machen, dass der Aufrufer getValue()den Text in der Zeichenfolge ändern könnte.

Wenn Sie sich eine ähnliche Klasse vorstellen Foo, jedoch mit einem StringBuilderals StringMitglied, können Sie sehen, dass ein Aufrufer getValue()das StringBuilderAttribut einer FooInstanz ändern kann .

Achten Sie auch auf die verschiedenen Arten der Unveränderlichkeit: Eric Lippert hat einen Blog-Artikel darüber geschrieben. Grundsätzlich können Sie Objekte haben, deren Schnittstelle unveränderlich ist, aber hinter den Kulissen den tatsächlichen veränderlichen privaten Status (und daher nicht sicher zwischen Threads geteilt werden können).


3
Ich denke, Sie sollten einen Konstruktor mit einem Argument hinzufügen, um mindestens einmal einen Wert zuzuweisen. Der Punkt des aktuellen Codes ist nicht klar, da es keinen Wert gibt, der wirklich geändert werden könnte :).
Georgy Bolyuba

4
Sie sollten das Feld schreibgeschützt machen. Es macht deutlich, dass das Feld unveränderlich ist. Im Moment ist es durch Konvention unveränderlich
JaredPar

7
Das Mitglied myVar sollte endgültig sein, damit dies wirklich unveränderlich ist.
Laz

13
Sie haben Recht, dass myVar außerhalb von Foo nicht zugänglich ist. Das Vorhandensein von final zeigt jedoch jedem an, der die Klasse in Zukunft möglicherweise ändert, dass sich ihr Wert nicht ändern soll. Ich neige dazu, unter solchen Umständen so explizit wie möglich zu sein.
Laz

2
Wie wäre es mit "Referenztypen können nicht einfach mit dem Schlüsselwort final unveränderlich gemacht werden. Final verhindert nur die Neuzuweisung." von en.wikipedia.org/wiki/Immutable_object
Yousha Aleayoub

81

Ein unveränderliches Objekt ist ein Objekt, bei dem die internen Felder (oder zumindest alle internen Felder, die sich auf das externe Verhalten auswirken) nicht geändert werden können.

Unveränderliche Saiten bieten viele Vorteile:

Leistung: Führen Sie die folgenden Schritte aus:

String substring = fullstring.substring(x,y);

Das zugrunde liegende C für die Methode substring () ist wahrscheinlich ungefähr so:

// Assume string is stored like this:
struct String { char* characters; unsigned int length; };

// Passing pointers because Java is pass-by-reference
struct String* substring(struct String* in, unsigned int begin, unsigned int end)
{
    struct String* out = malloc(sizeof(struct String));
    out->characters = in->characters + begin;
    out->length = end - begin;
    return out;
}

Beachten Sie, dass keines der Zeichen kopiert werden muss! Wenn das String-Objekt veränderbar wäre (die Zeichen könnten sich später ändern), müssten Sie alle Zeichen kopieren, andernfalls würden Änderungen an Zeichen in der Teilzeichenfolge später in der anderen Zeichenfolge wiedergegeben.

Parallelität: Wenn die interne Struktur eines unveränderlichen Objekts gültig ist, ist sie immer gültig. Es besteht keine Möglichkeit, dass verschiedene Threads einen ungültigen Status innerhalb dieses Objekts erstellen. Daher sind unveränderliche Objekte threadsicher .

Speicherbereinigung: Für den Speicherbereiniger ist es viel einfacher, logische Entscheidungen über unveränderliche Objekte zu treffen.

Die Unveränderlichkeit hat jedoch auch Nachteile:

Leistung: Warten Sie, ich dachte, Sie sagten, Leistung sei ein Vorteil der Unveränderlichkeit! Nun, manchmal, aber nicht immer. Nehmen Sie den folgenden Code:

foo = foo.substring(0,4) + "a" + foo.substring(5);  // foo is a String
bar.replace(4,5,"a"); // bar is a StringBuilder

Die beiden Zeilen ersetzen das vierte Zeichen durch den Buchstaben "a". Der zweite Code ist nicht nur besser lesbar, sondern auch schneller. Schauen Sie sich an, wie Sie den zugrunde liegenden Code für foo erstellen müssten. Die Teilzeichenfolgen sind einfach, aber jetzt, da sich bereits ein Zeichen im fünften Feld befindet und etwas anderes möglicherweise auf foo verweist, können Sie es nicht einfach ändern. Sie müssen die gesamte Zeichenfolge kopieren (natürlich wird ein Teil dieser Funktionalität in Funktionen im realen zugrunde liegenden C abstrahiert, aber hier geht es darum, den Code anzuzeigen, der an einer Stelle ausgeführt wird).

struct String* concatenate(struct String* first, struct String* second)
{
    struct String* new = malloc(sizeof(struct String));
    new->length = first->length + second->length;

    new->characters = malloc(new->length);

    int i;

    for(i = 0; i < first->length; i++)
        new->characters[i] = first->characters[i];

    for(; i - first->length < second->length; i++)
        new->characters[i] = second->characters[i - first->length];

    return new;
}

// The code that executes
struct String* astring;
char a = 'a';
astring->characters = &a;
astring->length = 1;
foo = concatenate(concatenate(slice(foo,0,4),astring),slice(foo,5,foo->length));

Beachten Sie, dass die Verkettung zweimal aufgerufen wird, was bedeutet, dass die gesamte Zeichenfolge durchlaufen werden muss! Vergleichen Sie dies mit dem C-Code für die barOperation:

bar->characters[4] = 'a';

Die veränderbare String-Operation ist offensichtlich viel schneller.

Fazit: In den meisten Fällen möchten Sie eine unveränderliche Zeichenfolge. Wenn Sie jedoch viel anhängen und in eine Zeichenfolge einfügen müssen, benötigen Sie die Veränderbarkeit für die Geschwindigkeit. Wenn Sie die Vorteile der Parallelitätssicherheit und der Speicherbereinigung nutzen möchten, müssen Sie Ihre veränderlichen Objekte für eine Methode lokal halten:

// This will have awful performance if you don't use mutable strings
String join(String[] strings, String separator)
{
    StringBuilder mutable;
    boolean first = true;

    for(int i = 0; i < strings.length; i++)
    {
        if(!first) first = false;
        else mutable.append(separator);

        mutable.append(strings[i]);
    }

    return mutable.toString();
}

Da es sich bei dem mutableObjekt um eine lokale Referenz handelt, müssen Sie sich keine Gedanken über die Sicherheit der Parallelität machen (nur ein Thread berührt es jemals). Und da es nirgendwo anders referenziert wird, wird es nur auf dem Stapel zugewiesen, sodass die Zuordnung aufgehoben wird, sobald der Funktionsaufruf abgeschlossen ist (Sie müssen sich nicht um die Speicherbereinigung kümmern). Und Sie erhalten alle Leistungsvorteile von Veränderlichkeit und Unveränderlichkeit.


4
Tolle Lektüre! Nur eine Sache, denke ich, sollte es sein, wenn (zuerst) und nicht wenn (! zuerst)
Siddhartha

Notwendig ist nicht, dass die Felder unveränderlich sind, sondern dass der definierte beobachtbare Zustand des Objekts unveränderlich ist; Ein Objekt, das einen Verweis auf ein anderes Objekt als Mittel zur Einkapselung des darin enthaltenen Zustands enthält, kann nur unveränderlich sein, wenn alle eingekapselten Aspekte des Zustands, die es der Außenwelt aussetzt, ebenfalls unveränderlich sind. Beachten Sie, dass es weder notwendig noch ausreichend ist, dass Felder unveränderlichen Typs sind. Was zählt, ist der sichtbare Zustand.
Supercat

7
Passing pointers because Java is pass-by-referenceIst Java nicht "Pass-by-Value"?
Cristian Gutu

@CristianGutu ja, Sie haben Recht JAVA ist "Pass by Value" nicht "Pass by REFERENCE"
Arsh Kaushal

Referenz wird als Wert übergeben !!
Devv

31

Tatsächlich ist String nicht unveränderlich, wenn Sie die oben vorgeschlagene Wikipedia-Definition verwenden.

Der Status des Strings ändert die Postkonstruktion. Schauen Sie sich die Hashcode () -Methode an. String speichert den Hashcode-Wert in einem lokalen Feld zwischen, berechnet ihn jedoch erst beim ersten Aufruf von Hashcode (). Diese verzögerte Auswertung von Hashcode bringt String an eine interessante Position als unveränderliches Objekt, dessen Status sich ändert, aber es kann nicht beobachtet werden, dass es sich ohne Verwendung von Reflexion geändert hat.

Vielleicht sollte die Definition von unveränderlich ein Objekt sein, von dem nicht beobachtet werden kann, dass es sich geändert hat.

Wenn sich der Status eines unveränderlichen Objekts ändert, nachdem es erstellt wurde, aber niemand es sehen kann (ohne Reflexion), ist das Objekt dann noch unveränderlich?


1
Gute Idee - ein Objekt, von dem nicht beobachtet werden kann, dass es sich geändert hat, und auch keine Möglichkeit, es von außen zu ändern. Das private Feld für hashCode () ist eine interne Änderung, die für den extern sichtbaren Status des Objekts nicht wesentlich ist.
Mparaz

2
Tatsächlich kann beobachtet werden, dass es sich geändert hat, wenn Sie Reflexion verwenden. Weitere Informationen finden Sie unter Sedgewicks Saiten sind veränderlich, wenn Sie Reflexion zulassen .
Miguel

24

Unveränderliche Objekte sind Objekte, die nicht programmgesteuert geändert werden können. Sie eignen sich besonders für Umgebungen mit mehreren Threads oder andere Umgebungen, in denen mehr als ein Prozess die Werte in einem Objekt ändern (mutieren) kann.

Um dies zu verdeutlichen, ist StringBuilder tatsächlich ein veränderliches Objekt, kein unveränderliches. Ein regulärer Java-String ist unveränderlich (dh, sobald er erstellt wurde, können Sie den zugrunde liegenden String nicht mehr ändern, ohne das Objekt zu ändern).

Angenommen, ich habe eine Klasse namens ColoredString mit einem String-Wert und einer String-Farbe:

public class ColoredString {

    private String color;
    private String string;

    public ColoredString(String color, String string) {
        this.color  = color;
        this.string = string;
    }

    public String getColor()  { return this.color;  }
    public String getString() { return this.string; }

    public void setColor(String newColor) {
        this.color = newColor;
    }

}

In diesem Beispiel wird der ColoredString als veränderbar bezeichnet, da Sie eine seiner Schlüsseleigenschaften ändern (mutieren) können, ohne eine neue ColoredString-Klasse zu erstellen. Der Grund, warum dies möglicherweise schlecht ist, ist beispielsweise, dass Sie eine GUI-Anwendung mit mehreren Threads haben und ColoredStrings verwenden, um Daten in das Fenster zu drucken. Wenn Sie eine Instanz von ColoredString haben, die als erstellt wurde

new ColoredString("Blue", "This is a blue string!");

Dann würden Sie erwarten, dass die Zeichenfolge immer "Blau" ist. Wenn jedoch ein anderer Thread diese Instanz erhalten und aufgerufen hat

blueString.setColor("Red");

Sie würden plötzlich und wahrscheinlich unerwartet jetzt eine "rote" Saite haben, wenn Sie eine "blaue" wollten. Aus diesem Grund werden unveränderliche Objekte fast immer bevorzugt, wenn Instanzen von Objekten weitergegeben werden. Wenn Sie einen Fall haben, in dem veränderbare Objekte wirklich notwendig sind, schützen Sie das Objekt normalerweise, indem Sie nur Kopien aus Ihrem spezifischen Kontrollbereich verteilen.

Zusammenfassend ist java.lang.String in Java ein unveränderliches Objekt (es kann nach seiner Erstellung nicht mehr geändert werden) und java.lang.StringBuilder ist ein veränderliches Objekt, da es geändert werden kann, ohne eine neue Instanz zu erstellen.


Sie sollten die Felder schreibgeschützt machen. Im Moment ist Ihre Klasse gemäß Konvention unveränderlich. Zukünftigen Entwicklern gibt es keinen Hinweis darauf, dass das Unveränderliche beabsichtigt ist. Wenn Sie die Felder schreibgeschützt machen, können Sie Ihre Absicht gegenüber einem zukünftigen Entwickler klarstellen
JaredPar

@JaredPar - Eigentlich ist die Klasse überhaupt nicht unveränderlich ... es ist ein Beispiel für eine veränderbare Klasse, um zu demonstrieren, warum es ein Problem sein kann.
Jason Coco

1
@JaredPar - Oh, das ist völlig in Ordnung :) Ich wollte es ein bisschen umschreiben, um es klarer zu machen, aber Douglas ist bereits gut geschrieben und scheint der Favorit zu sein, also lasse ich mein Beispiel einfach als weiteres; aber jemand hat es tatsächlich bearbeitet, um die Eigenschaften endgültig zu machen, was ich amüsant fand :)
Jason Coco

24
  1. In großen Anwendungen ist es üblich, dass Zeichenfolgenliterale große Speicherbits belegen. Um den Speicher effizient zu handhaben, weist die JVM einen Bereich mit dem Namen "String-Konstantenpool" zu. ( Beachten Sie, dass im Speicher sogar ein nicht referenzierter String ein char [], ein int für seine Länge und ein anderes für seinen hashCode enthält. Für eine Zahl wird dagegen maximal acht unmittelbaren Bytes erforderlich )
  2. Wenn der Complier auf ein String-Literal stößt, überprüft er den Pool, um festzustellen, ob bereits ein identisches Literal vorhanden ist. Und wenn einer gefunden wird, wird der Verweis auf das neue Literal auf den vorhandenen String gerichtet, und es wird kein neues 'String-Literal-Objekt' erstellt (der vorhandene String erhält einfach einen zusätzlichen Verweis).
  3. Daher: String-Mutabilität spart Speicher ...
  4. Aber wenn eine der Variablen ihren Wert ändert, ändert sich tatsächlich nur ihre Referenz, nicht der Wert im Speicher (daher wirkt sich dies nicht auf die anderen Variablen aus, die darauf verweisen), wie unten dargestellt.

String s1 = "Alter String";

//s1 variable, refers to string in memory
        reference                 |     MEMORY       |
        variables                 |                  |

           [s1]   --------------->|   "Old String"   |

String s2 = s1;

//s2 refers to same string as s1
                                  |                  |
           [s1]   --------------->|   "Old String"   |
           [s2]   ------------------------^

s1 = "Neuer String";

//s1 deletes reference to old string and points to the newly created one
           [s1]   -----|--------->|   "New String"   |
                       |          |                  |
                       |~~~~~~~~~X|   "Old String"   |
           [s2]   ------------------------^

Die ursprüngliche Zeichenfolge 'im Speicher' wurde nicht geändert, aber die Referenzvariable wurde so geändert, dass sie auf die neue Zeichenfolge verweist. Und wenn wir nicht s2 hätten, wäre "Old String" immer noch im Speicher, aber wir können nicht darauf zugreifen ...


16

"unveränderlich" bedeutet, dass Sie den Wert nicht ändern können. Wenn Sie eine Instanz der String-Klasse haben, erstellt jede von Ihnen aufgerufene Methode, die den Wert zu ändern scheint, tatsächlich einen weiteren String.

String foo = "Hello";
foo.substring(3);
<-- foo here still has the same value "Hello"

Um Änderungen beizubehalten, sollten Sie Folgendes tun: foo = foo.sustring (3);

Unveränderlich gegen veränderlich kann lustig sein, wenn Sie mit Sammlungen arbeiten. Überlegen Sie, was passieren wird, wenn Sie ein veränderliches Objekt als Schlüssel für die Karte verwenden und dann den Wert ändern (Tipp: Denken Sie an equalsund hashCode).


13

java.time

Es mag etwas spät sein, aber um zu verstehen, was ein unveränderliches Objekt ist, betrachten Sie das folgende Beispiel aus der neuen Java 8-API für Datum und Uhrzeit ( java.time ). Wie Sie wahrscheinlich wissen, sind alle Datumsobjekte aus Java 8 im folgenden Beispiel unveränderlich

LocalDate date = LocalDate.of(2014, 3, 18); 
date.plusYears(2);
System.out.println(date);

Ausgabe:

18.03.2014

Dies gibt das gleiche Jahr wie das ursprüngliche Datum aus, da plusYears(2)ein neues Objekt zurückgegeben wird, sodass das alte Datum unverändert bleibt, da es sich um ein unveränderliches Objekt handelt. Einmal erstellt, können Sie es nicht weiter ändern und die Datumsvariable zeigt weiterhin darauf.

Dieses Codebeispiel sollte also das neue Objekt erfassen und verwenden, das von diesem Aufruf an instanziiert und zurückgegeben wird plusYears.

LocalDate date = LocalDate.of(2014, 3, 18); 
LocalDate dateAfterTwoYears = date.plusYears(2);

date.toString ()… 2014-03-18

dateAfterTwoYears.toString ()… 2016-03-18


8

Die Erklärung von SCJP Sun Certified Programmer für Java 5 Study Guide gefällt mir sehr gut .

Um Java speichereffizienter zu machen, reserviert die JVM einen speziellen Speicherbereich, den "String Constant Pool". Wenn der Compiler auf ein String-Literal stößt, überprüft er den Pool, um festzustellen, ob bereits ein identischer String vorhanden ist. Wenn eine Übereinstimmung gefunden wird, wird der Verweis auf das neue Literal auf den vorhandenen String gerichtet, und es wird kein neues String-Literalobjekt erstellt.


Es sollte in der Lage sein, dies mit identischen unveränderlichen Objekten zu tun, aber ich nehme an, dass dies zu viel Laufzeit in Anspruch nehmen würde.
Zan Lynx

8

Unveränderliche Objekte können ihren Status nach ihrer Erstellung nicht mehr ändern.

Es gibt drei Hauptgründe, unveränderliche Objekte zu verwenden, wann immer Sie können. All dies trägt dazu bei, die Anzahl der Fehler zu verringern, die Sie in Ihren Code einführen:

  • Es ist viel einfacher zu überlegen, wie Ihr Programm funktioniert, wenn Sie wissen, dass der Status eines Objekts nicht durch eine andere Methode geändert werden kann
  • Unveränderliche Objekte sind automatisch threadsicher (vorausgesetzt, sie werden sicher veröffentlicht) und sind daher niemals die Ursache für diese schwer zu behebenden Multithreading-Fehler
  • Unveränderliche Objekte haben immer denselben Hash-Code, sodass sie als Schlüssel in einer HashMap (oder ähnlichem) verwendet werden können. Wenn sich der Hash-Code eines Elements in einer Hash-Tabelle ändern würde, würde der Tabelleneintrag effektiv verloren gehen, da Versuche, ihn in der Tabelle zu finden, am falschen Ort suchen würden. Dies ist der Hauptgrund dafür, dass String-Objekte unveränderlich sind - sie werden häufig als HashMap-Schlüssel verwendet.

Es gibt auch einige andere Optimierungen, die Sie möglicherweise im Code vornehmen können, wenn Sie wissen, dass der Status eines Objekts unveränderlich ist - beispielsweise das Zwischenspeichern des berechneten Hashs -, aber dies sind Optimierungen und daher bei weitem nicht so interessant.


5

Eine Bedeutung hängt damit zusammen, wie der Wert auf dem Computer gespeichert wird. Für eine .Net-Zeichenfolge bedeutet dies beispielsweise, dass die Zeichenfolge im Speicher nicht geändert werden kann. Wenn Sie glauben, dass Sie sie ändern, erstellen Sie tatsächlich eine neue Zeichenfolge im Speicher und Zeigen der vorhandenen Variablen (die nur ein Zeiger auf die tatsächliche Sammlung von Zeichen an einer anderen Stelle ist) auf die neue Zeichenfolge.


4
String s1="Hi";
String s2=s1;
s1="Bye";

System.out.println(s2); //Hi  (if String was mutable output would be: Bye)
System.out.println(s1); //Bye

s1="Hi": Ein Objekt s1wurde mit dem Wert "Hi" erstellt.

s2=s1 : Ein Objekt s2wird mit Bezug auf das s1-Objekt erstellt.

s1="Bye": s1Der Wert des vorherigen Objekts ändert sich nicht, da s1der String-Typ und der String-Typ ein unveränderlicher Typ sind. Stattdessen erstellt der Compiler ein neues String-Objekt mit dem Wert "Bye" und s1verweist darauf. Wenn wir hier den s2Wert drucken , ist das Ergebnis "Hi", nicht "Bye", da s2auf das vorherige s1Objekt verwiesen wird, das den Wert "Hi" hatte.


Können Sie bitte eine kleine Erklärung hinzufügen?
Minigeek

3

Unveränderlich bedeutet, dass sich nach dem Erstellen des Objekts keines seiner Mitglieder ändert. Stringist unveränderlich, da Sie seinen Inhalt nicht ändern können. Zum Beispiel:

String s1 = "  abc  ";
String s2 = s1.trim();

Im obigen Code hat sich die Zeichenfolge s1 nicht geändert, ein anderes Objekt ( s2) wurde mit erstellt s1.


3

Unveränderlich bedeutet einfach unveränderlich oder nicht veränderbar. Sobald ein Zeichenfolgenobjekt erstellt wurde, können seine Daten oder sein Status nicht mehr geändert werden

Betrachten Sie das folgende Beispiel:

class Testimmutablestring{  
  public static void main(String args[]){  
    String s="Future";  
    s.concat(" World");//concat() method appends the string at the end  
    System.out.println(s);//will print Future because strings are immutable objects  
  }  
 }  

Lassen Sie uns eine Vorstellung von dem folgenden Diagramm bekommen.

Geben Sie hier die Bildbeschreibung ein

In diesem Diagramm sehen Sie ein neues Objekt, das als "Future World" erstellt wurde. Aber nicht "Zukunft" ändern. Because String is immutable. s, beziehen sich immer noch auf "Zukunft". Wenn Sie "Future World" nennen müssen,

String s="Future";  
s=s.concat(" World");  
System.out.println(s);//print Future World

Warum sind String-Objekte in Java unveränderlich?

Weil Java das Konzept des String-Literal verwendet. Angenommen, es gibt 5 Referenzvariablen, die sich alle auf ein Objekt "Future" beziehen. Wenn eine Referenzvariable den Wert des Objekts ändert, wirkt sich dies auf alle Referenzvariablen aus. Deshalb sind String-Objekte in Java unveränderlich.


2

Einmal instanziiert, kann nicht mehr geändert werden. Stellen Sie sich eine Klasse vor, deren Instanz möglicherweise als Schlüssel für eine Hashtabelle oder ähnliches verwendet wird. Lesen Sie die Best Practices für Java.


0

Unveränderliche Objekte

Ein Objekt gilt als unveränderlich, wenn sich sein Zustand nach seiner Erstellung nicht ändern kann. Maximale Abhängigkeit von unveränderlichen Objekten wird allgemein als solide Strategie zur Erstellung von einfachem, zuverlässigem Code akzeptiert.

Unveränderliche Objekte sind besonders nützlich bei gleichzeitigen Anwendungen. Da sie den Status nicht ändern können, können sie nicht durch Thread-Interferenzen beschädigt oder in einem inkonsistenten Status beobachtet werden.

Programmierer zögern oft, unveränderliche Objekte zu verwenden, da sie sich Sorgen über die Kosten für die Erstellung eines neuen Objekts machen, anstatt ein vorhandenes Objekt zu aktualisieren. Die Auswirkungen der Objekterstellung werden häufig überschätzt und können durch einige der mit unveränderlichen Objekten verbundenen Effizienzvorteile ausgeglichen werden. Dazu gehören ein geringerer Overhead aufgrund der Speicherbereinigung und die Beseitigung von Code, der zum Schutz veränderlicher Objekte vor Beschädigung erforderlich ist.

Die folgenden Unterabschnitte nehmen eine Klasse, deren Instanzen veränderbar sind, und leiten daraus eine Klasse mit unveränderlichen Instanzen ab. Dabei geben sie allgemeine Regeln für diese Art der Konvertierung an und demonstrieren einige der Vorteile unveränderlicher Objekte.

Quelle


0

Da die akzeptierte Antwort nicht alle Fragen beantwortet. Ich bin gezwungen, nach 11 Jahren und 6 Monaten eine Antwort zu geben.

Kann jemand klarstellen, was unter unveränderlich zu verstehen ist?

Ich hoffe, Sie meinten ein unveränderliches Objekt (weil wir über unveränderliche Referenzen nachdenken konnten ).

Ein Objekt ist unveränderlich : Wenn es einmal erstellt wurde, stellen sie immer denselben Wert dar (es gibt keine Methode, die den Wert ändert).

Warum ist ein Stringunveränderlicher?

Beachten Sie die obige Definition, die durch einen Blick in den Quellcode von Sting.java überprüft werden kann.

Was sind die Vor- und Nachteile der unveränderlichen Objekte? unveränderliche Typen sind:

  • sicherer vor Insekten.

  • leichter zu verstehen.

  • und mehr bereit für Veränderungen.

Warum sollte ein veränderliches Objekt wie StringBuilder gegenüber String bevorzugt werden und umgekehrt?

Eingrenzen der Frage Warum brauchen wir den veränderlichen StringBuilder für die Programmierung? Es wird häufig verwendet, um eine große Anzahl von Zeichenfolgen wie folgt miteinander zu verknüpfen:

String s = "";
for (int i = 0; i < n; ++i) {
    s = s + n;
}

Bei Verwendung unveränderlicher Zeichenfolgen werden viele temporäre Kopien erstellt - die erste Nummer der Zeichenfolge ("0") wird im Verlauf des Aufbaus der endgültigen Zeichenfolge tatsächlich n-mal kopiert, die zweite Nummer wird n-1-mal kopiert und so weiter auf. Es kostet tatsächlich O (n2) Zeit, nur das ganze Kopieren durchzuführen, obwohl wir nur n Elemente verkettet haben.

StringBuilder wurde entwickelt, um dieses Kopieren zu minimieren. Es verwendet eine einfache, aber clevere interne Datenstruktur, um zu vermeiden, dass bis zum Ende kopiert wird, wenn Sie mit einem toString () -Aufruf nach dem endgültigen String fragen:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; ++i) {
  sb.append(String.valueOf(n));
}
String s = sb.toString();

Eine gute Leistung ist ein Grund, warum wir veränderbare Objekte verwenden. Ein weiterer Grund ist die bequeme Freigabe: Zwei Teile Ihres Programms können bequemer kommunizieren, indem Sie eine gemeinsame veränderbare Datenstruktur gemeinsam nutzen.

Weitere finden Sie hier: https://web.mit.edu/6.005/www/fa15/classes/09-immutability/#useful_immutable_types


-1

Ein unveränderliches Objekt können Sie nach dem Erstellen nicht mehr ändern. Ein typisches Beispiel sind String-Literale.

Die AD-Programmiersprache, die immer beliebter wird, hat den Begriff "Unveränderlichkeit" durch das Schlüsselwort "invariant". Lesen Sie den Artikel von Dr.Dobb darüber - http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29 . Es erklärt das Problem perfekt.


Ich glaube, dass ab D 2.020 das Schlüsselwort von invariant in unveränderlich geändert wurde. Ich sehe keinen Punkt, aber es heißt: "Unveränderlich ist jetzt implementiert." digitalmars.com/d/2.0/changelog.html#new2_020
he_the_great
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.