Ich konnte den Grund dafür nicht verstehen. Ich verwende die String-Klasse immer wie andere Entwickler, aber wenn ich den Wert ä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.
Antworten:
Parallelität
Java wurde von Anfang an unter Berücksichtigung der Parallelität definiert. Wie schon oft erwähnt, sind geteilte Variablen problematisch. Eine Sache kann eine andere hinter dem Rücken eines anderen Threads ändern, ohne dass dieser Thread davon Kenntnis hat.
Es gibt eine Vielzahl von Multithread-C ++ - Fehlern, die aufgrund eines gemeinsam genutzten Strings 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 dieser gleich bleibt.
Die "Lösung" für dieses Problem besteht darin, 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. Bei unveränderlichen Zeichenfolgen ist das Erstellen einer Kopie O (1), da es sich nicht um eine Kopie handelt, sondern um dasselbe Objekt, das nicht geändert werden kann.
In einer Multithread-Umgebung können unveränderliche Objekte immer sicher miteinander geteilt werden. Dies führt insgesamt zu einer Verringerung der Speichernutzung und verbessert das Zwischenspeichern von Speicher.
Sicherheit
Oft werden Zeichenfolgen als Argumente an Konstrukteure weitergegeben - Netzwerkverbindungen und Protokolle sind die beiden, die am einfachsten 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 glaubte, eine Verbindung zu einem Computer herzustellen, wurde jedoch zu einem anderen umgeleitet, aber alles im Objekt scheint mit dem ersten verbunden zu sein). es ist sogar die gleiche Zeichenfolge).
In Java kann man Reflection verwenden - und die Parameter dafür sind Strings. Die Gefahr, dass eine Zeichenfolge übergeben wird, 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änderbar wären und die Hash-Tabelle dies nicht schafft, könnte der Hash-Schlüssel in einiger Entfernung geändert werden.
Die Art und Weise, wie das Objekt in Java funktioniert, ist, dass alles einen Hash-Schlüssel hat (auf den über die Methode hashCode () zugegriffen wird). Ein unveränderlicher String bedeutet, dass der Hashcode zwischengespeichert werden kann. In Anbetracht der Häufigkeit, mit der Zeichenfolgen als Schlüssel für einen Hash verwendet werden, wird die Leistung erheblich gesteigert (anstatt dass der Hashcode jedes Mal neu berechnet werden muss).
Teilstrings
Indem der String unveränderlich ist, ist auch das zugrunde liegende Zeichenarray, das die Datenstruktur unterstützt, unveränderlich. Dadurch können bestimmte Optimierungen an der
substring
Methode vorgenommen werden (dies ist nicht unbedingt der Fall - es können auch Speicherverluste auftreten).Wenn Sie tun:
Der Wert von
bar
ist 'Meile'. Beidefoo
undbar
können jedoch durch dasselbe Zeichenarray gesichert werden, wodurch die Instanziierung von mehr Zeichenarrays reduziert oder kopiert wird - nur mit unterschiedlichen Start- und Endpunkten in der Zeichenfolge.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 ebenfalls durch das 1k lange Zeichenarray unterstützt würde. Dieses Array würde auch dann im Speicher verbleiben, wenn die ursprüngliche Zeichenfolge, die den Wert des gesamten Zeichen-Arrays enthielt, fehlerhaft erfasst worden wäre.
Dies ist in String aus JDK 6b14 zu sehen (der folgende Code stammt aus einer GPL v2-Quelle und wird als Beispiel verwendet).
Beachten Sie, dass die Teilzeichenfolge den String-Konstruktor auf Paketebene verwendet, bei dem das Array nicht kopiert werden muss und der viel schneller ist (möglicherweise auf Kosten einiger großer Arrays - obwohl auch keine großen Arrays dupliziert werden).
Beachten Sie, dass der obige Code für Java 1.6 ist. Die Art und Weise, wie der Konstruktor der Teilzeichenfolge implementiert wird, wurde mit Java 1.7 geändert ( siehe Änderungen an der internen Darstellung von Zeichenfolgen in Java 1.7.0_06) . Java wurde wahrscheinlich nicht als eine Sprache mit vielen Zeichenfolgenmanipulationen angesehen, und daher war die Leistungssteigerung für eine Teilzeichenfolge eine gute Sache. Bei riesigen XML-Dokumenten, die in Strings gespeichert sind, die niemals erfasst werden, wird dies zu einem Problem.
String
Daher wird die Verwendung desselben zugrunde liegenden Arrays mit einer Teilzeichenfolge geändert , sodass das größere Zeichenarray schneller erfasst werden kann.Missbrauche den Stapel nicht
Man könnte den Wert der Zeichenfolge anstelle des Verweises auf die unveränderliche Zeichenfolge übergeben, um Probleme mit der Veränderbarkeit zu vermeiden. Wenn Sie jedoch große Zeichenfolgen auf dem Stapel ablegen, wird dies dem System missbräuchlich. (Legen Sie ganze XML-Dokumente als Zeichenfolgen auf den Stapel und nehmen Sie sie dann ab oder leiten Sie sie weiter.)
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 dafür ansieht, warum unveränderliche Strings eine gute Sache sind, sollte man dies mit Sicherheit berücksichtigen.
Jeder, der ein bisschen mit Strings gearbeitet hat, weiß, dass er Erinnerungen lutschen kann. Dies gilt insbesondere dann, wenn Sie Daten aus Datenbanken abrufen, die eine Weile in der Nähe bleiben. Oftmals sind diese Stiche immer wieder dieselbe Saite (einmal für jede Reihe).
Mit Java 8 Update 20 wird JEP 192 (oben zitierte Motivation) implementiert, um dies zu beheben. Ohne näher auf die Funktionsweise der String-Deduplizierung einzugehen, ist es wichtig, dass die Strings selbst unveränderlich sind. Sie können StringBuilder nicht deduplizieren, da sie sich ändern können und Sie nicht möchten, dass jemand etwas unter Ihnen ändert. Unveränderliche Zeichenfolgen (im Zusammenhang mit diesem Zeichenfolgenpool) bedeuten, dass Sie durchgehen können. Wenn Sie zwei identische Zeichenfolgen finden, können Sie eine Zeichenfolgenreferenz auf die andere verweisen und den Garbage Collector die neu nicht verwendete Zeichenfolge verwenden lassen.
Andere Sprachen
Ziel C (welches vor Java liegt) hat
NSString
undNSMutableString
.C # und .NET haben dieselbe Entwurfsauswahl getroffen, bei der die Standardzeichenfolge unveränderlich ist.
Lua- Saiten sind ebenfalls unveränderlich.
Python auch.
In der Vergangenheit haben Lisp, Scheme, Smalltalk alle die Zeichenfolge interniert und müssen sie daher unveränderlich sein. Modernere dynamische Sprachen verwenden oft Strings in irgendeiner Art und Weise, dass sie sein unveränderlich erfordert (es ist nicht ein sein kann String , aber es ist unveränderlich).
Fazit
Diese gestalterischen Überlegungen wurden immer wieder in einer Vielzahl von Sprachen angestellt. Es besteht allgemeiner Konsens darüber, dass unveränderliche Zeichenfolgen trotz aller Ungeschicklichkeit besser sind als die Alternativen und zu besserem Code (weniger Bugs) und insgesamt schnelleren ausführbaren Dateien führen.
quelle
Gründe, an die ich mich erinnern kann:
Eine String-Pool-Funktion, ohne den String unveränderlich zu machen, ist überhaupt nicht möglich, da im Falle eines String-Pools ein String-Objekt / Literal, z. B. "XYZ", von vielen Referenzvariablen referenziert wird. Wenn sich also einer von ihnen ändert, wird der Wert der anderen automatisch beeinflusst .
Zeichenfolge wird häufig als Parameter für viele Java-Klassen verwendet, z. B. zum Öffnen der Netzwerkverbindung, zum Öffnen der Datenbankverbindung und zum Öffnen von Dateien. Wenn String nicht unveränderlich ist, würde dies zu einer ernsthaften Sicherheitsbedrohung führen.
Durch die Unveränderlichkeit kann String seinen Hashcode zwischenspeichern.
Macht es threadsicher.
quelle
1) String Pool
Java-Designer wissen, dass String in allen Arten von Java-Anwendungen der am häufigsten verwendete Datentyp sein wird, und deshalb wollten sie von Anfang an optimieren. Ein wichtiger Schritt in diese Richtung war die Idee, String-Literale im String-Pool zu speichern. Ziel war es, temporäre String-Objekte zu reduzieren, indem sie gemeinsam genutzt werden. Um sie gemeinsam nutzen zu können, müssen sie aus der Klasse Unveränderlich stammen. Sie können ein veränderbares Objekt nicht mit zwei unbekannten Parteien teilen. Nehmen wir ein hypothetisches Beispiel, in dem zwei Referenzvariablen auf dasselbe String-Objekt zeigen:
Wenn nun s1 das Objekt von "Java" in "C ++" ändert, hat die Referenzvariable auch den Wert s2 = "C ++", von dem sie nichts weiß. Indem String unveränderlich gemacht wurde, war dieses Teilen von String-Literal möglich. Kurz gesagt, die Schlüsselidee des String-Pools kann nicht implementiert werden, ohne String final oder Unveränderlich in Java zu machen.
2) Sicherheit
Java hat ein klares Ziel in Bezug auf die Bereitstellung einer sicheren Umgebung auf jeder Serviceebene, 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, zum Lesen von Dateien in Java können Sie den Pfad von Dateien und das Verzeichnis als String übergeben und zum Öffnen der Datenbankverbindung Datenbank-URL als String übergeben. Wenn String nicht unveränderlich war, hat ein Benutzer möglicherweise Zugriff auf eine bestimmte Datei im System gewährt. Nach der Authentifizierung kann er den Pfad jedoch in einen anderen ändern. Dies kann schwerwiegende Sicherheitsprobleme verursachen. Während der Verbindung mit der Datenbank oder einem anderen Computer im Netzwerk kann die Änderung des String-Werts ebenfalls Sicherheitsrisiken mit sich bringen. Veränderbare Zeichenfolgen können auch in Reflection Sicherheitsprobleme verursachen.
3) Verwendung von Fäden im Klassenlademechanismus
Ein weiterer Grund dafür, String final oder Immutable zu machen, war die Tatsache, dass er in Klassenlademechanismen häufig verwendet wurde. Da String nicht unveränderlich ist, kann ein Angreifer diese Tatsache ausnutzen und eine Anforderung zum Laden von Java-Standardklassen, z. B. java.io.Reader, in die böswillige Klasse com.unknown.DataStolenReader ändern. Indem wir String final und unveränderlich halten, können wir zumindest sicher sein, dass JVM die richtigen Klassen lädt.
4) Multithreading-Vorteile
Da Concurrency und Multi-Threading das Hauptangebot von Java waren, war es sehr sinnvoll, über die Thread-Sicherheit von String-Objekten nachzudenken. Da erwartet wurde, dass String in großem Umfang verwendet wird, bedeutet Unveränderlich keine externe Synchronisation, viel saubereren Code, der das Teilen von String zwischen mehreren Threads beinhaltet. Diese einzige Funktion erleichtert die komplizierte, verwirrende und fehleranfällige Parallelitätscodierung erheblich. Da String unveränderlich ist und nur zwischen Threads geteilt wird, führt dies zu besser lesbarem Code.
5) Optimierung und Leistung
Wenn Sie eine Klasse zu Unveränderlich machen, wissen Sie im Voraus, dass sich diese Klasse nach ihrer Erstellung nicht ändern wird. Dies garantiert einen offenen Pfad für viele Leistungsoptimierungen, z. B. Caching. String selbst weiß, dass ich nicht ändern werde, also zwischenspeichern String seinen Hashcode. Es berechnet sogar den Hashcode träge und sobald er erstellt wurde, kann er zwischengespeichert werden. Wenn Sie in einer einfachen Welt die Methode hashCode () eines beliebigen String-Objekts zum ersten Mal aufrufen, wird der Hash-Code berechnet, und alle nachfolgenden Aufrufe von hashCode () geben bereits berechnete, zwischengespeicherte Werte zurück. Dies führt zu einer guten Leistungssteigerung, da String in Hash-basierten Maps, z. B. Hashtable und HashMap, häufig verwendet wird. Das Zwischenspeichern von Hashcode war nicht möglich, ohne ihn unveränderlich und endgültig zu machen, da dies vom Inhalt von String selbst abhängt.
quelle
Die Java Virtual Machine führt verschiedene 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 einer anderen Zeichenfolge "Mississippi" .substring (0, 4) zugewiesen haben, wurde, soweit Sie wissen, eine Kopie der ersten vier Zeichen erstellt, um "Miss" zu erstellen. . Was Sie nicht wissen, ist, dass beide dieselbe ursprüngliche Zeichenfolge "Mississippi" gemeinsam haben, wobei die eine der Eigentümer ist und die andere eine Referenz dieser Zeichenfolge von Position 0 bis 4. (Die Referenz auf den Eigentümer verhindert, dass der Eigentümer von gesammelt wird der Müllsammler, wenn der Besitzer den Rahmen verlässt)
Dies ist trivial für eine Saite, die so klein wie "Mississippi" ist, aber bei größeren Saiten und mehreren Operationen ist es eine große Zeitersparnis, die Saite nicht kopieren zu müssen! Wenn Strings veränderbar wären, könnten Sie dies nicht tun, da das Ändern des Originals auch die "Kopien" des Teilstrings beeinflussen würde.
Außerdem würde, wie Donal erwähnt, der Vorteil durch seinen Nachteil stark beeinträchtigt. Stellen Sie sich vor, Sie schreiben ein Programm, das von einer Bibliothek abhängt, und Sie verwenden eine Funktion, die einen String zurückgibt. Wie können Sie sicher sein, dass dieser Wert konstant bleibt? Damit so etwas nicht passiert, müssten Sie immer eine Kopie vorlegen.
Was ist, wenn Sie zwei Threads haben, die dieselbe Zeichenfolge verwenden? Sie möchten nicht eine Zeichenfolge lesen, die gerade von einem anderen Thread umgeschrieben wird, oder? String müsste dann Thread-sicher sein, was die übliche Klasse ist, die praktisch jedes Java-Programm so viel langsamer macht. Andernfalls müssten Sie für jeden Thread, für den diese Zeichenfolge erforderlich ist, eine Kopie erstellen, oder Sie müssten den Code mithilfe dieser Zeichenfolge in einen Synchronisierungsblock einfügen, was beides Ihr Programm nur verlangsamt.
Aus all diesen Gründen war dies eine der ersten Entscheidungen, die für Java getroffen wurden, um sich von C ++ abzuheben.
quelle
Der Grund für die Unveränderlichkeit der Zeichenfolge liegt in der Übereinstimmung mit anderen primitiven Typen in der Sprache. Wenn Sie eine haben,
int
die den Wert 42 enthält, und den Wert 1 hinzufügen, ändern Sie die 42 nicht. Sie erhalten einen neuen Wert, 43, der völlig unabhängig von den Startwerten ist. Andere Grundelemente als Zeichenfolgen zu mutieren, ergibt keinen begrifflichen Sinn. und als solche sind Programme, die Zeichenfolgen als unveränderlich behandeln, oft einfacher zu überlegen und zu verstehen.Darüber hinaus bietet Java wirklich sowohl veränderbare als auch unveränderliche Zeichenfolgen, wie Sie sehen
StringBuilder
. Eigentlich ist nur die unveränderliche Zeichenfolge die Standardeinstellung . Wenn SieStringBuilder
überall Referenzen weitergeben möchten, können Sie dies gerne tun. Java verwendet für diese Konzepte separate Typen (String
undStringBuilder
), da es keine Unterstützung für das Ausdrücken von Veränderlichkeit oder deren Fehlen in seinem Typsystem gibt. In 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 Zeichenfolgen unveränderlich sind, können einige Optimierungen für unveränderliche Zeichenfolgen implementiert werden, z. B. Internierung. Außerdem können Zeichenfolgenreferenzen ohne Synchronisierung zwischen Threads weitergegeben werden. Dies verwechselt jedoch den Mechanismus mit dem angestrebten Ziel einer Sprache mit einem einfachen und konsistenten Typensystem. Ich vergleiche das damit, wie jeder falsch über Müllsammlung denkt; Speicherbereinigung ist nicht "Rückgewinnung von nicht verwendetem Speicher"; Es wird "ein Computer mit unbegrenztem Speicher simuliert" . Die besprochenen Leistungsoptimierungen dienen dazu, dass das Ziel unveränderlicher Zeichenfolgen auf realen Maschinen eine gute Leistung erbringt. nicht der Grund, warum solche Saiten überhaupt unveränderlich sind.
quelle
43 = 6
und erwarten, dass die Zahl 43 dasselbe wie die Zahl 6 bedeutet.i
, nicht 42. Überlegen Siestring s = "Hello "; s += "World";
. Sie haben den Wert der Variablen geänderts
. Aber die Saiten"Hello "
,"World"
und"Hello World"
unveränderlich sind.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 Java-Implementierung befinden, und zu den Zeichenfolgen, die nicht geändert werden sollten, gehören Sicherheitstoken, Dienstadressen usw. Sie sollten diese Sortierungen wirklich nicht ändern können von Dingen (und dies gilt doppelt, wenn im Sandkasten-Modus gearbeitet wird).
Wenn String nicht unveränderlich ist, müssen Sie jedes Mal, wenn Sie ihn aus einem Kontext abrufen, in dem der Inhalt des Strings nicht unter den Füßen geändert werden soll, eine Kopie "nur für den Fall" erstellen. Das wird sehr teuer.
quelle
String
. Aber zum Beispiel sindArray
s trotzdem veränderlich. Also, warum sindString
s unveränderlich undArray
s nicht. Und wenn Unveränderlichkeit so wichtig ist, warum macht es Java dann so schwierig, unveränderliche Objekte zu erstellen und damit zu arbeiten?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 a
String
und müssen mindestens 5 Zeichen lang sein. Ihre Methode sieht ungefähr so aus:Jetzt können wir uns darauf einigen, dass, wenn
storeInDatabase
hier aufgerufeninput
wird, die Anforderungen erfüllt werden. Aber wennString
wandelbar waren, dann wird der Anrufer konnte verändert dasinput
Objekt (von einem anderen Thread) direkt nach dem festgestellt wurde , und bevor es wurde in der Datenbank gespeichert . Dies würde ein gutes Timing erfordern und wahrscheinlich nicht jedes Mal gut gehen, aber gelegentlich kann er Sie dazu bringen, ungültige Werte in der Datenbank zu speichern.Unveränderliche Datentypen sind eine sehr einfach Lösung für dieses Problem (und viele ähnliche) Probleme: wenn Sie einen gewissen Wert überprüfen, können Sie abhängig von der Tatsache , dass die überprüfte Bedingung später noch wahr ist.
quelle
input
von derhandle
methode schon zu lang ist (egal was das originalinput
ist), würde es einfach eine ausnahme auslösen . Sie erstellen eine neue Eingabe, bevor Sie die Methode aufrufen. Das ist kein Problem.Im Allgemeinen werden Sie auf Werttypen und Referenztypen stoßen . Bei einem Wertetyp kümmert es Sie nicht um das Objekt, das ihn darstellt, sondern um den Wert. Wenn ich Ihnen einen Wert gebe, erwarten Sie, dass dieser Wert derselbe bleibt. Du willst nicht, dass es sich plötzlich ändert. Die Nummer 5 ist ein Wert. Sie erwarten nicht, dass es sich plötzlich auf 6 ändert. Die Zeichenfolge "Hallo" ist ein Wert. Sie erwarten nicht, dass es plötzlich auf "P *** off" wechselt.
Bei Referenztypen interessiert Sie das Objekt und Sie erwarten, dass es sich ändert. Beispielsweise werden Sie häufig erwarten, dass sich ein Array ändert. Wenn ich Ihnen ein Array gebe und Sie möchten, dass es genau so bleibt, wie es ist, müssen Sie mir entweder vertrauen, dass ich es nicht ändere, oder Sie erstellen eine Kopie davon.
Bei der Java-String-Klasse mussten die Designer eine Entscheidung treffen: Ist es besser, wenn sich Strings wie ein Werttyp verhalten, oder sollten sie sich wie ein Referenztyp verhalten? Bei Java-Strings wurde die Entscheidung getroffen, dass es sich um Werttypen handeln soll. Da es sich also um Objekte handelt, müssen es sich um unveränderliche Objekte handeln.
Die gegenteilige Entscheidung hätte getroffen werden können, aber meiner Meinung nach hätte dies 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. Zeichenfolgen können konstant oder nicht konstant sein. In C ++ können Objektparameter im Gegensatz zu Java jedoch als Werte und nicht als Referenzen übergeben werden.
quelle
Ich bin wirklich überrascht, dass niemand darauf hingewiesen hat.
Antwort: Es würde Ihnen keinen nennenswerten Nutzen bringen, selbst wenn es veränderlich wäre. Es würde Ihnen nicht so viel nützen, da dies zusätzliche Probleme verursacht. Untersuchen wir zwei der häufigsten Mutationsfälle:
Ändern eines Zeichens einer Zeichenfolge
Da jedes Zeichen in einer Java-Zeichenfolge entweder 2 oder 4 Bytes benötigt, fragen Sie sich, ob Sie etwas gewinnen würden, 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. Das ist nicht anders als das Kopieren des gesamten Strings aus rechnerischer Sicht.
Dies ist auch ein sehr unregelmäßiges Verhalten, das in der Regel unerwünscht ist. Stellen Sie sich vor, jemand testet eine Anwendung mit englischem Text, und wenn die Anwendung in einem anderen Land wie China eingeführt 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 ändern möchten, indem Sie den zweiten anhängen, können Sie nicht einfach zusätzlichen Speicher am Ende des ersten Strings anfordern, da dieser wahrscheinlich bereits belegt ist.
Sie müssen die verkettete Zeichenfolge an eine ganz neue Position kopieren. Dies ist genauso, als ob beide Zeichenfolgen unveränderlich wären.
Wenn Sie das Anhängen effizient durchführen möchten, können Sie das Programm verwenden
StringBuilder
, das am Ende einer Zeichenfolge ziemlich viel Speicherplatz reserviert, und zwar nur für diesen Zweck eines möglichen zukünftigen Anhängens.quelle
Sie sind teuer und können unveränderlich bleiben, beispielsweise wenn Unterzeichenfolgen das Byte-Array der Hauptzeichenfolge gemeinsam nutzen. (Geschwindigkeitssteigerung auch, da kein neues Byte-Array erstellt und kopiert werden muss)
Sicherheit - möchte nicht, dass Ihr Paket oder Klassencode umbenannt wird
[entfernte alte 3 sah sich StringBuilder src an - es teilt sich keinen Speicher mit String (bis geändert) Ich denke, das war in 1.3 oder 1.4]
Cache-Hashcode
für mutalble Strings verwenden Sie SB (Builder oder Buffer nach Bedarf)
quelle
Strings sollten in Java ein primitiver Datentyp sein. Wenn dies der Fall gewesen wäre, wären die Zeichenfolgen standardmäßig veränderbar, und das letzte Schlüsselwort würde unveränderliche Zeichenfolgen generieren. Veränderbare Zeichenfolgen sind nützlich, und daher gibt es mehrere Hacks für veränderbare Zeichenfolgen in den Klassen stringbuffer, stringbuilder und charsequence.
quelle