Was ist String Interning in Java, wann sollte ich es verwenden und warum ?
java
string
string-interning
saplingPro
quelle
quelle
String a = new String("abc");
String b = new String("abc");
danna.intern() == b.intern()
String.intern()
anClassLoader
, was bedeutet, dass verschiedene Klassenlader "verschiedene" erstellen und unterschiedliche "String
verursachen"intern
?Antworten:
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern ()
Wenn Sie String.intern () für eine Reihe von Zeichenfolgen ausführen, wird sichergestellt, dass alle Zeichenfolgen mit demselben Inhalt denselben Speicher verwenden. Wenn Sie also eine Liste mit Namen haben, in denen 'John' 1000 Mal vorkommt, stellen Sie durch Internierung sicher, dass nur einem 'John' tatsächlich Speicher zugewiesen wird.
Dies kann nützlich sein, um den Speicherbedarf Ihres Programms zu reduzieren. Beachten Sie jedoch, dass der Cache von JVM in einem permanenten Speicherpool verwaltet wird, dessen Größe im Vergleich zum Heap normalerweise begrenzt ist. Verwenden Sie daher intern nicht, wenn Sie nicht zu viele doppelte Werte haben.
Weitere Informationen zu Speicherbeschränkungen bei der Verwendung von intern ()
- Von: http://www.codeinstructions.com/2009/01/busting-javalangstringintern-myths.html
Ab JDK 7 (ich meine in HotSpot) hat sich etwas geändert.
- Von Java SE 7 Funktionen und Verbesserungen
Update: Internierte Zeichenfolgen werden ab Java 7 im Hauptheap gespeichert. http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html#jdk7changes
quelle
char[]
anstelle vonString
sensiblem Text zu verwenden und ihn auf Null zu setzen, sobald er nicht mehr benötigt wird.Es gibt einige "eingängige Interview" -Fragen, z. B. warum Sie gleichberechtigt sind! wenn Sie den folgenden Code ausführen.
Wenn Sie Strings vergleichen möchten, sollten Sie verwenden
equals()
. Das obige wird gleich gedruckt, da das vom CompilertestString
bereits für Sie interniert wurde . Sie können die Zeichenfolgen mithilfe der internen Methode selbst internieren, wie in den vorherigen Antworten gezeigt.quelle
equals
Methode verwenden. Möglicherweise möchten Sie einennew String()
Vergleich hinzufügen , um die Unterscheidung deutlicher darzustellen.JLS
JLS 7 3.10.5 definiert es und gibt ein praktisches Beispiel:
JVMS
Laut JVMS 7 5.1 wird das Internieren mit einer dedizierten
CONSTANT_String_info
Struktur magisch und effizient implementiert (im Gegensatz zu den meisten anderen Objekten mit allgemeineren Darstellungen):Bytecode
Lassen Sie uns einen OpenJDK 7-Bytecode dekompilieren, um die Internierung in Aktion zu sehen.
Wenn wir dekompilieren:
Wir haben auf dem ständigen Pool:
und
main
:Beachten Sie, wie:
0
und3
: die gleicheldc #2
Konstante wird geladen (die Literale)12
: Eine neue String-Instanz wird erstellt (mit#2
als Argument)35
:a
undc
werden als reguläre Objekte mit verglichenif_acmpne
Die Darstellung konstanter Zeichenfolgen ist auf dem Bytecode ziemlich magisch:
new String
)und das obige JVMS-Zitat scheint zu sagen, dass immer dann, wenn der Utf8, auf den gezeigt wird, derselbe ist, identische Instanzen von geladen werden
ldc
.Ich habe ähnliche Tests für Felder durchgeführt und:
static final String s = "abc"
zeigt über das ConstantValue-Attribut auf die Konstantentabelleldc
Schlussfolgerung : Es gibt eine direkte Bytecode-Unterstützung für den Zeichenfolgenpool und die Speicherdarstellung ist effizient.
Bonus: Vergleichen Sie das mit dem Integer-Pool , der keine direkte Bytecode-Unterstützung bietet (dh kein
CONSTANT_String_info
Analogon).quelle
Update für Java 8 oder höher . In Java 8 wird der PermGen-Speicherplatz (Permanent Generation) entfernt und durch den Meta-Speicherplatz ersetzt. Der String-Pool-Speicher wird auf den Heap von JVM verschoben.
Im Vergleich zu Java 7 wird die Größe des String-Pools im Heap erhöht. Daher haben Sie mehr Platz für verinnerlichte Zeichenfolgen, aber weniger Speicher für die gesamte Anwendung.
Eine weitere Sache, Sie haben bereits gewusst, dass beim Vergleichen von 2 (Verweisen von) Objekten in Java '
==
' zum Vergleichen der Objektreferenz 'equals
' zum Vergleichen des Objektinhalts verwendet wird.Überprüfen wir diesen Code:
Ergebnis:
value1 == value2
---> wahrvalue1 == value3
---> falschvalue1.equals(value3)
---> wahrvalue1 == value3.intern()
---> wahrDeshalb sollten Sie '
equals
' verwenden, um 2 String-Objekte zu vergleichen. Und so istintern()
es nützlich.quelle
String Interning ist eine Optimierungstechnik des Compilers. Wenn Sie zwei identische Zeichenfolgenliterale in einer Kompilierungseinheit haben, stellt der generierte Code sicher, dass nur ein Zeichenfolgenobjekt für die gesamte Instanz dieses Literals (in doppelte Anführungszeichen eingeschlossene Zeichen) in der Assembly erstellt wird.
Ich komme aus dem C # -Hintergrund, daher kann ich dies anhand eines Beispiels erklären:
Ausgabe der folgenden Vergleiche:
Anmerkung 1 : Objekte werden als Referenz verglichen.
Anmerkung 2 : typeof (int) .Name wird durch die Reflektionsmethode ausgewertet, sodass es beim Kompilieren nicht ausgewertet wird. Hier werden diese Vergleiche zur Kompilierungszeit durchgeführt.
Analyse der Ergebnisse: 1) true, da beide dasselbe Literal enthalten und der generierte Code daher nur ein Objekt enthält, das auf "Int32" verweist. Siehe Anmerkung 1 .
2) wahr, weil der Inhalt beider Werte überprüft wird, was gleich ist.
3) FALSE, weil str2 und obj nicht dasselbe Literal haben. Siehe Anmerkung 2 .
quelle
quelle
Aus dem Buch des OCP Java SE 11-Programmierers Deshmukh fand ich die einfachste Erklärung für Interning, die wie folgt lautete: Da Zeichenfolgen Objekte sind und alle Objekte in Java immer nur im Heap-Bereich gespeichert sind, werden alle Zeichenfolgen im Heap-Bereich gespeichert. Java behält jedoch Zeichenfolgen bei, die ohne Verwendung des neuen Schlüsselworts in einem speziellen Bereich des Heap-Bereichs erstellt wurden, der als "Zeichenfolgenpool" bezeichnet wird. Java behält die mit dem neuen Schlüsselwort erstellten Zeichenfolgen im regulären Heap-Bereich bei.
Der Zweck des Zeichenfolgenpools besteht darin, eine Reihe eindeutiger Zeichenfolgen zu verwalten. Jedes Mal, wenn Sie eine neue Zeichenfolge erstellen, ohne das neue Schlüsselwort zu verwenden, prüft Java, ob dieselbe Zeichenfolge bereits im Zeichenfolgenpool vorhanden ist. In diesem Fall gibt Java einen Verweis auf dasselbe String-Objekt zurück. Wenn dies nicht der Fall ist, erstellt Java ein neues String-Objekt im String-Pool und gibt seinen Verweis zurück. Wenn Sie beispielsweise die Zeichenfolge "Hallo" zweimal in Ihrem Code verwenden, wie unten gezeigt, erhalten Sie einen Verweis auf dieselbe Zeichenfolge. Wir können diese Theorie tatsächlich testen, indem wir zwei verschiedene Referenzvariablen mit dem Operator == vergleichen , wie im folgenden Code gezeigt:
Der Operator == prüft einfach, ob zwei Referenzen auf dasselbe Objekt verweisen oder nicht, und gibt in diesem Fall true zurück. Im obigen Code erhält str2 den Verweis auf dasselbe String-Objekt, das zuvor erstellt wurde. Allerdings str3 und str4 get Verweise auf zwei völlig verschiedene String - Objekte. Deshalb gibt str1 == str2 true zurück, aber str1 == str3 und str3 == str4 geben false zurück. In der Tat, wenn Sie einen neuen String machen ("Hallo"); Es werden zwei Zeichenfolgenobjekte anstelle von nur einem erstellt, wenn dies das erste Mal ist, dass die Zeichenfolge "Hallo" in einem beliebigen Programm verwendet wird - eines im Zeichenfolgenpool aufgrund der Verwendung einer Zeichenfolge in Anführungszeichen und eines im regulären Heap-Bereich, weil der Verwendung eines neuen Schlüsselworts.
String-Pooling ist Javas Methode, um Programmspeicher zu sparen, indem die Erstellung mehrerer String-Objekte mit demselben Wert vermieden wird. Es ist möglich, eine Zeichenfolge aus dem Zeichenfolgenpool für eine Zeichenfolge abzurufen, die mit dem neuen Schlüsselwort mithilfe der internen Methode von String erstellt wurde. Es wird als "Internierung" von Zeichenfolgenobjekten bezeichnet. Beispielsweise,
quelle