2016-07-15 22 views
19

Ich bin mir dessen bewusst, wenn SieWie verwendet die JVM interne String-Teilstrings?

for (condition) { 
    String s = "hi there"; 
} 

Nur eine String Instanz machen, ist in allen Iterationen erstellt, im Gegensatz zu String s = new String("hi there"); die eine neue Instanz in jeder Iteration wird erstellen.

Aber lesen Effective Java von Joshua Bloch: Kapitel 2 Punkt 5 (Seite 20) heißt es:

Darüber hinaus wird sichergestellt, dass das Objekt von jedem anderen Code ausgeführt wird in den gleichen wiederverwendet werden virtuelle Maschine, die mit passiert enthält die gleiche Zeichenfolge Literal [JLS, 3.10.5].

AFAIK, der nicht sagen zu zufällig die gleiche Stringliteral, heißt es enthält.

Lesen [JLS, 3.10.5] kann keine genaue Referenz dazu finden und ich habe Zweifel.

Giving diese Schnipsel:

String s1 = "hi "; 
String s2 = "there"; 
String s3 = "hi there"; 

Wie viele Instanzen erstellt werden?

  • 3 Instanzen (Phrase ist nicht wirklich genau).
  • 2 Instanzen, s1 und s2 (dann s3 erstellt s1 und s2 Referenzen Wiederverwendung)
+1

Er bedeutet wahrscheinlich "die virtuelle Maschine enthält ..", nicht die Zeichenfolge enthält eine andere Zeichenfolge –

+1

Ich bin mir nicht sicher, so ein Kommentar anstelle einer Antwort. Aber ich denke, dass das "contain" teilweise falsch ist und dein Beispiel tatsächlich drei Instanzen ergibt. – glglgl

+0

@glglgl ist eigentlich was * meine Logik * sagt, aber kann JVM schlau genug sein, 's3' als Referenz zu' s1' + 's2' zu erstellen? –

Antwort

17

Die JLS auch immer jede Wiederverwendung von Unterketten nicht garantieren. Das "contain" hier bedeutet nur, dass die Klasse das exakt gleiche Stringliteral irgendwo erwähnt. Es ist nicht in der "Teilzeichenfolge" Sinn verwendet.

+2

Insbesondere _ "jeder andere Code [..], die zufällig enthält die ** gleiche String Literal **" _ (Hervorhebung meins) –

+1

, wenn Sie sagen * garantiert keine Wiederverwendung von Sub-Strings * bedeutet, dass es manchmal passieren kann? –

+3

@JordiCastilla: Ich glaube nicht, dass eine aktuelle VM Teilstrings wiederverwendet, aber es ist möglich (und frühere Iterationen von OpenJDK zum Beispiel teilten manchmal das zugrundeliegende char [], wenn zwei Strings Teilstrings voneinander waren). Beachten Sie, dass Sie * separate * String-Instanzen weiterhin beobachten und es keine öffentliche API gibt, um festzustellen, ob dies der Fall ist (d. H., Sie wären nicht in der Lage, dies ohne irgendwelche Tricks zu tun). –

3

Jede Klassendatei enthält eine Liste aller Zeichenfolgenliterale oder anderen Konstanten, die in dieser Klasse verwendet werden (außer für kleine numerische Konstanten, die in den Befehlsstrom eingebettet sind). Wenn das Element 19 in der Liste das Zeichenfolgenliteral "Freddy" ist und die lokale Variable Fred einen Index von 6 aufweist, ist der für Fred="Freddy"; generierte Bytecode wahrscheinlich ldc 19/astore 6.

Wenn eine Klasse geladen wird, erstellt das System eine Tabelle aller Konstanten und - für die Referenztypen - die damit identifizierten Objekte. Wenn bekannt ist, dass keine Instanz eines Zeichenfolgenliterals existiert, fügt das System eins zur Internierungstabelle hinzu und speichert einen Verweis darauf. Wenn der Maschinencode generiert wird, wird ldc 19 durch eine Anweisung zum Laden der entsprechenden Referenz ersetzt.

Wichtig ist, dass durch die Zeit, jeder der Code in einer Klasse läuft, haben Objekte für alle Stringliterale darin erstellt wurde, so eine Aussage wie Fred="Freddy"; wird lediglich eine Referenz zu speichern, um eine bereits bestehende String Objekt enthält Freddy , anstatt ein neues String Objekt zu erstellen.

2

Wenn s3s1 und s2 Fälle wiederverwendet wird, dann würde s3 nicht physisch als kontinuierliches Zeichenfeld dargestellt werden, sondern würde eher ein Verbund String von String s Objekten sein. Stellen Sie sich nun vor, wie sich die Leistung auf den Zugriff auf einzelne Zeichen innerhalb eines solchen Strings auswirkt - indexbasierter Zugriff würde eigentlich den Indexwert mit der Größe des ersten Strings vergleichen, dann die Berechnung des Offsets, der zum Index für den zweiten String werden würde .

das Gegenteil könnte Sinn machen Eigentlich

: Nur eine zugrunde liegende char-Sequenz für "hi there" ( s3) zugeordnet werden kann, und s1 und s2 konnte nur innerhalb dieser Zeichenfolge ihre Längen und Adressen des ersten Zeichens speichern. Aber ich gehe davon aus, dass es für jvm eine komplexe und teure Arbeit wäre, die "einbettbaren" Kandidaten zu identifizieren, und dass die Kosten den potenziellen Nutzen überwiegen würden.

+1

Nun, vor Java 7 wurde die 'substring'-Methode so implementiert, dass sie eine Zeichenkette zurückliefert, die vom ursprünglichen Zeichenkettenarray unterstützt wird, aber selbst diese wurde gelöscht, weil sie mehr Schaden als Nutzen verursachte (große Texte könnten sein) am Leben gehalten, indem Sie einen Verweis auf eine kleine Teilkette halten, zum Beispiel) – Hulk

+1

@Hulk: Es wurde [Änderung in Java7update6] (http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4513622). Es ist nicht nur ein GC-Problem; es erfordert, dass jede Zeichenfolge ein "Offset" - und ein "Längen" -Feld für den einzigen Zweck einer einzigen Operation, "Teilzeichenfolge", trägt. Darüber hinaus profitiert die Deduplizierungsfunktion für Zeichenketten von kürzlichen JVMs vom vereinfachten Objektlayout, da ein einzelnes "cas" im Feld "value" ausreichend ist. – Holger