Warum ist String in Java unveränderlich?

1. Einleitung

In Java sind Strings unveränderlich. Eine offensichtliche Frage, die in Interviews häufig vorkommt, lautet: „Warum werden Strings in Java als unveränderlich konzipiert?“

James Gosling, der Schöpfer von Java, wurde einmal in einem Interview gefragt, wann man unveränderliche Dinge verwenden soll, auf die er antwortet:

Ich würde eine unveränderliche verwenden, wann immer ich kann.

Er unterstützt ferner seine Argumentation, die Merkmale angibt, die Unveränderlichkeit bietet, wie Caching, Sicherheit, einfache Wiederverwendung ohne Replikation usw.

In diesem Tutorial werden wir weiter untersuchen, warum die Java-Sprachdesigner beschlossen haben, String unveränderlich zu halten .

2. Was ist ein unveränderliches Objekt?

Ein unveränderliches Objekt ist ein Objekt, dessen interner Zustand nach seiner vollständigen Erstellung konstant bleibt . Dies bedeutet, dass wir, sobald das Objekt einer Variablen zugewiesen wurde, weder die Referenz aktualisieren noch den internen Status auf irgendeine Weise mutieren können.

Wir haben einen separaten Artikel, in dem unveränderliche Objekte ausführlich behandelt werden. Weitere Informationen finden Sie im Artikel Unveränderliche Objekte in Java.

3. Warum ist String in Java unveränderlich?

Die Hauptvorteile, wenn diese Klasse unveränderlich bleibt, sind Caching, Sicherheit, Synchronisation und Leistung.

Lassen Sie uns diskutieren, wie diese Dinge funktionieren.

3.1. Einführung in String Pool

Der String ist die am häufigsten verwendete Datenstruktur. Das Zwischenspeichern und Wiederverwenden der String- Literale spart viel Heap-Speicherplatz, da verschiedene String- Variablen auf dasselbe Objekt im String- Pool verweisen . Der String Intern Pool dient genau diesem Zweck.

Java String Pool ist der spezielle Speicherbereich, in dem Strings von der JVM gespeichert werden . Da Strings unveränderlich sind in Java optimiert die JVM die Größe des Speichers für sie zugeteilt durch nur eine Kopie jeder wörtlichen Speicherung String im Pool. Dieser Vorgang wird als Internierung bezeichnet:

String s1 = "Hello World"; String s2 = "Hello World"; assertThat(s1 == s2).isTrue();

Aufgrund des Vorhandenseins des String- Pools im vorherigen Beispiel zeigen zwei verschiedene Variablen auf dasselbe String- Objekt aus dem Pool, wodurch wichtige Speicherressourcen gespart werden.

Wir haben einen separaten Artikel über Java String Pool. Weitere Informationen finden Sie in diesem Artikel.

3.2. Sicherheit

Der String wird häufig in Java-Anwendungen verwendet, um vertrauliche Informationen wie Benutzernamen, Kennwörter, Verbindungs-URLs, Netzwerkverbindungen usw. zu speichern. Er wird auch häufig von JVM-Klassenladeprogrammen beim Laden von Klassen verwendet.

Daher ist das Sichern der String- Klasse für die Sicherheit der gesamten Anwendung im Allgemeinen von entscheidender Bedeutung. Betrachten Sie beispielsweise dieses einfache Codefragment:

void criticalMethod(String userName) { // perform security checks if (!isAlphaNumeric(userName)) { throw new SecurityException(); } // do some secondary tasks initializeDatabase(); // critical task connection.executeUpdate("UPDATE Customers SET Status = 'Active' " + " WHERE UserName = '" + userName + "'"); }

Nehmen wir im obigen Codefragment an, dass wir ein String- Objekt von einer nicht vertrauenswürdigen Quelle erhalten haben. Wir führen zunächst alle erforderlichen Sicherheitsüberprüfungen durch, um zu überprüfen, ob der String nur alphanumerisch ist, gefolgt von einigen weiteren Vorgängen.

Denken Sie daran, dass unsere unzuverlässige Quellaufrufmethode immer noch auf dieses userName- Objekt verweist .

Wenn Strings veränderbar wären , können wir zum Zeitpunkt der Ausführung des Updates nicht sicher sein, ob der String , den wir erhalten haben, auch nach Durchführung von Sicherheitsüberprüfungen sicher ist. Die nicht vertrauenswürdige Aufrufermethode verfügt weiterhin über die Referenz und kann den String zwischen Integritätsprüfungen ändern . Dadurch ist unsere Abfrage in diesem Fall anfällig für SQL-Injektionen. Veränderbare Strings können also im Laufe der Zeit zu einer Verschlechterung der Sicherheit führen.

Es kann auch vorkommen, dass der String userName für einen anderen Thread sichtbar ist, der dann nach der Integritätsprüfung seinen Wert ändert.

Im Allgemeinen hilft uns die Unveränderlichkeit in diesem Fall, weil es einfacher ist, mit vertraulichem Code zu arbeiten, wenn sich die Werte nicht ändern, da weniger Verschachtelungen von Operationen das Ergebnis beeinflussen können.

3.3. Synchronisation

Unveränderlich zu sein, macht den String- Thread automatisch sicher, da sie beim Zugriff von mehreren Threads nicht geändert werden.

Daher können unveränderliche Objekte im Allgemeinen von mehreren Threads gemeinsam genutzt werden, die gleichzeitig ausgeführt werden. Sie sind auch threadsicher, denn wenn ein Thread den Wert ändert, wird anstelle des gleichen Wertes ein neuer String im String- Pool erstellt. Daher sind Strings für Multithreading sicher.

3.4. Hashcode-Caching

Da String- Objekte häufig als Datenstruktur verwendet werden, werden sie auch häufig in Hash-Implementierungen wie HashMap , HashTable , HashSet usw. verwendet. Wenn Sie mit diesen Hash-Implementierungen arbeiten, wird die hashCode () -Methode häufig zum Bucketing aufgerufen.

Die Unveränderlichkeit garantiert Strings, dass sich ihr Wert nicht ändert. Daher wird die hashCode () -Methode in der String- Klasse überschrieben , um das Caching zu erleichtern, sodass der Hash beim ersten Aufruf von hashCode () berechnet und zwischengespeichert wird und seitdem derselbe Wert zurückgegeben wird.

Dies wiederum verbessert die Leistung von Sammlungen, die Hash-Implementierungen verwenden, wenn sie mit String- Objekten betrieben werden.

Auf der anderen Seite, wandelbar Strings erzeugen würden zwei verschiedene Hashcodes zum Zeitpunkt des Einsetzens und Retrieval , wenn der Inhalt von String nach der Operation verändert wurde, möglicherweise das Wertobjekt in der unterlegenen Karte .

3.5. Performance

Wie wir zuvor gesehen haben, existiert der String- Pool, weil Strings unveränderlich sind. Dies wiederum verbessert die Leistung, indem es Heap-Speicher spart und schneller auf Hash-Implementierungen zugreift, wenn es mit Strings betrieben wird.

Da String die am häufigsten verwendete Datenstruktur ist, hat die Verbesserung der Leistung von String einen erheblichen Einfluss auf die Verbesserung der Leistung der gesamten Anwendung im Allgemeinen.

4. Fazit

Durch diesen Artikel können wir schließen, dass Strings genau unveränderlich sind, so dass ihre Referenzen als normale Variable behandelt werden können und man sie zwischen Methoden und über Threads hinweg weitergeben kann, ohne sich Gedanken darüber zu machen, ob sich das tatsächliche String- Objekt, auf das es zeigt, ändert.

Wir haben auch gelernt, was die anderen Gründe sein könnten, die die Java- Sprachdesigner dazu veranlasst haben, diese Klasse als unveränderlich zu betrachten.