Beim Betrachten von Online-Codebeispielen bin ich manchmal auf eine Zuweisung einer String-Konstante zu einem String-Objekt mithilfe des neuen Operators gestoßen.
Zum Beispiel:
String s;
...
s = new String("Hello World");
Dies natürlich im Vergleich zu
s = "Hello World";
Ich bin mit dieser Syntax nicht vertraut und habe keine Ahnung, was der Zweck oder die Wirkung sein würde. Da String-Konstanten normalerweise im Konstantenpool und dann in der Darstellung gespeichert werden, die die JVM für den Umgang mit String-Konstanten hat, würde überhaupt etwas auf dem Heap zugewiesen werden?
new String(String)
werden soll, ists = new String("Hello World")
der Parameter ein Literal, was in Java nicht sinnvoll ist und wahrscheinlich auch nie sinnvoll sein wird.Antworten:
Der einzige Ort, an dem Sie vielleicht denken, dass Sie möchten,
new String(String)
ist das Erzwingen einer eindeutigen Kopie des internen Zeichenarrays, wie insmall=new String(huge.substring(10,20))
Dieses Verhalten ist jedoch leider nicht dokumentiert und von der Implementierung abhängig.
Ich bin dadurch verbrannt worden, als ich große Dateien (einige bis zu 20 MiB) in einen String gelesen und nachträglich in Zeilen geschnitten habe. Am Ende hatte ich alle Zeichenfolgen für die Zeilen, die auf das Zeichen [] verweisen, das aus der gesamten Datei besteht. Leider wurde dadurch für die wenigen Zeilen, an denen ich mich länger als bei der Verarbeitung der Datei festhielt, ungewollt auf das gesamte Array verwiesen - ich musste es umgehen
new String()
, da die Verarbeitung von 20.000 Dateien sehr schnell sehr viel RAM verbrauchte.Der einzige implementierungsunabhängige Weg, dies zu tun, ist:
small=new String(huge.substring(10,20).toCharArray());
Dies muss das Array leider zweimal kopieren, einmal für
toCharArray()
und einmal im String-Konstruktor.Es muss eine dokumentierte Möglichkeit geben, einen neuen String zu erhalten, indem die Zeichen eines vorhandenen Strings kopiert werden. oder die Dokumentation von
String(String)
muss verbessert werden, um sie expliziter zu machen (es gibt eine Implikation, aber sie ist ziemlich vage und offen für Interpretationen).Fallstricke der Annahme, was der Doc nicht sagt
Beachten Sie als Antwort auf die Kommentare, die immer wieder eingehen, die Implementierung von Apache Harmony
new String()
:public String(String string) { value = string.value; offset = string.offset; count = string.count; }
Das ist richtig, keine Kopie des zugrunde liegenden Arrays dort. Und dennoch entspricht es der (Java 7) String-Dokumentation, indem es:
Das markante Stück ist „Kopie des Arguments Zeichenfolge “; Es heißt nicht "Kopie der Argumentzeichenfolge und des zugrunde liegenden Zeichenarrays, das die Zeichenfolge unterstützt".
Achten Sie darauf, dass Sie auf die Dokumentation und nicht auf eine Implementierung programmieren .
quelle
String(String)
Konstruktor heißt es: "Initialisiert ein neu erstelltes String-Objekt so, dass es dieselbe Zeichenfolge wie das Argument darstellt. Mit anderen Worten, die neu erstellte Zeichenfolge ist eine Kopie der Argumentzeichenfolge. Sofern keine explizite Kopie des Originals erforderlich ist, Verwendung dieses Konstruktor ist nicht erforderlich , da Strings unveränderlich sind. " , das ist ein Kreisverkehr Art zu sagen , sagte Konstruktor eine explizite Kopie des underying machtchar[]
derString
an sie übergeben.String(char[] value)
Sie dies mit einer expliziten Aussage : Der Inhalt des Zeichenarrays wird kopiert.!explicitCopyRequired --> constructor is unnecessary
(-> bedeutet "impliziert") und die zu enthüllende Regela --> b
<==> . Wenn Sie den Konstruktor verwenden, benötigen Sie eine explizite Kopie. Ich stimme zu, dass es besser formuliert sein könnte, aber wenn Sie es aufschlüsseln, ist es klar, dass dieser Konstruktor vertraglich eine explizite Kopie erstellt.!b --> !a
constructor is necessary --> explicitCopyRequired
new String(String)
ohne eine Kopie des zugrunde liegenden Zeichenarrays zu erstellen - es könnte Apache Harmony gewesen sein, aber ich bin nicht sicher.substring
Kopiert stattdessen die Daten in ein neues Array. Dies begann in Java 1.7 Update 6. Siehe hier .Das einzige Mal, dass ich dies nützlich fand, ist das Deklarieren von Sperrvariablen:
private final String lock = new String("Database lock"); .... synchronized(lock) { // do something }
In diesem Fall zeigen Debugging-Tools wie Eclipse die Zeichenfolge an, wenn aufgelistet wird, welche Sperren ein Thread derzeit enthält oder auf die er wartet. Sie müssen "new String" verwenden, dh ein neues String-Objekt zuweisen, da andernfalls ein gemeinsam genutztes String-Literal möglicherweise in einem anderen nicht verwandten Code gesperrt werden könnte.
quelle
private static class Lock {}; private final Lock lock = new Lock();
, da der Klassenname so ziemlich überall auftaucht. Es kostet Sie jedoch ein paar K, da HotSPot nicht so effizient ist.Serializable
so ist, also bevorzuge ichnew Object[0]
.Das einzige von Software Monkey und Ruggs beschriebene Dienstprogramm für diesen Konstruktor scheint aus JDK7 verschwunden zu sein.
offset
In der Klasse String gibt es kein Feld mehr , und Teilzeichenfolgen werden immer verwendetArrays.copyOfRange(char[] original, int from, int to)
um das char-Array für die Kopie zu kürzen.
quelle
substring()
muss es nicht in jeder Implementierung verwendet werden (und OpenJDK ist nicht die einzige JVM-Implementierung auf dem Markt ).String s1 = "foo"; Literal wird in StringPool gehen und s1 wird verweisen.
String s2 = "foo"; Dieses Mal wird überprüft, ob das "foo" -Literal bereits in StringPool verfügbar ist oder nicht, da es jetzt existiert, sodass s2 auf dasselbe Literal verweist.
String s3 = neuer String ("foo"); Das Literal "foo" wird zuerst in StringPool erstellt, dann über den String-Arg-Konstruktor. Das String-Objekt wird erstellt, dh "foo" im Heap aufgrund der Objekterstellung durch einen neuen Operator, dann verweist s3 darauf.
String s4 = neuer String ("foo"); gleich wie s3
also System.out.println (s1 == s2); // wahr aufgrund eines wörtlichen Vergleichs.
und System.out.println (s3 == s4); // aufgrund des Objektvergleichs falsch (s3 und s4 werden an verschiedenen Stellen im Heap erstellt)
quelle
Nun, das hängt davon ab, was das "..." im Beispiel ist. Wenn es sich beispielsweise um einen StringBuffer oder ein Byte-Array oder etwas anderes handelt, wird aus den übergebenen Daten ein String erstellt.
Wenn es sich jedoch wie in nur um einen anderen String handelt,
new String("Hello World!")
sollte dieser"Hello World!"
in jedem Fall durch einfach ersetzt werden. Strings sind unveränderlich, daher hat das Klonen eines Strings keinen Zweck - es ist nur ausführlicher und weniger effizient, ein neues String-Objekt zu erstellen, um als Duplikat eines vorhandenen Strings zu dienen (unabhängig davon, ob es sich um ein Literal oder eine andere bereits vorhandene String-Variable handelt).Tatsächlich verwendet Effective Java (das ich sehr empfehle) genau dies als eines seiner Beispiele für "Vermeiden Sie das Erstellen unnötiger Objekte":
Betrachten Sie diese Aussage als extremes Beispiel dafür, was nicht zu tun ist:
String s = new String("stringette"); **//DON'T DO THIS!**
(Effektives Java, zweite Ausgabe)
quelle
Hier ist ein Zitat aus dem Buch Effective Java Third Edition (Punkt 17: Minimize Mutability):
Es war also eine falsche Entscheidung von Java, da die
String
Klasse unveränderlich ist. Sie hätte keinen Kopierkonstruktor für diese Klasse bereitstellen sollen. In Fällen, in denen Sie kostspielige Operationen an unveränderlichen Klassen ausführen möchten, können Sie öffentliche veränderbare Begleitklassen verwenden, dieStringBuilder
undStringBuffer
im Falle vonString
.quelle
Im Allgemeinen weist dies auf jemanden hin, der mit dem neuartigen C ++ - Deklarationsstil bei der Initialisierung nicht vertraut ist.
In den C-Tagen galt es nicht als gute Form, automatische Variablen in einem inneren Bereich zu definieren. C ++ beseitigte die Parser-Einschränkung und Java erweiterte diese.
Sie sehen also Code, der hat
int q; for(q=0;q<MAX;q++){ String s; int ix; // other stuff s = new String("Hello, there!"); // do something with s }
Im Extremfall befinden sich alle Deklarationen möglicherweise am Anfang einer Funktion und nicht in geschlossenen Bereichen wie der
for
Schleife hier.Im Allgemeinen bewirkt dies jedoch, dass ein String ctor einmal aufgerufen und der resultierende String weggeworfen wird. (Der Wunsch, dies zu vermeiden, hat Stroustrup dazu veranlasst, Deklarationen an einer beliebigen Stelle im Code zuzulassen.) Sie haben also Recht, dass dies im besten Fall unnötig und schlecht und möglicherweise sogar schlecht ist.
quelle
Es gibt zwei Möglichkeiten, wie Strings in Java erstellt werden können. Im Folgenden finden Sie Beispiele für beide Möglichkeiten: 1) Deklarieren Sie eine Variable vom Typ String (eine Klasse in Java) und weisen Sie sie einem Wert zu, der in doppelte Anführungszeichen gesetzt werden soll. Dadurch wird eine Zeichenfolge im Zeichenfolgenpoolbereich des Speichers erstellt. zB: String str = "JAVA";
2) Verwenden Sie den Konstruktor der String-Klasse und übergeben Sie einen String (in doppelten Anführungszeichen) als Argument. zB: String s = neuer String ("JAVA"); Dadurch wird eine neue Zeichenfolge JAVA im Hauptspeicher und auch im Zeichenfolgenpool erstellt, wenn diese Zeichenfolge nicht bereits im Zeichenfolgenpool vorhanden ist.
quelle
substring
,trim
,replace
,replaceAll
,StringBuilder
,StringBuffer
, usw.Ich denke, es hängt von den Codebeispielen ab, die Sie sehen.
In den meisten Fällen wird mit dem Klassenkonstruktor "new String ()" im Codebeispiel nur eine sehr bekannte Java-Klasse angezeigt, anstatt eine neue zu erstellen.
Sie sollten es meistens vermeiden. Nicht nur, weil String-Literale interniert sind, sondern hauptsächlich, weil String unveränderlich sind. Es ist nicht sinnvoll, zwei Kopien zu haben, die dasselbe Objekt darstellen.
Obwohl der von Ruggs gemessene Artikel "interessant" ist , sollte er nur unter ganz bestimmten Umständen verwendet werden, da er mehr Schaden als Nutzen verursachen kann. Sie codieren eher für eine Implementierung als für eine Spezifikation, und derselbe Code kann beispielsweise in JRockit, IBM VM oder anderen nicht gleich ausgeführt werden.
quelle