In Java gibt es zwei Formen der Erstellung von String-Objekten: Eine ist eine Literalform wie String str = „droid“; und die andere besteht darin, new zu verwenden, eine Standardmethode zum Erstellen von Objekten wie String str = new String( „droid“);, diese beiden Methoden werden häufig beim Schreiben von Code verwendet, insbesondere die Literalmethode. Es gibt jedoch tatsächlich einige Unterschiede in der Leistung und Speichernutzung zwischen diesen beiden Implementierungen. Dies alles ist auf die Tatsache zurückzuführen, dass die JVM einen speziellen Speicher unterhält, der als String-Konstantenpool oder String-Literal-Pool bezeichnet wird, um die wiederholte Erstellung von String-Objekten zu reduzieren.
Funktionsprinzip
Wenn im Code ein String-Objekt in Form eines Literals erstellt wird, prüft die JVM zunächst das Literal. Wenn im String-Konstantenpool ein Verweis auf ein String-Objekt mit demselben Inhalt vorhanden ist, wird der Verweis zurückgegeben Es wird eine neue Zeichenfolge erstellt. Das Objekt wird erstellt, diese Referenz wird in den String-Konstantenpool eingefügt und die Referenz wird zurückgegeben.
Geben Sie ein Beispiel
Wörtliche Schöpfungsform
Kopieren Sie den Codecode wie folgt:
String str1 = "Droide";
Die JVM erkennt dieses Literal. Wir gehen davon aus, dass es kein Objekt gibt, dessen Inhalt ein Droide ist. Die JVM kann die Existenz eines String-Objekts mit dem Inhalt von Droid nicht über den String-Konstantenpool finden. Dann erstellt sie das String-Objekt, fügt dann die Referenz des neu erstellten Objekts in den String-Konstantenpool ein und gibt die Referenz an das zurück Variable str1 .
Wenn es als nächstes einen Code wie diesen gibt
Kopieren Sie den Codecode wie folgt:
String str2 = "Droide";
Ebenso muss die JVM dieses Literal noch erkennen. Die JVM durchsucht den String-Konstantenpool und stellt fest, dass das String-Objekt mit dem Inhalt „droid“ vorhanden ist, sodass sie den Verweis des vorhandenen String-Objekts auf die Variable str2 zurückgibt. Beachten Sie, dass hier kein neues String-Objekt neu erstellt wird.
Um zu überprüfen, ob str1 und str2 auf dasselbe Objekt verweisen, können wir diesen Code verwenden
Kopieren Sie den Codecode wie folgt:
System.out.println(str1 == str2);
Das Ergebnis stimmt.
Mit Neu erstellen
Kopieren Sie den Codecode wie folgt:
String str3 = new String("droid");
Wenn wir new verwenden, um ein String-Objekt zu erstellen, wird ein neues String-Objekt erstellt, unabhängig davon, ob im String-Konstantenpool ein Verweis auf ein Objekt mit demselben Inhalt vorhanden ist. Deshalb verwenden wir den folgenden Code, um es zu testen:
Kopieren Sie den Codecode wie folgt:
String str3 = new String("droid");
System.out.println(str1 == str3);
Das Ergebnis ist falsch, wie wir dachten, was darauf hindeutet, dass die beiden Variablen auf unterschiedliche Objekte verweisen.
Praktikant
Wenn Sie für das oben mit „new“ erstellte Zeichenfolgenobjekt die Referenz dieses Objekts zum Zeichenfolgenkonstantenpool hinzufügen möchten, können Sie die interne Methode verwenden.
Überprüfen Sie nach dem Aufruf von intern zunächst, ob ein Verweis auf das Objekt im String-Konstantenpool vorhanden ist. Geben Sie den Verweis auf die Variable zurück. Andernfalls fügen Sie den Verweis hinzu und geben Sie ihn an die Variable zurück.
Kopieren Sie den Codecode wie folgt:
String str4 = str3.intern();
System.out.println(str4 == str1);
Das Ausgabeergebnis ist wahr.
Schwierige Fragen
Voraussetzung?
Voraussetzung für die Implementierung des String-Konstantenpools ist, dass das String-Objekt in Java unveränderlich ist, wodurch sicher sichergestellt werden kann, dass mehrere Variablen dasselbe Objekt gemeinsam nutzen. Wenn das String-Objekt in Java veränderbar ist und eine Referenzoperation den Wert des Objekts ändert, sind auch andere Variablen davon betroffen. Dies ist offensichtlich unvernünftig.
Referenz oder Objekt
Das häufigste Problem besteht darin, ob Referenzen oder Objekte im String-Konstantenpool gespeichert werden. Der String-Konstantenpool speichert Objektverweise, keine Objekte. In Java werden Objekte im Heapspeicher erstellt.
Update-Überprüfung, viele eingegangene Kommentare befassen sich auch mit diesem Problem, ich habe es einfach überprüft. Verifizierungsumgebung:
Kopieren Sie den Codecode wie folgt:
22:18:54-androidyue~/Videos$ cat /etc/os-release
NAME=Fedora
VERSION="17 (Beefy Miracle)"
ID=Fedora
VERSION_ID=17
PRETTY_NAME="Fedora 17 (Beefy Miracle)"
ANSI_COLOR="0;34"
CPE_NAME="cpe:/o:fedoraproject:fedora:17"
22:19:04-androidyue~/Videos$ Java-Version
Java-Version „1.7.0_25“
OpenJDK-Laufzeitumgebung (fedora-2.3.12.1.fc17-x86_64)
OpenJDK 64-Bit-Server-VM (Build 23.7-b01, gemischter Modus)
Verifizierungsidee: Das folgende Java-Programm liest eine Videodatei mit einer Größe von 82 MB und führt interne Operationen in Form von Zeichenfolgen aus.
Kopieren Sie den Codecode wie folgt:
22:01:17-androidyue~/Videos$ ll -lh |
-rw-rw-r--. 1 androidyue androidyue 82M 20. Okt. 2013 why_to_learn.mp4
Bestätigungscode
Kopieren Sie den Codecode wie folgt:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
öffentliche Klasse TestMain {
privater statischer String fileContent;
public static void main(String[] args) {
fileContent = readFileToString(args[0]);
if (null != fileContent) {
fileContent = fileContent.intern();
System.out.println("Nicht Null");
}
}
privater statischer String readFileToString(String file) {
BufferedReader-Reader = null;
versuchen {
reader = new BufferedReader(new FileReader(file));
StringBuffer buff = new StringBuffer();
String-Linie;
while ((line = reader.readLine()) != null) {
buff.append(line);
}
return buff.toString();
} Catch (FileNotFoundException e) {
e.printStackTrace();
} Catch (IOException e) {
e.printStackTrace();
} Endlich {
if (null != Leser) {
versuchen {
reader.close();
} Catch (IOException e) {
e.printStackTrace();
}
}
}
null zurückgeben;
}
}
Da der String-Konstantenpool in der permanenten Generierung im Heap-Speicher vorhanden ist, ist er vor Java8 anwendbar. Wir haben dies überprüft, indem wir die permanente Generation auf einen sehr kleinen Wert eingestellt haben. Wenn das String-Objekt im String-Konstantenpool vorhanden ist, wird zwangsläufig der Permgen-Space-Fehler java.lang.OutOfMemoryError ausgelöst.
Kopieren Sie den Codecode wie folgt:
java -XX:PermSize=6m TestMain ~/Videos/why_to_learn.mp4
Das Ausführen des Proof-Programms löste kein OOM aus. Tatsächlich kann dadurch nicht sehr gut nachgewiesen werden, ob Objekte oder Referenzen gespeichert sind.
Dies beweist aber zumindest, dass das eigentliche Inhaltsobjekt char[] des Strings nicht im String-Konstantenpool gespeichert ist. In diesem Fall ist es eigentlich nicht so wichtig, ob der String-Konstantenpool String-Objekte oder Referenzen auf String-Objekte speichert. Aber ich persönlich bevorzuge es immer noch, es als Referenz zu speichern.
Vor- und Nachteile
Der Vorteil des String-Konstantenpools besteht darin, die Erstellung von Strings mit demselben Inhalt zu reduzieren und Speicherplatz zu sparen.
Wenn wir unbedingt über die Nachteile sprechen wollen, dann ist es, dass CPU-Rechenzeit im Austausch für Platz geopfert wird. Die CPU-Berechnungszeit wird hauptsächlich verwendet, um herauszufinden, ob im String-Konstantenpool ein Verweis auf ein Objekt mit demselben Inhalt vorhanden ist. Die interne Implementierung ist jedoch HashTable, sodass der Berechnungsaufwand gering ist.
GC-Recycling?
Bedeutet das, dass der String-Konstantenpool Verweise auf gemeinsam genutzte String-Objekte enthält, dass diese Objekte nicht recycelt werden können?
Erstens sind die gemeinsam genutzten Objekte in der Frage im Allgemeinen relativ klein. Soweit ich weiß, gab es dieses Problem in früheren Versionen, aber mit der Einführung schwacher Referenzen sollte dieses Problem jetzt behoben sein.
Zu diesem Problem können Sie mehr über den internen Artikel Strings: Java Glossary erfahren
Interner Einsatz?
Voraussetzung für die Nutzung von intern ist, dass Sie wissen, dass Sie es wirklich nutzen müssen. Wir haben hier zum Beispiel Millionen von Datensätzen, und ein bestimmter Wert in dem Datensatz ist oft Kalifornien, USA. Wir möchten nicht Millionen solcher Zeichenfolgenobjekte erstellen, um nur eine Kopie im Speicher zu behalten. Dürfen. Für ein tiefergehendes Verständnis von intern lesen Sie bitte die ausführliche Analyse von String#intern.
Gibt es immer Ausnahmen?
Wussten Sie, dass der folgende Code mehrere String-Objekte erstellt und mehrere Referenzen im String-Konstantenpool speichert?
Kopieren Sie den Codecode wie folgt:
String-Test = „a“ + „b“ + „c“;
Die Antwort ist, dass nur ein Objekt erstellt und nur eine Referenz im Konstantenpool gespeichert wird. Wir können es herausfinden, indem wir Javap zum Dekompilieren verwenden und einen Blick darauf werfen.
Kopieren Sie den Codecode wie folgt:
17:02 $ javap -c TestInternedPoolGC
Zusammengestellt aus „TestInternedPoolGC.java“
Die öffentliche Klasse TestInternedPoolGC erweitert java.lang.Object{
public TestInternedPoolGC();
Code:
0: aload_0
1: invokespecial #1; //Methode java/lang/Object."<init>":()V
4: Rückkehr
public static void main(java.lang.String[]) löst java.lang.Exception aus;
Code:
0: ldc #2; //String abc
2: astore_1
3: Rückkehr
Haben Sie gesehen, dass diese drei Literale beim Kompilieren zu einem zusammengefasst wurden? Dies ist eigentlich eine Optimierung, die die Erstellung redundanter String-Objekte vermeidet und keine Probleme beim String-Spleißen verursacht. In Bezug auf das String-Spleißen können Sie Java-Details anzeigen: String-Spleißen.