Frage

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

  1. Kann jemand klären, was durch bedeutet unveränderlich ?
  2. Warum ist ein String unveränderlich?
  3. Was sind die Vorteile / Nachteile der unveränderlichen Objekte?
  4. Warum sollte ein veränderbares Objekt wie StringBuilder über String bevorzugt werden und umge Vers?

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

War es hilfreich?

Lösung

Immutable bedeutet, dass sobald der Konstruktor für ein Objekt der Ausführung abgeschlossen hat, dass Instanz kann nicht verändert werden.

Dies ist nützlich, da es bedeutet, dass Sie Verweise auf das Objekt passieren kann um, ohne sich Sorgen, dass jemand anderes seinen Inhalt ändern wird. Vor allem, wenn mit Concurrency Umgang, es gibt keine Probleme mit Sperren mit Objekten, die sich nie ändern

z.

class Foo
{
     private final String myvar;

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

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

Foo muss nicht befürchten, dass der Anrufer getValue() könnte den Text in der Zeichenfolge ändern.

Wenn Sie eine ähnliche Klasse vorstellen Foo, aber mit einem StringBuilder eher als einem String als Mitglied können Sie sehen, dass ein Anrufer wäre in der Lage zu getValue() das StringBuilder Attribute einer Foo Instanz zu ändern.

Passen Sie auch von den verschiedenen Arten von Unveränderlichkeit finden Sie vielleicht: Eric Lippert hat ein Blog-Artikel darüber. Grundsätzlich können Sie Objekte, deren Schnittstelle ist unveränderlich, aber hinter den Kulissen tatsächlich mutables privater Zustand (und daher nicht sicher zwischen Threads gemeinsam genutzt werden kann).

Andere Tipps

Ein unveränderliches Objekt ist ein Objekt, in dem die inneren Felder (oder zumindest alle internen Felder, die ihre äußere Verhalten beeinflussen) können nicht geändert werden.

Es gibt eine Menge von Vorteilen unveränderlichen Strings:

Performance: Nehmen Sie die folgende Operation:

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

Die zugrunde liegende C für die Methode substring () ist wahrscheinlich so etwas wie folgt aus:

// 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 keine der Zeichen kopiert werden! Wenn die String-Objekt wandelbar waren (die Zeichen später ändern könnte), dann würden Sie alle Zeichen kopieren, sonst Änderungen an Zeichen in der Teilzeichenfolge würde in der anderen Zeichenfolge später reflektiert werden.

Concurrency: Wenn die interne Struktur eines unveränderlichen Objekt gültig ist, wird es immer gültig sein. Es gibt keine Chance, dass verschiedene Threads einen ungültigen Zustand innerhalb dieses Objekt erstellen können. Daher unveränderliche Objekte sind Threadsicherheit .

Die Garbage-Collection:. Es ist viel einfacher für den Garbage Collector logische Entscheidungen über unveränderliche Objekte zu machen

Allerdings gibt es auch Schattenseiten zu Unveränderlichkeit:

Performance: Warten Sie, ich dachte, Sie sagten Leistung ein auf dem Kopf von Unveränderlichkeit war! Nun, es ist manchmal, aber nicht immer. Nehmen Sie den folgenden Code ein:

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

Die beiden Linien sowohl das vierte Zeichen mit dem Buchstaben „a“ ersetzen. Nicht nur ist das zweite Stück Code besser lesbar, es ist schneller. Schauen Sie, wie würden Sie den zugrunde liegenden Code für foo zu tun haben. Der Teil ist einfach, aber jetzt, weil es bereits ein Zeichen an Platz fünf und etwas anderes verweisen foo werden könnte, kann man nicht einfach ändern; Sie müssen die gesamte Zeichenfolge kopieren (natürlich einige dieser Funktionen in Funktionen in der realen zugrunde liegenden C abstrahiert, aber der Punkt ist, den Code zu zeigen, dass alle an einem Ort 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));

Hinweis erhält, dass concatenate genannt zweimal was bedeutet, dass die gesamte Zeichenfolge hat durchgeschleift werden! Vergleichen Sie dies mit dem C-Code für den bar Betrieb:

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

Die wandelbare String-Operation offensichtlich viel schneller ist.

Fazit: In den meisten Fällen wollen Sie eine unveränderliche Zeichenfolge. Aber wenn Sie eine Menge von Anhängen und Einfügen in einen String tun müssen, müssen Sie die Veränderlichkeit für die Geschwindigkeit. Wenn Sie die Parallelität Sicherheit und Garbage Collection Vorteile mit ihm den Schlüssel wollen, sind Ihre veränderbaren Objekte lokal auf ein Verfahren zu 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 die mutable Objekt eine lokale Referenz, Sie müssen nicht über die Parallelität Sicherheit sorgen (nur ein Thread berührt es überhaupt). Und da es nirgendwo anders verwiesen wird, wird es nur auf dem Stack zugeordnet, so wird es, sobald der Funktionsaufruf freigegeben beendet ist (Sie müssen nicht über die Garbage Collection kümmern). Und Sie erhalten alle Leistungsvorteile sowohl Veränderlichkeit und Unveränderlichkeit.

Eigentlich ist String nicht unveränderlich, wenn Sie die Wikipedia-Definition oben vorgeschlagen verwenden.

String Staat tut nach dem Bau ändern. Werfen Sie einen Blick auf die Hash-Code () -Methode. String speichert den Hash-Code-Wert in einem lokalen Feld jedoch nicht berechnet werden, bis es den ersten Aufruf von Hashcode (). Diese verzögerte Auswertung von Hash-Code platziert String in einer interessanten Position als unveränderliche Objekt, dessen Zustand ändert, aber es kann nicht ohne Reflexion geändert haben beobachtet werden.

Also vielleicht die Definition unveränderlich sollte ein Objekt sein, das nicht beobachtet werden kann, um sich geändert zu haben.

Wenn die Zustandsänderungen in einem unveränderlichen Objekt, nachdem es erstellt wurde, aber niemand kann es sehen (ohne Reflexion) ist das Objekt noch unveränderlich?

Unveränderliche Objekte sind Objekte, die programmatisch nicht geändert werden kann. Sie sind besonders gut für Multi-Threaded-Umgebungen oder andere Umgebungen, in denen mehr als ein Prozess der Lage ist, zu verändern (mutieren), um die Werte in einem Objekt.

Nur um zu klären, aber Stringbuilder ist eigentlich ein veränderbares Objekt, keine unveränderliche ein. Ein regulärer Java-String ist unveränderlich (was bedeutet, dass, sobald es erstellt wurde Sie nicht die zugrunde liegende Zeichenfolge ändern kannst, ohne das Objekt zu ändern).

Zum Beispiel, sagen wir mal, dass ich eine Klasse namens ColoredString, die einen String-Wert und einen 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 die ColoredString wandelbar sein, sagt, weil Sie (mutiert) eines seiner wichtigsten Eigenschaften, ohne eine neue ColoredString Klasse ändern können. Der Grund, warum das schlecht sein kann, ist zum Beispiel, sagen wir, Sie eine GUI-Anwendung, die mehrere Threads hat und Sie verwenden ColoredStrings Daten an 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 die Zeichenfolge immer erwarten, dass „Blue“ sein. Wenn ein anderer Thread, wurde jedoch von dieser Instanz ahold und dem Namen

blueString.setColor("Red");

würden Sie plötzlich und unerwartet wahrscheinlich, jetzt eine „Red“ string haben, wenn Sie eine „Blue“ wollte. Aus diesem Grunde sind fast unveränderliche Objekte immer dann bevorzugt, wenn die für Instanzen von Objekten vorbei. Wenn Sie einen Fall, wo veränderbare Objekte wirklich notwendig sind, dann würden Sie schützen typischerweise die objet nur um Kopien aus Ihrem spezifischen Bereich der Steuerung übergeben.

Zur Erinnerung, in Java, ist java.lang.String ein unveränderliches Objekt (es nicht geändert werden, sobald es erstellt wird) und java.lang.StringBuilder ist ein veränderliches Objekt, weil es ohne geändert werden kann eine neue Instanz zu schaffen.

  1. In großen Anwendungen ihre gemeinsame für Stringliterale große Speicherbits zu besetzen. So effizient den Speicher zu umgehen, weist die JVM einen Bereich "String Konstanten-Pool" genannt. ( Anmerkung in einem Speicher, dass auch ein nicht referenzierte String trägt, um einen char [], ein int für seine Länge, und eine andere für seine hashCode. für eine Reihe, dagegen ein Maximum von acht Bytes ist erforderlich, sofortigen )
  2. Wenn complier über einen Stringliteral kommt überprüft es, den Pool zu sehen, ob es eine identische wörtlichen bereits vorhanden ist. Und wenn man gefunden wird, wird der Verweis auf die neuen wörtlichen zum bestehenden String gerichtet und kein neues ‚Stringliteral Objekt‘ erstellt wird (das bestehende String einfach bekommt eine zusätzliche Referenz).
  3. Daraus folgt: String Veränderlichkeit spart Speicher ...
  4. Aber wenn eine der Variablen Wert zu ändern, eigentlich - es ist nur ihre Referenz, die sich geändert hat, nicht der Wert im Speicher (daher wird es nicht die anderen Variablen beeinflussen Referenzierung es), wie unten gesehen ....

String s1 = "Old 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 = "New 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‘ nicht ändern, aber die   Referenzgröße wurde so geändert, dass sie auf die neue Zeichenfolge bezieht.   Und wenn wir nicht s2 haben, „Old String“ noch im Gedächtnis sein würde, aber   wir werden es nicht zugreifen können ...

„unveränderlich“ bedeutet, dass Sie nicht Wert ändern können. Wenn Sie eine Instanz von String-Klasse haben, jede Methode, die Sie aufrufen, die den Wert zu ändern scheint, tatsächlich eine andere Zeichenfolge erstellen.

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

Änderungen zu erhalten, sollten Sie etwas tun     foo = foo.sustring (3);

Immutable vs wandelbar kann lustig sein, wenn Sie mit Sammlungen arbeiten. Überlegen Sie, was passiert, wenn Sie wandelbar verwenden Objekt als Schlüssel für Karte und ändern Sie den Wert (Tipp: denken über equals und hashCode).

java.time

Es ist vielleicht ein bisschen spät, aber sein, um zu verstehen, was ein unveränderliches Objekt ist, betrachten Sie das folgende Beispiel aus der neuen Java 8 Datum und Uhrzeit API ( java.time ). Wie Sie wahrscheinlich alle Datums Objekte aus Java 8 wissen unveränderlich so im folgenden Beispiel

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

Ausgabe:

  

2014.03.18

Dieses druckt im selben Jahr als Anfangsdatum, da die plusYears(2) ein neues Objekt zurückgibt, so das alte Datum noch unverändert ist, weil es ein unveränderliches Objekt ist. Sobald Sie es nicht weiter modifizieren erstellt und die Datumsvariablen immer noch auf sie.

das Codebeispiel sollte also erfassen und das neue Objekt verwenden, indem Sie diesen Anruf instanziiert und kehrte nach plusYears.

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

Date.toString () ... 2014.03.18

     

dateAfterTwoYears.toString () ... 2016.03.18

Ich mag die explaination von SCJP Sun Certified Programmer for Java 5 Study Guide .

  

Um Java mehr Speicher effizienter zu gestalten, die JVM Hebt einen speziellen Speicherbereich, der den Namen „String Konstanten-Pools.“ Wenn der Compiler eine Stringliteral trifft, prüft sie den Pool zu sehen, ob eine identische String bereits vorhanden ist. Wenn eine Übereinstimmung gefunden wird, wird der Verweis auf die neuen wörtlichen zum bestehenden String gerichtet ist, und kein neues Stringliteral Objekt erstellt wird.

Objekte, die unveränderlich sind, können nicht ihren Zustand geändert haben, nachdem sie erstellt wurden.

Es gibt drei Hauptgründe, unveränderliche Objekte zu verwenden, wann immer Sie können, von denen alle die Anzahl der Fehler reduzieren helfen Ihnen, in Ihrem Code vorstellen:

  • Es ist viel einfacher zu folgern, wie Sie Ihr Programm funktioniert, wenn Sie wissen, dass ein Zustand des Objekts kann nicht durch eine andere Methode
  • geändert werden
  • sind Unveränderliche Objekte automatisch Thread-sicher (vorausgesetzt, sie sind sicher veröffentlicht) so wird nie die Ursache für diese schwer zu pin-down sein Multithreading Bugs
  • Unveränderliche Objekte haben immer den gleichen Hash-Code, so können sie als Schlüssel in einer HashMap (oder ähnlichem) verwendet werden. Wenn der Hash-Code eines Element in einer Hash-Tabelle zu ändern, würde der Tabelleneintrag dann effektiv verloren, da Versuche, sie in der Tabelle finden würde an der falschen Stelle am Ende aussehen. Dies ist der Hauptgrund, dass String-Objekte sind unveränderlich -. Sie werden als HashMap Tasten häufig verwendete

Es gibt auch einige andere Optimierungen Sie in Code zu machen vielleicht in der Lage, wenn Sie wissen, dass der Zustand eines Objekt unveränderlich ist - Caching des berechneten Hash, zum Beispiel -. Aber diese sind Optimierungen und daher nicht annähernd so interessant

Eine Bedeutung mit dem zu tun hat, wie der Wert in dem Computer gespeichert ist, für einen .NET-String zum Beispiel, bedeutet dies, dass die Zeichenfolge im Speicher nicht geändert werden können, wenn Sie denken, dass Sie sie sind zu ändern, sind Sie in der Tat eine neue Zeichenfolge im Speicher zu schaffen und zeigt die vorhandenen variablen auf die neue Zeichenfolge (die nur ein Zeiger auf die tatsächliche Sammlung von Zeichen irgendwo anders ist).

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 s1 mit "Hallo" Wert in ihm erstellt wurde

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

s1="Bye": Das vorherige s1 Objekts Wert ändert sich nicht, weil s1 String-Typen hat und String-Typ ist ein unveränderlicher Typ, stattdessen Compiler ein neues String-Objekt mit „Bye“ Wert und s1 darauf verwies erstellen. hier, wenn wir s2 Wert drucken, wird das Ergebnis „Hallo“ nicht „Bye“, weil s2 zum vorherigen s1 Objekt referenziert, den „Hallo“ Wert hatte.

Immutable bedeutet, dass, sobald das Objekt erstellt wird, nicht ihre Mitglieder ändern. String ist unveränderlich, da Sie nicht ihren Inhalt verändern. Zum Beispiel:

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

In dem obigen Code, die String s1 nicht ändern, ein anderes Objekt (s2) wurde mit s1 erstellt.

Immutable bedeutet einfach unveränderlich oder als nicht änderbar. Sobald String-Objekt seiner Daten oder Zustand erstellt wird, können nicht geändert werden

Betrachten unten 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  
  }  
 }  

Idee unter Berücksichtigung unten Diagramm erhalten Lassen,

In diesem Diagramm können Sie neues Objekt sehen, wie „Future World“ geschaffen. Aber nicht „Future“ .Because String is immutable ändern. s, beziehen sich noch auf „Zukunft“. Wenn Sie "Future World" nennen,

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

Warum sind String-Objekte unveränderlich in Java?

  

Da Java das Konzept des Stringliteral verwendet. Angenommen, es gibt 5 Referenzvariablen, die alle beziehen sich auf ein Objekt „Future“ .Wenn eine Referenzgröße den Wert des Objekts ändert, wird es an alle Bezugsgrößen beeinflusst werden. Deshalb String-Objekte sind unveränderlich in Java.

Sobald instanziiert, kann nicht verändert werden. Betrachten wir eine Klasse, die eine Instanz könnte als Schlüssel für eine Hash-Tabelle oder ähnliche verwendet werden. Schauen Sie sich Java Best Practices.

unveränderliche Objekte

Ein Objekt wird als unveränderlich, wenn sein Zustand nicht, nachdem es aufgebaut ist, ändern. Maximale Vertrauen auf unveränderliche Objekte wird weithin als eine solide Strategie akzeptiert für die Erstellung von einfachen, zuverlässigen Code.

Unveränderliche Objekte sind besonders nützlich bei gleichzeitig ablaufenden Anwendungen. Da sie nicht den Zustand ändern können, können sie nicht durch Gewindeinterferenz oder beobachtet in einem inkonsistenten Zustand beschädigt werden.

Programmierer sind oft nur ungern unveränderliche Objekte verwenden, weil sie im Gegensatz zu den Kosten Sorgen um ein neues Objekt zu schaffen, um ein Objekt in Position zu aktualisieren. Die Auswirkungen der Objekterstellung wird oft überschätzt und kann durch einige der Effizienz mit unveränderlichen Objekten zugeordnet ausgeglichen werden. Dazu gehören verringerte Aufwand aufgrund Müllabfuhr, und die Beseitigung von Code benötigt veränderbare Objekte von Korruption zu schützen.

In den folgenden Abschnitten nehmen Sie eine Klasse, deren Instanzen sind wandelbar und leitet eine Klasse mit unveränderlichen Instanzen von ihm. Dabei geben sie die allgemeinen Regeln für diese Art der Umwandlung und einige der Vorteile der unveränderlichen Objekte zeigen.

Quelle

Orakel docs sagt

  

Ein Objekt wird als unveränderlich , wenn sein Zustand nicht, nachdem es ändern kann   ist konstruiert. Maximale Vertrauen auf unveränderliche Objekte ist weit verbreitet   als solide Strategie akzeptiert für die Erstellung von einfachen, zuverlässigen Code.

     

Unveränderliche Objekte sind besonders nützlich bei gleichzeitig ablaufenden Anwendungen.   Da sie nicht den Zustand ändern können, können sie nicht durch Gewinde beschädigt werden   Störungen oder in einem inkonsistenten Zustand beobachtet.

Ich mag diesen Satz aus der Post

  

Unveränderliche Objekte Parallelität Programmierung erleichtern

Ein unveränderliches Objekt ist, die Sie nicht ändern können, nachdem Sie es erstellen. Ein typisches Beispiel ist Stringliterale.

A D Programmiersprache, die immer beliebter wird, hat eine Vorstellung von „Unveränderlichkeit“ bis „invariant“ Schlüsselwort. Überprüfen Sie dieses Dr.Dobb Artikel über sie - http: // dobbscodetalk .com / index.php? option = com_myblog & show = Invariant-Strings.html & Itemid = 29 . Es erklärt das Problem perfekt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top