Ist "new String ()" auch unveränderlich?

73

Ich habe Java String für eine Weile studiert. Die folgenden Fragen basieren auf den folgenden Beiträgen

Java String ist eine spezielle
Unveränderlichkeit von String in Java

  1. Unveränderlichkeit: Nach der Unveränderlichkeit wurde die String-Klasse so konzipiert, dass die Werte im gemeinsamen Pool an anderen Stellen / Variablen wiederverwendet werden können. Dies gilt, wenn das Stringals erstellt wurde

    String a = "Hello World!"; Allerdings, wenn ich String wie erstelle

    String b = new String("Hello World!"); Warum ist das auch unveränderlich? (oder ist es?). Da dies einen dedizierten Heap-Speicher hat, sollte ich dies ändern können, ohne andere Variablen zu beeinflussen. Gab es also einen anderen Grund, warum Stringinsgesamt als unveränderlich angesehen wird? Oder ist meine obige Annahme falsch?

  2. Das zweite, was ich fragen wollte, war über den gemeinsamen String-Pool . Wenn ich ein String-Objekt als erstelle

    String c = ""; Wird im Pool ein leerer Eintrag erstellt?

Gibt es schon einen Beitrag dazu? Wenn ja, könnte jemand den Link teilen?

Irgendein Typ
quelle
1
Ich denke, es wäre gut zu erfahren, wie nützlich es ist, unveränderliche Objekte überhaupt zu haben, nicht nur für Zeichenfolgen. Ein zufälliger Google-Treffer ist javapractices.com/topic/TopicAction.do?Id=29 . Wenn Sie wissen, dass eine Klasse unveränderlich ist, wird die Verwendung in vielerlei Hinsicht viel einfacher.
RemcoGerlich
Konzept Referenz: Einführung und Grundlagen der Zeichenfolge
Kein Fehler
3
Verwechseln Sie "Unveränderlichkeit" nicht mit einem "gemeinsamen Pool" - sie sind nicht dasselbe. Es ist durchaus möglich, dass Sie einen eigenen Typ erstellen, einen unveränderlichen Typ, und keinen "gemeinsamen Pool" verwenden. Ihre Frage ist keine "Frage", sondern eine Reihe falscher Aussagen.
Aaron McDaid
Konzentrieren Sie sich zuerst auf die Grundlagen, bevor Sie sich um etwas anderes kümmern. Wenn Sie kein klares Verständnis der Unveränderlichkeit haben, sollten Sie nichts über den String-Pool lernen. Unveränderlichkeit ist ein Schlüsselkonzept zum Lernen, das sprachunabhängig ist.
Trevor-E

Antworten:

105

new String()ist ein Ausdruck, der ein String... erzeugt, und a Stringist unveränderlich, egal wie es erzeugt wird.

(Zu fragen, ob new String()veränderlich ist oder nicht, ist unsinnig. Es ist Programmcode, kein Wert. Aber ich gehe davon aus, dass Sie das nicht wirklich gemeint haben.)


Wenn ich ein String-Objekt erstelle, wie String c = "";wird ein leerer Eintrag im Pool erstellt?

Ja; Das heißt, für die leere Zeichenfolge wird ein Eintrag erstellt. Es ist nichts Besonderes an einem leeren String.

(Um pedantisch zu sein, wird der Pooleintrag für ""lange vor der Ausführung Ihres Codes erstellt. Tatsächlich wird er erstellt, wenn Ihr Code geladen wird ... oder möglicherweise sogar früher.)


Ich wollte also wissen, ob das neue Heap-Objekt auch unveränderlich ist, ...

Ja ist es. Die Unveränderlichkeit ist jedoch eine grundlegende Eigenschaft von String-Objekten. Alle StringObjekte.

Sie sehen, die StringAPI bietet einfach keine Methoden zum Ändern von a String. Also (abgesehen von einigen gefährlichen und dummen 1 Tricks mit Reflexion) können Sie a nicht mutieren String.

und wenn ja, was war der Zweck?

Der Hauptgrund dafür, dass Java Stringals unveränderliche Klasse konzipiert ist, ist die Einfachheit. Es erleichtert das Schreiben korrekter Programme und das Lesen / Begründen des Codes anderer Personen, wenn die Kernzeichenfolgenklasse eine unveränderliche Schnittstelle bietet.

Ein wichtiger zweiter Grund ist, dass die Unveränderlichkeit von Stringgrundlegende Auswirkungen auf das Java-Sicherheitsmodell hat. Aber ich glaube nicht, dass dies ein Treiber für das Design der Originalsprache war ... in Java 1.0 und früher.

Anhand der Antwort stelle ich fest, dass andere Verweise auf dieselbe Variable einer der Gründe sind. Bitte lassen Sie mich wissen, ob ich das richtig verstehe.

Nein, es ist grundlegender als das. Alle StringObjekte sind einfach unveränderlich. Es ist keine komplizierte Argumentation für Sonderfälle erforderlich, um dies zu verstehen. Es ist nur >> <<.

Wenn Sie für den Datensatz ein veränderbares "string-like" Objekt in Java möchten, können Sie StringBuilderoder verwenden StringBuffer. Dies sind jedoch verschiedene Typen von String.


1 - Der Grund, warum diese Tricks (IMO) gefährlich und dumm sind, besteht darin, dass sie sich auf die Werte von Zeichenfolgen auswirken, die möglicherweise von anderen Teilen Ihrer Anwendung über den Zeichenfolgenpool gemeinsam genutzt werden. Dies kann Chaos verursachen ... auf eine Weise, dass der nächste Typ, der Ihren Code verwaltet, kaum eine Chance hat, ihn aufzuspüren.

Stephen C.
quelle
42

String ist unveränderlich, unabhängig davon, wie es instanziiert wird

1) Kurze Antwort ist ja , new String()ist auch unveränderlich.

Da jeder möglicher wandelbar Betrieb (wie replace, toLowerCaseetcetra) , dass Sie führen an String die Original nicht beeinflussen String Instanz und gibt Ihnen eine neue Instanz .

Sie können dies in Javadoc überprüfen für String. Jede publicMethode String, die verfügbar gemacht wird, gibt eine neue StringInstanz zurück und ändert nicht die aktuelle Instanz, für die Sie die Methode aufgerufen haben.

Dies ist in Multithread-Umgebungen sehr hilfreich, da Sie nicht jedes Mal über Veränderlichkeit nachdenken müssen ( jemand wird den Wert ändern ), wenn Sie die StringUmgebung passieren oder teilen . Stringkann leicht der am häufigsten verwendete Datentyp sein, daher haben die Designer uns alle gesegnet, nicht jedes Mal über Veränderlichkeit nachzudenken, und uns viel Schmerz erspart.

Unveränderlichkeit erlaubt String-Pool oder Caching

Aufgrund der Unveränderlichkeitseigenschaft war der interne String-Pool möglich. Wenn an einer anderen Stelle derselbe String-Wert erforderlich ist, wird diese unveränderliche Referenz zurückgegeben. Wenn Stringes veränderlich gewesen wäre, wäre es nicht möglich gewesen, solche Strings zu teilen , um Speicherplatz zu sparen.

Die Unveränderlichkeit von Strings war nicht auf das Pooling zurückzuführen, aber die Unveränderlichkeit hat mehr Vorteile.

String Interning oder Pooling ist ein Beispiel für ein Flyweight Design-Muster

2) Ja, es wird wie jedes andere interniert, Stringda ein Leerzeichen genauso wichtig Stringist Stringwie andere StringInstanzen.

Verweise:

Narendra Pathai
quelle
Es lohnt sich hinzuzufügen, dass jeder Typ unveränderlich ist, wenn: alle Datenelemente vorhanden sind privateund keine der Methoden etwas ändert. Die Entscheidung, Stringeine unveränderliche Klasse zu bilden, ist einfach eine Entwurfsentscheidung der Sprachdesigner und stellt keinen "besonderen" Teil der Kernsprache dar.
Aaron McDaid
@ Basilevs Nicht sicher, ob Sie tatsächlich gesucht oder nur vgrepped.
Chrylis
18

Die Java-Bibliotheken sind stark auf die Einschränkung optimiert, dass jedes StringObjekt unveränderlich ist, unabhängig davon, wie dieses Objekt aufgebaut ist. Selbst wenn Sie Ihre bVerwendung erstellen new, behandelt anderer Code, an den Sie diese Instanz übergeben, den Wert als unveränderlich. Dies ist ein Beispiel für das Wertobjektmuster, und alle Vorteile (Thread-Sicherheit, keine privaten Kopien erforderlich) gelten.

Die leere Zeichenfolge ""ist Stringwie alles andere ein legitimes Objekt, sie enthält einfach keinen internen Inhalt, und da alle Zeichenfolgen für die Konstante zur Kompilierungszeit interniert sind, kann ich praktisch garantieren, dass sie zur Laufzeitbibliothek bereits hinzugefügt wurde Schwimmbad.

chrylis -vorsichtig optimistisch-
quelle
Was mich verwirrt hat, war, dass das Erstellen eines Stringneuen 'String ()' einen dedizierten Eintrag im Heap macht, oder? Wie wird Unveränderlichkeit hier berücksichtigt, wenn dieser Speicher nirgendwo anders verwendet wird? Ich versuche nur zu verstehen, nicht unklug zu sein.
Ein Typ
2
@Rakesh: Wie Chrylis schrieb, können andere Teile des Programms, die die Zeichenfolge verwenden, ihre Unveränderlichkeit annehmen, wodurch sie von Verantwortlichkeiten wie der Synchronisierung oder dem Erstellen privater Kopien von Zeichenfolgen befreit werden, die andernfalls hinter ihrem Rücken geändert werden könnten.
Dolda2000
4
@Rakesh: Wenn das, was Sie wirklich fragen (ich bin mir nicht ganz sicher, wie Sie es formulieren), durch welchen genauen Mechanismus a new String()unveränderlich ist, dann ist es einfach, weil Stringes keine öffentlichen Methoden implementiert, um seinen Inhalt zu ändern Es gibt einfach keine Schnittstelle, über die man es ändern kann.
Dolda2000
4
@ Rakesh: Ihre Annahme, dass der "Speicher nirgendwo anders verwendet wird", ist falsch. Sie können den Verweis auf dasselbe Objekt an Dutzende von Threads übergeben, und es ist viel sicherer, wenn er garantiert unveränderlich ist.
Groo
14

1) Der unveränderliche Teil ist nicht wegen des Pools; es macht nur den Pool überhaupt erst möglich. Zeichenfolgen werden häufig als Argumente an andere Funktionen übergeben oder sogar mit anderen Threads geteilt. Strings unveränderlich zu machen war eine Designentscheidung, um das Denken in solchen Situationen zu vereinfachen. Also ja - Strings in Java sind immer unveränderlich, egal , wie Sie sie erstellen (beachten Sie, dass es möglich ist wandelbar Strings in Java haben - nur nicht mit der StringKlasse).

2) Ja. Wahrscheinlich. Ich bin mir nicht 100% sicher, aber das sollte der Fall sein.

Kubisch
quelle
7

Dies ist nicht unbedingt eine Antwort auf Ihre Frage, aber wenn hinter Ihrer Frage der Wunsch nach veränderlichen Zeichenfolgen steht, die Sie manipulieren können, sollten Sie die StringBuilderKlasse überprüfen , die viele der exakt gleichen Methoden implementiert, Stringaber auch Methoden hinzufügt Ändern Sie den aktuellen Inhalt.

Sobald Sie Ihre Zeichenfolge so erstellt haben, dass Sie damit zufrieden sind, rufen Sie sie einfach toString()auf, um sie in eine normale Zeichenfolge zu konvertieren String, die Sie an Bibliotheksroutinen und andere Funktionen übergeben können, die nur Strings benötigen.

Beides StringBuilderund Stringimplementiert die CharSequenceSchnittstelle. Wenn Sie also Funktionen in Ihren eigenen Code schreiben möchten, die sowohl veränderbare als auch unveränderliche Zeichenfolgen verwenden können, können Sie diese als CharSequenceObjekte deklarieren .

Dolda2000
quelle
Ich habe speziell die Unveränderlichkeit von String untersucht. Auf jeden Fall ist dies eine gute Einsicht.
Ein Typ
7

Aus der Java Oracle-Dokumentation :

Saiten sind konstant; Ihre Werte können nach ihrer Erstellung nicht mehr geändert werden .

Und wieder:

String-Puffer unterstützen veränderbare Strings. Da String-Objekte unveränderlich sind, können sie gemeinsam genutzt werden.

Im Allgemeinen: "Alle primitiven" (oder verwandten) Objekte sind unveränderlich (bitte akzeptieren Sie meinen Mangel an Formalismus).

In Verbindung stehender Beitrag zum Stapelüberlauf:

Informationen zum Objektpool : Der Objektpool ist eine Java-Optimierung, die sich NICHT auf unveränderliche Daten bezieht.

venergiac
quelle
6

Zeichenfolge ist unveränderlich bedeutet, dass Sie das Objekt selbst nicht ändern können, egal wie Sie es erstellt haben. Und was die zweite Frage betrifft: Ja, es wird ein Eintrag erstellt.

Trete
quelle
5

Eigentlich ist es umgekehrt.

[...] Die StringKlasse wurde so konzipiert, dass die Werte im gemeinsamen Pool an anderen Stellen / Variablen wiederverwendet werden können.

Nein, die StringKlasse ist unveränderlich, sodass Sie sicher auf eine Instanz verweisen können, ohne sich Sorgen machen zu müssen, dass sie von einem anderen Teil Ihres Programms geändert wird. Aus diesem Grund ist Pooling in erster Linie möglich.

Betrachten Sie also Folgendes:

// this string literal is interned and referenced by 'a'
String a = "Hello World!";

// creates a new instance by copying characters from 'a'
String b = new String(a);

Was passiert nun, wenn Sie einfach einen Verweis auf Ihre neu erstellte bVariable erstellen ?

// 'c' now points to the same instance as 'b'
String c = b;

Stellen Sie sich vor, Sie übergeben c(oder genauer gesagt das Objekt, auf das verwiesen wird) eine Methode in einem anderen Thread und arbeiten weiterhin mit derselben Instanz in Ihrem Hauptthread. Und jetzt stellen Sie sich vor, was passieren würde, wenn Zeichenfolgen veränderlich wären.

Warum ist das überhaupt so?

Nicht zuletzt deshalb, weil unveränderliche Objekte das Multithreading viel einfacher und in der Regel sogar noch schneller machen. Wenn Sie ein veränderbares Objekt (dh ein zustandsbehaftetes Objekt mit veränderlichen privaten / öffentlichen Feldern oder Eigenschaften) für verschiedene Threads freigeben, müssen Sie besonders darauf achten, dass der synchronisierte Zugriff (Mutexe, Semaphoren) gewährleistet ist. Trotzdem benötigen Sie besondere Sorgfalt, um die Atomizität bei all Ihren Operationen sicherzustellen. Multithreading ist schwer.

Beachten Sie in Bezug auf die Auswirkungen auf die Leistung, dass das Kopieren der gesamten Zeichenfolge in eine neue Instanz, um auch nur ein einzelnes Zeichen zu ändern, aufgrund von Synchronisationskonstrukten, die für einen threadsicheren Zugriff erforderlich sind, häufig schneller ist als das Auslösen eines teuren Kontextwechsels. Und wie Sie bereits erwähnt haben, bietet Unveränderlichkeit auch Internierungsmöglichkeiten, was bedeutet, dass die Speicherauslastung tatsächlich reduziert werden kann.

Es ist im Allgemeinen eine ziemlich gute Idee , so viel Material wie möglich unveränderlich zu machen .

Groo
quelle
4

1) Unveränderlichkeit: Die Zeichenfolge ist unveränderlich, wenn Sie sie aus Sicherheitsgründen auf neue oder andere Weise erstellen

2) Ja, es wird ein leerer Eintrag im String-Pool vorhanden sein.

Sie können das Konzept mithilfe des Codes besser verstehen

    String s1 = new String("Test");
    String s2 = new String("Test");
    String s3 = "Test";
    String s4 = "Test";

    System.out.println(s1==s2);//false
    System.out.println(s1==s3);//false
    System.out.println(s2==s3);//false
    System.out.println(s4==s3);//true

Hoffe, dies wird Ihrer Anfrage helfen. Sie können den Quellcode für die String-Klasse jederzeit überprüfen, um das Verständnis zu verbessern. Link: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String .Java

nikhilgupta86
quelle
2

Erstellte Zeichenfolgen sind immer unveränderlich, unabhängig davon, wie sie erstellt wurden.

Antworten auf Ihre Fragen:

  1. Der einzige Unterschied ist:
    Wenn eine Zeichenfolge wie folgt erstellt wird, wird {String a = "Hello World!";}nur ein Objekt erstellt.
    Und wenn es wie geschaffen ist - {String b = new String("Hello World!");}dann zwei Objekte erhalten erstellt. Das erste, weil Sie das Schlüsselwort 'new' verwendet haben , und das zweite wegen der String- Eigenschaft.

  2. Ja sicher. Es wird ein leerer Eintrag im Pool erstellt.

Arbind
quelle
1

Der String ist unveränderlich, da er Ihnen keine Möglichkeit bietet, ihn zu ändern. Es ist so konzipiert, dass Manipulationen vermieden werden (es ist endgültig, das zugrunde liegende Array darf nicht berührt werden ...).

Ganzzahlig ist identisch, da es keine Möglichkeit gibt, sie zu ändern.

Es spielt keine Rolle, wie Sie es erstellen.

njzk2
quelle
1

Unveränderlichkeit ist kein Merkmal von new, es ist ein Merkmal der Klasse String. Es hat keine Mutator-Methoden, daher ist es unveränderlich.

fastcodejava
quelle
1
 String A = "Test"
 String B = "Test"

Jetzt String B called"Test" .toUpperCase () which change the same object into"TEST" , soEin will also be"TEST" `, der nicht wünschenswert ist.

Surya Rawat
quelle
Kannst du bitte Erklären?
Fabio
"Test" wurde von vielen Referenzvariablen referenziert. Wenn also eine von ihnen den Wert ändert, werden andere automatisch beeinflusst.
Surya Rawat
0

Beachten Sie, dass in Ihrem Beispiel die Referenz geändert wird und nicht das Objekt, auf das sie verweist, dh dass beine Referenz geändert werden kann und auf ein neues Objekt verweist. Dieses neue Objekt ist jedoch unveränderlich, was bedeutet, dass sein Inhalt "nach" dem Aufruf des Konstruktors nicht geändert wird.

Sie können eine Zeichenfolge mit b=b+"x";oder ändern b=new String(b);, und der Inhalt der Variablen ascheint sich zu ändern, aber verwechseln Sie nicht die Unveränderlichkeit einer Referenz (hier Variable b) und des Objekts, auf das sie verweist (denken Sie an Zeiger in C). Das Objekt, auf das die Referenz zeigt, bleibt nach seiner Erstellung unverändert.

Wenn Sie eine Zeichenfolge ändern müssen, indem Sie den Inhalt des Objekts ändern (anstatt die Referenz zu ändern), können Sie StringBuffereine veränderbare Version von String verwenden.

Sohail Si
quelle