it-swarm.com.de

Warum ist String in Java unveränderlich?

Ich konnte den Grund dafür nicht verstehen. Ich verwende immer die String-Klasse wie andere Entwickler, aber wenn ich den Wert davon ändere, wird eine neue Instanz von String erstellt.

Was könnte der Grund für die Unveränderlichkeit der String-Klasse in Java sein?

Ich weiß, dass es einige Alternativen wie StringBuffer oder StringBuilder gibt. Es ist nur Neugier.

80
yfklon

Parallelität

Java wurde von Anfang an unter Berücksichtigung der Parallelität definiert. Wie oft erwähnt, sind gemeinsame Mutables problematisch. Eine Sache kann eine andere hinter der Rückseite eines anderen Threads ändern, ohne dass dieser Thread davon Kenntnis hat.

Es gibt eine Vielzahl von Multithread-C++ - Fehlern, die aufgrund einer gemeinsam genutzten Zeichenfolge aufgetreten sind. Ein Modul hielt es für sicher, Änderungen vorzunehmen, wenn ein anderes Modul im Code einen Zeiger darauf gespeichert hatte und erwartete, dass er gleich bleibt.

Die 'Lösung' dafür ist, dass jede Klasse eine defensive Kopie der veränderlichen Objekte erstellt, die an sie übergeben werden. Für veränderbare Zeichenfolgen ist dies O(n), um die Kopie zu erstellen. Für unveränderliche Zeichenfolgen ist das Erstellen einer Kopie O(1), da dies nicht der Fall ist Eine Kopie, das gleiche Objekt, das sich nicht ändern kann.

In einer Multithread-Umgebung können unveränderliche Objekte immer sicher miteinander geteilt werden. Dies führt zu einer allgemeinen Reduzierung der Speichernutzung und verbessert das Zwischenspeichern des Speichers.

Sicherheit

Oft werden Zeichenfolgen als Argumente an Konstruktoren weitergegeben - Netzwerkverbindungen und Protokolle sind die beiden, die am leichtesten in den Sinn kommen. Die Möglichkeit, dies zu einem unbestimmten Zeitpunkt später in der Ausführung zu ändern, kann zu Sicherheitsproblemen führen (die Funktion dachte, sie würde eine Verbindung zu einem Computer herstellen, wurde jedoch zu einem anderen umgeleitet, aber alles im Objekt sieht so aus, als wäre es mit dem ersten verbunden ... es ist sogar die gleiche Zeichenfolge).

In Java kann man Reflektion verwenden - und die Parameter dafür sind Zeichenfolgen. Die Gefahr, dass einer eine Zeichenfolge übergibt, die auf dem Weg zu einer anderen reflektierenden Methode geändert werden kann. Das ist sehr schlecht.

Schlüssel zum Hash

Die Hash-Tabelle ist eine der am häufigsten verwendeten Datenstrukturen. Die Schlüssel zur Datenstruktur sind sehr oft Zeichenfolgen. Unveränderliche Zeichenfolgen bedeuten, dass (wie oben) die Hash-Tabelle nicht jedes Mal eine Kopie des Hash-Schlüssels erstellen muss. Wenn Strings veränderlich wären und die Hash-Tabelle dies nicht gemacht hätte, wäre es möglich, dass etwas den Hash-Schlüssel in einiger Entfernung ändert.

Die Art und Weise, wie das Objekt in Java funktioniert) ist, dass alles einen Hash-Schlüssel hat (Zugriff über die hashCode () -Methode). Eine unveränderliche Zeichenfolge bedeutet, dass der hashCode zwischengespeichert werden kann. Wenn man bedenkt, wie oft Strings Wenn sie als Schlüssel für einen Hash verwendet werden, bedeutet dies eine erhebliche Leistungssteigerung (anstatt den Hash-Code jedes Mal neu berechnen zu müssen).

Teilzeichenfolgen

Wenn der String unveränderlich ist, ist auch das zugrunde liegende Zeichenarray, das die Datenstruktur unterstützt, unveränderlich. Dies ermöglicht, dass bestimmte Optimierungen an der substring -Methode vorgenommen werden (sie werden nicht notwendigerweise durchgeführt - es wird auch die Möglichkeit einiger eingeführt Speicherlecks auch).

Wenn Sie tun:

String foo = "smiles";
String bar = foo.substring(1,5);

Der Wert von bar ist 'Meile'. Sowohl foo als auch bar können jedoch von demselben Zeichenarray unterstützt werden, wodurch die Instanziierung weiterer Zeichenarrays verringert oder kopiert wird - nur mit unterschiedlichen Start- und Endpunkten innerhalb der Zeichenfolge.

 Foo | | (0, 6) 
 V v 
 Lächelt 
 ^^ 
 Bar | | (fünfzehn)

Der Nachteil davon (der Speicherverlust) ist, dass wenn man eine 1k lange Zeichenfolge hätte und die Teilzeichenfolge des ersten und zweiten Zeichens nehmen würde, diese auch durch das 1k lange Zeichenarray unterstützt würde. Dieses Array würde im Speicher bleiben, selbst wenn die ursprüngliche Zeichenfolge, die einen Wert des gesamten Zeichenarrays hatte, durch Müll gesammelt wurde.

Dies kann man in String aus JDK 6b14 sehen (der folgende Code stammt aus einer GPL v2-Quelle und wird als Beispiel verwendet)

   public String(char value[], int offset, int count) {
       if (offset < 0) {
           throw new StringIndexOutOfBoundsException(offset);
       }
       if (count < 0) {
           throw new StringIndexOutOfBoundsException(count);
       }
       // Note: offset or count might be near -1>>>1.
       if (offset > value.length - count) {
           throw new StringIndexOutOfBoundsException(offset + count);
       }
       this.offset = 0;
       this.count = count;
       this.value = Arrays.copyOfRange(value, offset, offset+count);
   }

   // Package private constructor which shares value array for speed.
   String(int offset, int count, char value[]) {
       this.value = value;
       this.offset = offset;
       this.count = count;
   }

   public String substring(int beginIndex, int endIndex) {
       if (beginIndex < 0) {
           throw new StringIndexOutOfBoundsException(beginIndex);
       }
       if (endIndex > count) {
           throw new StringIndexOutOfBoundsException(endIndex);
       }
       if (beginIndex > endIndex) {
           throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
       }
       return ((beginIndex == 0) && (endIndex == count)) ? this :
           new String(offset + beginIndex, endIndex - beginIndex, value);
   }

Beachten Sie, wie der Teilstring den String-Konstruktor auf Paketebene verwendet, der kein Kopieren des Arrays beinhaltet und viel schneller wäre (auf Kosten der Möglichkeit, einige große Arrays zu behalten - obwohl auch keine großen Arrays dupliziert werden).

Beachten Sie, dass der obige Code für Java 1.6. Gilt. Die Art und Weise, wie der Teilzeichenfolgenkonstruktor implementiert wird, wurde mit Java 1.7 geändert, wie in Änderungen an.) Dokumentiert) Interne Zeichenfolgendarstellung in Java 1.7.0_06 - das Problem mit dem oben erwähnten Speicherverlust. Java wurde wahrscheinlich nicht als solches angesehen Eine Sprache mit vielen String-Manipulationen und daher war die Leistungssteigerung für einen Teilstring eine gute Sache. Jetzt, da riesige XML-Dokumente in Strings gespeichert sind, die nie gesammelt werden, wird dies zu einem Problem ... und damit zur Änderung des String verwendet nicht dasselbe zugrunde liegende Array mit einem Teilstring, sodass das größere Zeichenarray schneller erfasst werden kann.

Missbrauche den Stapel nicht

Ein könnte den Wert der Zeichenfolge anstelle des Verweises auf die unveränderliche Zeichenfolge weitergeben, um Probleme mit der Veränderlichkeit zu vermeiden. Bei großen Zeichenfolgen wäre es jedoch ... missbräuchlich, dies auf dem Stapel zu übergeben (ganze XML-Dokumente als Zeichenfolgen auf den Stapel zu legen und sie dann abzunehmen oder weiterzuleiten ...).

Die Möglichkeit der Deduplizierung

Zugegeben, dies war keine anfängliche Motivation dafür, warum Strings unveränderlich sein sollten, aber wenn man sich die Gründe ansieht, warum unveränderliche Strings eine gute Sache sind, ist dies sicherlich etwas zu beachten.

Jeder, der ein bisschen mit Strings gearbeitet hat, weiß, dass er Gedächtnis saugen kann. Dies gilt insbesondere dann, wenn Sie beispielsweise Daten aus Datenbanken abrufen, die eine Weile bestehen bleiben. Bei diesen Stichen handelt es sich häufig immer wieder um dieselbe Saite (einmal für jede Reihe).

Viele große Java -Anwendungen haben derzeit einen Speicherengpass. Messungen haben gezeigt, dass ungefähr 25% des Java-Heap-Live-Datensatzes in diesen Anwendungstypen vorhanden sind) Von String-Objekten verbraucht. Außerdem ist ungefähr die Hälfte dieser String-Objekte Duplikate, wobei Duplikate bedeuten, dass string1.equals (string2) wahr ist. Doppelte String-Objekte auf dem Heap zu haben, ist im Wesentlichen nur eine Verschwendung von Speicher. ...

Mit Java 8 Update 20, JEP 192 (oben zitierte Motivation) wird implementiert, um dies zu beheben. Ohne auf die Details der Funktionsweise der String-Deduplizierung einzugehen, ist dies unerlässlich dass die Strings selbst unveränderlich sind. Sie können StringBuilder nicht deduplizieren, weil sie sich ändern können und Sie nicht möchten, dass jemand etwas unter Ihnen ändert. Unveränderliche Strings (im Zusammenhang mit diesem String-Pool) bedeuten, dass Sie durchlaufen können und wenn Sie zwei finden Wenn die Zeichenfolgen identisch sind, können Sie eine Zeichenfolgenreferenz auf die andere verweisen und den Garbage Collector die neu verwendete nicht verwendete verwenden lassen.

Andere Sprachen

Ziel C (vor Java) hat NSString und NSMutableString.

C # und .NET haben die gleichen Entwurfsentscheidungen getroffen, wobei die Standardzeichenfolge unveränderlich ist.

Lua Strings sind ebenfalls unveränderlich.

Python auch.

Historisch gesehen sind LISP, Scheme, Smalltalk all intern the string und damit unveränderlich. In moderneren dynamischen Sprachen werden Zeichenfolgen häufig auf eine Weise verwendet, die erfordert, dass sie unveränderlich sind (es kann sich nicht um eine Zeichenfolge handeln, sie ist jedoch unveränderlich).

Fazit

Diese Entwurfsüberlegungen wurden immer wieder in einer Vielzahl von Sprachen gemacht. Es besteht allgemeiner Konsens darüber, dass unveränderliche Zeichenfolgen trotz all ihrer Unbeholfenheit besser sind als die Alternativen und zu besserem Code (weniger Fehler) und insgesamt schnelleren ausführbaren Dateien führen.

105
user40980

Gründe, an die ich mich erinnern kann:

  1. Eine String-Pool-Funktion, ohne einen String unveränderlich zu machen, ist überhaupt nicht möglich, da im Fall eines String-Pools ein String-Objekt/Literal, z. "XYZ" wird von vielen Referenzvariablen referenziert. Wenn sich also eine von ihnen ändert, wird der Wert, den andere ändern, automatisch beeinflusst.

  2. String wurde häufig als Parameter für viele Java -Klassen verwendet, z. B. zum Öffnen einer Netzwerkverbindung, zum Öffnen einer Datenbankverbindung und zum Öffnen von Dateien. Wenn String nicht unveränderlich ist, würde dies zu einer ernsthaften Sicherheitsbedrohung führen.

  3. Durch die Unveränderlichkeit kann String seinen Hashcode zwischenspeichern.

  4. Macht es threadsicher.

21
NINCOMPOOP

1) String Pool

Der Java-Designer weiß, dass String der am häufigsten verwendete Datentyp in allen Arten von Java -Anwendungen) sein wird, und deshalb wollten sie von Anfang an optimieren. Ein wichtiger Schritt in diese Richtung war die Idee, String zu speichern Literale im String-Pool. Ziel war es, temporäre String-Objekte durch gemeinsame Nutzung zu reduzieren. Um sie gemeinsam zu nutzen, müssen sie aus einer unveränderlichen Klasse stammen. Sie können ein veränderliches Objekt nicht mit zwei Parteien teilen, die einander unbekannt sind hypothetisches Beispiel, bei dem zwei Referenzvariablen auf dasselbe String-Objekt zeigen:

String s1 = "Java";
String s2 = "Java";

Wenn s1 das Objekt von "Java" in "C++" ändert, hat die Referenzvariable auch den Wert s2 = "C++", von dem sie nicht einmal weiß. Indem String unveränderlich gemacht wurde, war diese gemeinsame Nutzung des String-Literal möglich. Kurz gesagt, die Schlüsselidee des String-Pools kann nicht implementiert werden, ohne String in Java endgültig oder unveränderlich zu machen.

2) Sicherheit

Java hat ein klares Ziel in Bezug auf die Bereitstellung einer sicheren Umgebung auf allen Serviceebenen, und String ist für diese gesamten Sicherheitsaspekte von entscheidender Bedeutung. String wurde häufig als Parameter für viele Java Klassen verwendet, z. B. zum Öffnen der Netzwerkverbindung können Sie Host und Port als String übergeben, um Dateien in Java) zu lesen Sie können den Pfad von Dateien und Verzeichnissen als Zeichenfolge übergeben und zum Öffnen der Datenbankverbindung die Datenbank-URL als Zeichenfolge übergeben. Wenn Zeichenfolge nicht unveränderlich war, hat ein Benutzer möglicherweise den Zugriff auf eine bestimmte Datei im System gewährt, kann diese jedoch nach der Authentifizierung ändern PATH zu etwas anderem, dies kann schwerwiegende Sicherheitsprobleme verursachen. Während der Verbindung mit einer Datenbank oder einem anderen Computer im Netzwerk kann der mutierende Zeichenfolgenwert Sicherheitsbedrohungen darstellen. Veränderbare Zeichenfolgen können auch in Reflection Sicherheitsprobleme verursachen, da die Parameter Zeichenfolgen sind .

3) Verwendung eines Strings im Klassenlademechanismus

Ein weiterer Grund für die endgültige oder unveränderliche Verwendung von String war die Tatsache, dass er häufig im Klassenlademechanismus verwendet wurde. Da String nicht unveränderlich war, kann ein Angreifer diese Tatsache ausnutzen und eine Anforderung zum Laden von Standardklassen Java Klassen, z. B. Java.io.Reader, kann in die böswillige Klasse com.unknown.DataStolenReader. By geändert werden Wenn wir String endgültig und unveränderlich halten, können wir zumindest sicher sein, dass JVM die richtigen Klassen lädt.

4) Multithreading-Vorteile

Da Parallelität und Multithreading das Schlüsselangebot von Java waren, war es sehr sinnvoll, über die Thread-Sicherheit von String-Objekten nachzudenken. Da erwartet wurde, dass String weit verbreitet ist und unveränderlich ist, bedeutet dies keine externe Synchronisation. Dies bedeutet viel saubereren Code, bei dem String zwischen mehreren Threads geteilt wird. Diese einzige Funktion erleichtert die bereits komplizierte, verwirrende und fehleranfällige Parallelitätscodierung erheblich. Da String unveränderlich ist und wir ihn nur zwischen Threads teilen, führt dies zu besser lesbarem Code.

5) Optimierung und Leistung

Wenn Sie eine Klasse unveränderlich machen, wissen Sie im Voraus, dass sich diese Klasse nach ihrer Erstellung nicht ändern wird. Dies garantiert einen offenen Weg für viele Leistungsoptimierungen, z. Caching. String selbst weiß das, ich werde es nicht ändern, also speichert String seinen Hashcode. Der Hashcode wird sogar träge berechnet und nach der Erstellung einfach zwischengespeichert. In einer einfachen Welt berechnet der erste Aufruf der hashCode () -Methode eines beliebigen String-Objekts den Hash-Code und alle nachfolgenden Aufrufe von hashCode () geben den bereits berechneten, zwischengespeicherten Wert zurück. Dies führt zu einem guten Leistungsgewinn, da String in Hash-basierten Maps, z. Hashtable und HashMap. Das Zwischenspeichern von Hashcode war nicht möglich, ohne ihn unveränderlich und endgültig zu machen, da dies vom Inhalt des Strings selbst abhängt.

7
saidesh kilaru

Die Java Virtual Machine führt mehrere Optimierungen in Bezug auf Zeichenfolgenoperationen durch, die sonst nicht ausgeführt werden könnten. Wenn Sie beispielsweise eine Zeichenfolge mit dem Wert "Mississippi" hatten und "Mississippi" .substring (0) zugewiesen haben , 4) zu einer anderen Zeichenfolge, soweit Sie wissen, wurde eine Kopie der ersten vier Zeichen erstellt, um "Miss" zu machen. Was Sie nicht wissen, ist, dass beide dieselbe ursprüngliche Zeichenfolge "Mississippi" teilen, wobei eine der Eigentümer ist und die andere ist eine Referenz dieser Zeichenfolge von Position 0 bis 4. (Die Referenz auf den Eigentümer verhindert, dass der Eigentümer vom Garbage Collector erfasst wird, wenn der Eigentümer den Gültigkeitsbereich verlässt.)

Dies ist für eine Zeichenfolge so klein wie "Mississippi" trivial, aber bei größeren Zeichenfolgen und mehreren Operationen ist es eine große Zeitersparnis, die Zeichenfolge nicht kopieren zu müssen! Wenn Zeichenfolgen veränderbar wären, könnten Sie dies nicht tun, da sich das Ändern des Originals auch auf die "Kopien" der Teilzeichenfolge auswirken würde.

Wie Donal erwähnt, würde der Vorteil durch seinen Nachteil stark belastet. Stellen Sie sich vor, Sie schreiben ein Programm, das von einer Bibliothek abhängt, und Sie verwenden eine Funktion, die eine Zeichenfolge zurückgibt. Wie können Sie sicher sein, dass dieser Wert konstant bleibt? Um sicherzustellen, dass so etwas nicht passiert, müssten Sie immer eine Kopie erstellen.

Was ist, wenn zwei Threads dieselbe Zeichenfolge verwenden? Sie möchten nicht eine Zeichenfolge lesen, die gerade von einem anderen Thread neu geschrieben wird, oder? String müsste dann daher threadsicher sein, was die übliche Klasse ist, die praktisch jedes Java Programm so viel langsamer macht. Andernfalls müssten Sie für jedes eine Kopie erstellen Thread, für den diese Zeichenfolge erforderlich ist, oder Sie müssten den Code mithilfe dieser Zeichenfolge in einen Synchronisierungsblock einfügen, die beide Ihr Programm nur verlangsamen.

Aus all diesen Gründen war dies eine der frühen Entscheidungen für Java, um sich von C++ zu unterscheiden.

5
Neil

Der Grund für die Unveränderlichkeit des Strings liegt in der Konsistenz mit anderen primitiven Typen in der Sprache. Wenn Sie ein int haben, das den Wert 42 enthält, und den Wert 1 hinzufügen, ändern Sie das 42 nicht. Sie erhalten einen neuen Wert 43, der völlig unabhängig von den Startwerten ist. Das Mutieren anderer Primitive als der Zeichenfolge macht konzeptionell keinen Sinn. Daher sind Programme, die Zeichenfolgen als unveränderlich behandeln, oft leichter zu verstehen und zu verstehen.

Außerdem ist Java bietet wirklich sowohl veränderbare als auch unveränderliche Zeichenfolgen, wie Sie mit StringBuilder sehen; wirklich ist nur die Standard die unveränderliche Zeichenfolge. Wenn Sie überall Verweise auf StringBuilder weitergeben möchten, können Sie dies gerne tun. Java verwendet separate Typen (String und StringBuilder) für diese Konzepte, da es keine Unterstützung für das Ausdrücken von Veränderlichkeit oder deren Fehlen in seinem Typsystem bietet Sprachen, die Unveränderlichkeit in ihren Typsystemen unterstützen (z. B. C++ const), gibt es häufig einen einzelnen Zeichenfolgentyp, der beiden Zwecken dient.

Ja, wenn die Zeichenfolge unveränderlich ist, können einige Optimierungen implementiert werden, die für unveränderliche Zeichenfolgen spezifisch sind, z. B. das Internieren, und es können Zeichenfolgenreferenzen ohne Synchronisierung über Threads hinweg weitergegeben werden. Dies verwechselt den Mechanismus jedoch mit dem beabsichtigten Ziel einer Sprache mit einem einfachen und konsistenten Typsystem. Ich vergleiche das damit, wie jeder falsch über die Müllabfuhr denkt. Garbage Collection ist nicht "Rückgewinnung von nicht verwendetem Speicher"; es ist "Simulation eines Computers mit unbegrenztem Speicher" . Die besprochenen Leistungsoptimierungen sind Dinge, die getan werden, um das Ziel unveränderlicher Zeichenfolgen auf realen Maschinen gut zu machen. nicht der Grund dafür, dass solche Saiten überhaupt unveränderlich sind.

5
Billy ONeal

Unveränderlichkeit bedeutet, dass Konstanten von Klassen, die Sie nicht besitzen, nicht geändert werden können. Zu den Klassen, die Sie nicht besitzen, gehören diejenigen, die sich im Kern der Implementierung von Java befinden, und Zeichenfolgen, die nicht geändert werden sollten, umfassen Dinge wie Sicherheitstoken, Dienstadressen usw. Sie wirklich sollten nicht ' Sie können diese Art von Dingen nicht ändern (und dies gilt doppelt, wenn Sie im Sandbox-Modus arbeiten).

Wenn String nicht unveränderlich wäre, müssten Sie jedes Mal, wenn Sie ihn aus einem Kontext abrufen, in dem der Inhalt des Strings nicht geändert werden soll, eine Kopie "nur für den Fall" erstellen. Das wird sehr teuer.

4
Donal Fellows

Stellen Sie sich ein System vor, in dem Sie einige Daten akzeptieren, ihre Richtigkeit überprüfen und dann weitergeben (um sie beispielsweise in einer Datenbank zu speichern).

Angenommen, die Daten sind String und müssen mindestens 5 Zeichen lang sein. Ihre Methode sieht ungefähr so ​​aus:

public void handle(String input) {
  if (input.length() < 5) {
    throw new IllegalArgumentException();
  }
  storeInDatabase(input);
}

Jetzt können wir uns darauf einigen, dass wenn storeInDatabase hier aufgerufen wird, das input der Anforderung entspricht. Aber Wenn String veränderlich wäre, könnte der Aufrufer das input Objekt ( von einem anderen Thread) direkt nachdem es überprüft wurde und bevor es in der Datenbank gespeichert wurde . Dies würde ein gutes Timing erfordern und wahrscheinlich nicht jedes Mal gut gehen, aber gelegentlich könnte er Sie dazu bringen, ungültige Werte in der Datenbank zu speichern .

Unveränderliche Datentypen sind eine sehr einfache Lösung für dieses (und viele verwandte) Probleme: Wenn Sie einen Wert überprüfen, können Sie abhängig davon, dass die überprüfte Bedingung später noch erfüllt ist.

2
Joachim Sauer

Im Allgemeinen werden Sie auf Werttypen und Referenztypen stoßen. Bei einem Werttyp interessiert Sie das Objekt, das ihn darstellt, nicht, sondern der Wert. Wenn ich Ihnen einen Wert gebe, erwarten Sie, dass dieser Wert gleich bleibt. Sie wollen nicht, dass es sich plötzlich ändert. Die Zahl 5 ist ein Wert. Sie erwarten nicht, dass es plötzlich auf 6 wechselt. Die Zeichenfolge "Hallo" ist ein Wert. Sie erwarten nicht, dass es plötzlich zu "P *** off" wechselt.

Mit Referenztypen interessiert Sie das Objekt und Sie erwarten, dass es sich ändert. Beispielsweise erwarten Sie häufig, dass sich ein Array ändert. Wenn ich Ihnen ein Array gebe und Sie es genau so lassen möchten, wie es ist, müssen Sie mir entweder vertrauen, dass ich es nicht ändere, oder Sie erstellen eine Kopie davon.

Bei der Zeichenfolgenklasse Java) mussten die Designer eine Entscheidung treffen: Ist es besser, wenn sich Zeichenfolgen wie ein Werttyp verhalten, oder sollten sie sich wie ein Referenztyp verhalten? Im Fall von Java Strings, die Entscheidung wurde getroffen, dass sie Werttypen sein sollten, was bedeutet, dass sie unveränderliche Objekte sein müssen, da sie Objekte sind.

Die gegenteilige Entscheidung hätte getroffen werden können, aber meiner Meinung nach hätte es viele Kopfschmerzen verursacht. Wie bereits an anderer Stelle erwähnt, haben viele Sprachen dieselbe Entscheidung getroffen und sind zu demselben Ergebnis gekommen. Eine Ausnahme ist C++ mit einer Zeichenfolgenklasse, und Zeichenfolgen können konstant oder nicht konstant sein. In C++ können Objektparameter jedoch im Gegensatz zu Java als Werte und nicht als Referenzen übergeben werden.

0
gnasher729

Ich bin wirklich überrascht, dass niemand darauf hingewiesen hat.

Antwort: Es würde Ihnen keinen wesentlichen Nutzen bringen, selbst wenn es veränderlich wäre. Es würde Ihnen nicht so viel nützen, da dies zusätzliche Probleme verursacht. Lassen Sie uns zwei häufigste Mutationsfälle untersuchen:

Ändern eines Zeichens einer Zeichenfolge

Da jedes Zeichen in einer Java Zeichenfolge entweder 2 oder 4 Bytes benötigt, fragen Sie sich, würden Sie etwas gewinnen, wenn Sie die vorhandene Kopie mutieren könnten?

In dem Szenario, in dem Sie ein 2-Byte-Zeichen durch ein 4-Byte-Zeichen ersetzen (oder umgekehrt), müssen Sie den verbleibenden Teil der Zeichenfolge um 2 Byte nach links oder rechts verschieben. Was sich aus rechnerischer Sicht nicht wesentlich vom Kopieren der gesamten Zeichenfolge unterscheidet.

Dies ist auch ein wirklich unregelmäßiges Verhalten, das im Allgemeinen unerwünscht ist. Stellen Sie sich vor, jemand testet eine Anwendung mit englischem Text, und wenn die Anwendung in fremde Länder wie China übernommen wird, funktioniert das Ganze merkwürdig.

Anhängen einer anderen Zeichenfolge (oder eines anderen Zeichens) an die vorhandene Zeichenfolge

Wenn Sie zwei beliebige Zeichenfolgen haben, befinden sich diese an zwei unterschiedlichen Speicherorten. Wenn Sie den ersten durch Anhängen des zweiten ändern möchten, können Sie nicht einfach zusätzlichen Speicher am Ende der ersten Zeichenfolge anfordern, da diese wahrscheinlich bereits belegt ist.

Sie müssen die verkettete Zeichenfolge an einen völlig neuen Speicherort kopieren, was genau so ist, als ob beide Zeichenfolgen unveränderlich wären.

Wenn Sie Anhänge effizient ausführen möchten, sollten Sie StringBuilder verwenden, das am Ende einer Zeichenfolge ziemlich viel Speicherplatz reserviert, nur für den Zweck eines möglichen zukünftigen Anhängens.

0
Rok Kralj