Wie soll ich Strings in Java kopieren?

198
    String s = "hello";
    String backup_of_s = s;
    s = "bye";

Zu diesem Zeitpunkt enthält die Sicherungsvariable noch den ursprünglichen Wert "Hallo" (dies liegt an der Unveränderlichkeit von String, oder?).

Aber ist es wirklich sicher , Strings mit dieser Methode zu kopieren (was natürlich nicht sicher ist, reguläre veränderbare Objekte zu kopieren), oder ist es besser, dies zu schreiben? ::

    String s = "hello";
    String backup_of_s = new String(s);
    s = "bye";

Mit anderen Worten, was ist der Unterschied (falls vorhanden) zwischen diesen beiden Schnipsel?


BEARBEITEN - der Grund, warum das erste Snippet sicher ist:

Lassen Sie mich die Dinge anhand der bereits gegebenen guten Antworten (die sich im Wesentlichen auf die Frage des Leistungsunterschieds zwischen den beiden Ausschnitten konzentrierten) etwas detaillierter erläutern:

Strings sind in Java unveränderlich, was bedeutet, dass ein String-Objekt nach seiner Erstellung nicht mehr geändert werden kann. Daher,

String s = "hello";Erstellt eine neue String-Instanz und weist ihre Adresse zu s( sals Referenz auf die Instanz / das Objekt).

String backup_of_s = s;Erstellt eine neue Variable backup_of_sund initialisiert sie so, dass sie auf das Objekt verweist, auf das aktuell verwiesen wird s.

Hinweis: Die Unveränderlichkeit von Zeichenfolgen garantiert, dass dieses Objekt nicht geändert wird: Unsere Sicherung ist sicher

Hinweis 2: Der Java-Garbage-Collection-Mechanismus garantiert, dass dieses Objekt nicht zerstört wird, solange es von mindestens einer Variablen referenziert wird ( backup_of_sin diesem Fall).

Schließlich wird s = "bye";eine weitere String-Instanz erstellt (aufgrund der Unveränderlichkeit ist dies der einzige Weg) und die sVariable so geändert , dass sie jetzt auf das neue Objekt verweist.

Sébastien
quelle

Antworten:

139

Da Zeichenfolgen unveränderlich sind, sind beide Versionen sicher. Letzteres ist jedoch weniger effizient (es erstellt ein zusätzliches Objekt und kopiert in einigen Fällen die Zeichendaten).

Vor diesem Hintergrund sollte die erste Version bevorzugt werden.

NPE
quelle
15
Unveränderlichkeit hat nichts damit zu tun. So funktionieren Objektreferenzen einfach. Ich könnte ein äquivalentes StringBuilder-Beispiel liefern.
GriffeyDog
1
@BalusC, ich kann nicht sehen, wie mit neuem String () etwas im String-Pool der JVM erstellt werden kann. Im Pool befinden sich nur String Litterals und solche, die über intern () in den Pool übernommen wurden.
Snicolas
3
@GriffeyDog: Ich lese die Frage weniger wörtlich. Was ich damit sagen möchte, ist, dass es sicher ist, Verweise auf ein Zeichenfolgenobjekt auszugeben, ohne befürchten zu müssen, dass jemand die Zeichenfolge ändert.
NPE
2
@GriffeyDog Ich finde Ihren Kommentar sehr irreführend: Unveränderlichkeit macht das erste Snippet sicher. Warum hat es nichts mit "es" zu tun?
Sébastien
5
@Sebastien Alles, was es tut, ist die Neuzuweisung der Referenzvariablen s, um auf ein anderes Objekt zu verweisen (das String"Tschüss"). Dies hat keinen Einfluss darauf, worauf sich die Referenzvariable backup_of_sbezieht (das String"Hallo"). Wie gesagt, ich könnte ein gleichwertiges Beispiel mit StringBuilders liefern , die nicht unveränderlich sind. Mein Kommentar bezieht sich hauptsächlich auf die OPs-Anweisung: Zu diesem Zeitpunkt enthält die Sicherungsvariable noch den ursprünglichen Wert "Hallo" (dies liegt an der Unveränderlichkeit von String, oder?).
GriffeyDog
22

Zeichenfolgen sind unveränderliche Objekte, sodass Sie sie kopieren können, indem Sie nur den Verweis auf sie kopieren, da sich das referenzierte Objekt nicht ändern kann ...

So können Sie problemlos wie in Ihrem ersten Beispiel kopieren:

String s = "hello";
String backup_of_s = s;
s = "bye";
aleroot
quelle
10

Ihre zweite Version ist weniger effizient, da sie ein zusätzliches Zeichenfolgenobjekt erstellt, wenn dies einfach nicht erforderlich ist.

Unveränderlichkeit bedeutet, dass sich Ihre erste Version so verhält, wie Sie es erwarten, und daher der bevorzugte Ansatz ist.

David Heffernan
quelle
0

Der zweite Fall ist auch in Bezug auf den String-Pool ineffizient. Sie müssen intern () bei der Rückgabereferenz explizit aufrufen, um ihn intern zu machen.

Amit Yadav
quelle
-16
String str1="this is a string";
String str2=str1.clone();

Wie wäre es mit einer Kopie wie dieser? Ich denke, eine neue Kopie zu bekommen ist besser, damit die Daten von str1nicht beeinflusst werden, wennstr2 referenziert und in einer weiteren Aktion geändert werden.

Cqiao13
quelle
3
Stringist unveränderlich. Das Klonen von Strings macht nicht viel Sinn.
Vladimir