Strings erzeugen

Generic1

Top Contributor
Hi,

ich hab gerade Effective Java gelesen und da steht drinnen, man soll:

String s = "test";

anstatt

String s = new String("test");

schreiben.
Macht das bei den heutigen Java Compiler eigentlich noch einen Unterschied? oder wird das im hintergrund alles zu einem StringBuilder?

Besten Dank!
 
Es ist nicht das gleiche:
Java:
public static void main(final String[] args) 
{
	String test1="test";
	String test2="test";
	String test3=new String("test");
	
	System.out.println(test1==test2);
	System.out.println(test1==test3);
}

Ergibt:
Code:
true
false

test1 und test2 referenzieren das gleiche Objekt. test1 und test3 nicht. Man soll eben die Variante hier nehmen:
Java:
String stringValue="value";

Weil der String aus einem Pool genommen wird, wenn schon vorhanden. Es wird also nicht immer explizit ein neuer erstellt.
 
Hallo,

meines wissens nach ist der Datentyp String ein Referenztyp in Java, dass heißt kein einfacher Datentyp. Und somit ist es eigentlich egal welche Schreibweise du verwendenest. bei der Schreibweise new wird der Konstruktor eben expliziet von dir aufgerufen und bei der anderen Schreibweise wird der Konstruktor implizit augerufen.

Grüße
 
bei der Schreibweise new wird der Konstruktor eben expliziet von dir aufgerufen und bei der anderen Schreibweise wird der Konstruktor implizit augerufen.
Bei der zweiten Variante werden 2 Strings erzeugt. Einer davon wird gleich wieder weggeworfen, nachdem der Inhalt in den zweiten String kopiert worden ist. Das ist nutzlos und überflüssig. Deswegen ist dieser String(String)-Konstruktor praktisch ebenfalls nutzlos.
 
Hallo,

meines wissens nach ist der Datentyp String ein Referenztyp in Java, dass heißt kein einfacher Datentyp. Und somit ist es eigentlich egal welche Schreibweise du verwendenest. bei der Schreibweise new wird der Konstruktor eben expliziet von dir aufgerufen und bei der anderen Schreibweise wird der Konstruktor implizit augerufen.

Grüße

Strings bilden nochmals eine Sondergruppe, da sie, wie gesagt, aus einem Pool genommen werden, wenn man sie nicht selbst explizit konstruiert.

Ebenso sollte man immer die valueOf methoden von Integer etc nehmen, da diese ebenso gecached werden (jdf ein Teil), sowie Boolean.TRUE u. Boolean.FALSE nehmen - anstatt selbst immer welche zu erzeugen.
 
Hallo,

Zitat: fidibus

Beitrag anzeigen



Hallo,

meines wissens nach ist der Datentyp String ein Referenztyp in Java, dass heißt kein einfacher Datentyp. Und somit ist es eigentlich egal welche Schreibweise du verwendenest. bei der Schreibweise new wird der Konstruktor eben expliziet von dir aufgerufen und bei der anderen Schreibweise wird der Konstruktor implizit augerufen.

Grüße


Strings bilden nochmals eine Sondergruppe, da sie, wie gesagt, aus einem Pool genommen werden, wenn man sie nicht selbst explizit konstruiert.

Ebenso sollte man immer die valueOf methoden von Integer etc nehmen, da diese ebenso gecached werden (jdf ein Teil), sowie Boolean.TRUE u. Boolean.FALSE nehmen - anstatt selbst immer welche zu erzeugen.

Diesbezüglich liegt der Fehler natürlich auf meiner Seite. Aber danke für die Korrektur.🙂 Man lernt halt nie aus.
Grüße
 
@tfa Bleibt bei
Java:
new String("lala")
nicht einer auf dem Heap zurück, bis die GC zuschlägt und ihn "eventuell" abräumt? Ich weis das man damit nämlich wunderschöne Memory Leaks produzieren kann...
 
werden bei

Java:
String s = new String("test");

jetzt 2 Strings erzeugt oder einer und wie kann man das beweisen?

hier wird ein neuer String erzeugt, der nicht aus dem Pool genommen wird.

schau dir mal "Tomate_Salat"'s Beispiel an, dann siehst du auch direkt den Beweis, dass es 2 unterschiedliche Strings sind wenn man sie mit "==" "vergleicht"
 
hier wird ein neuer String erzeugt, der nicht aus dem Pool genommen wird.

schau dir mal "Tomate_Salat"'s Beispiel an, dann siehst du auch direkt den Beweis, dass es 2 unterschiedliche Strings sind wenn man sie mit "==" "vergleicht"

Bitte genau lesen wenn du schon antworten willst.
Meine Frage war ob mit der Zeile

String s = new String("test");

zwei Strings erzeugt werden -> also new String("test"); und dieses Objekt/dieser String dann in ein neues Objekt kopiert wird oder ob nur ein Objekt erzeugt wird und s auf dieses Objekt zeigt?
 
Ja
Code:
String test = new String("test");
erzeugt zwei String-Objekte. Wobei "test" eine Konstante ist, und im Constantpool der Classfile "lebt".
Code:
new String(String)
ist der Copy-Konstruktor von String, dieser erzeugt eine tiefe Kopie des internen char-Arrays, des übergebenen Strings und verbraucht damit doppelt soviel Speicher als
Code:
String test = "test";
.

Wobei ich mich frage, wieso String einen Copy-Konstruktor braucht, diese sind eigentlich bei Immutablen überflüssig.
 
Also zum Literal mit Doublequotes ("string")... Um solche Dinge kümmert sich der GC erst, wenn er die gesammte Klasse ensorgen kann, wo sie definiert wurden, den dort ist auch der Stringpool (eigentlich ConstantPool) zu finden.
[OOPS]Letzten Beitrag übersehen...[/OOPS].
Aber erzeugt wird durch new halt nur einer, der andere ist Teil der Klasse. Die DeepCopy wird nur gemacht, wenn originalValue.length > original.count ist, ein Umstand, der bei Literalen kaum passieren kann.
Java:
    /**
     * Initializes a newly created {@code String} object so that it represents
     * the same sequence of characters as the argument; in other words, the
     * newly created string is a copy of the argument string. Unless an
     * explicit copy of {@code original} is needed, use of this constructor is
     * unnecessary since Strings are immutable.
     *
     * @param  original
     *         A {@code String}
     */
    public String(String original) {
	int size = original.count;
	char[] originalValue = original.value;
	char[] v;
  	if (originalValue.length > size) {
 	    // The array representing the String is bigger than the new
 	    // String itself.  Perhaps this constructor is being called
 	    // in order to trim the baggage, so make a copy of the array.
            int off = original.offset;
            v = Arrays.copyOfRange(originalValue, off, off+size);
 	} else {
 	    // The array representing the String is the same
 	    // size as the String, so no point in making a copy.
	    v = originalValue;
 	}
	this.offset = 0;
	this.count = size;
	this.value = v;
    }
 
Zuletzt bearbeitet von einem Moderator:
Ich denke richtig ist aber, das dabei zwei String-Objekte entstehen und darum ging es im ganzen Thread.

Java:
public String(String original) {
....
}

Was macht ein Konstruktor? Richtig, ein Konstruktor erzeugt ein neues Objekt 😉 Was hier geshared, bzw. kopiert wird, ist das zugrunde liegende char[], aber nicht das String-Objekt selbst, darum hast Du am Ende 2 String-Objekte..
 
Das's doch nur wieder die halbe Wahrheit (nämlich nur der erste Teil), darum geht's ja in diesem Thread. Die Frage ist doch, warum man das eine dem anderen vorziehen soll.
Natürlich erzeugt "new" immer ein Objekt aber das kannst du von mir aus auch "n" mal machen, sowohl erneut auf das Literal als auch auf seine Kinder und Kindeskinder. Auf diese Art erzeugte Stringobjekte verhunzen in diesem Fall immer 16 Bytes des wertvollen Heaps. Literale (Text in den Ganterpranken) werden nicht durch "new" erzeugt, sondern durch die JVM, welche den Text (das Chararray) aus dem Constantpool der Klasse bezieht. Durch [c]"new String("literal")[/c] wird die JVM höchstens daran gehindert, die Erzeugerklasse aus dem Speicher zu "entsorgen", wenn sie nicht mehr benötigt wird. Literale kopiert man anders. [c]new StringBuilder("literal").toString()[/c] forciert die oben genannte deepCopy. Die 16 + 2*n Bytes auf dem Heap finden ihre Berechtigung nun darin, ein Literal ausserhalb seiner Erzeugerklasse zu verwenden. So werden evtl. nur Stringlänge + 16 Bytes statt X-Bytes gesamte KlassenDefinition erhalten, aber auch bei diesem Konstrukt gibt's Haken, der Speicherverbrauch bei falscher Anwendung. Dieser String-Copy-Konstruktor aber ist nutzlos, solange die DeepCopy nicht erfolgt (muss ja automatisch erfolgen), was sie bei Literalen halt nicht tut, wohl aber unter Umständen bei Variablen des Typs String.
 
Zuletzt bearbeitet von einem Moderator:
Das stimmt schon, was Du schreibst. Trotzdem wird bei new String("lala") ein String-Objekt erzeugt, welche Du bei String s = "lala" einfach mal nicht hast 😉 Was eben gerade die Antwort auf die Frage des TO's ist. Man muß also die 16 Bytes des Heaps nicht "verhunzen".

Die Frage ist doch, warum man das eine dem anderen vorziehen soll.

Verstehe ich nicht, ich würde new String("lala") niemals der anderen Variante vorziehen.

Durch "new String("literal") wird die JVM höchstens daran gehindert, die Erzeugerklasse aus dem Speicher zu "entsorgen", wenn sie nicht mehr benötigt wird.

Tja stell Dir das mal in einer Schleife vor und/oder in einer langlebigen Klasse vor. Dann wird Dein "höchstens" schnell zum Problem.
 
Da hier der Zweck des Konstruktors noch nicht so wirklich genannt wurde:
Bei einer Methode wie
Code:
substring()
ist der neu erzeugte String nicht komplett "unabhängig" von dem ursprünglichen. Beide referenzieren ab diesem Zeitpunkt dasselbe char-Array. Kommt nun der ursprüngliche String out-of-scope und wird vom GC eingesammelt, bleibt trotzdem dessen char-Array übrig, weil es ja noch vom neuen String referenziert wird. Wenn dieses char-Array um ein Vielfaches größer als der neue String ist und dieser über einen längeren Zeitraum referenziert wird, ist es eine Überlegung wert, eine Kopie zu erzeugen. So wird ein neues char-Array mit der Länge des Strings erstellt. Der alte große "Klumpen" kann dadurch dann auch vom GC eingesammelt werden.
 
Verstehe ich nicht, ich würde new String("lala") niemals der anderen Variante vorziehen.
Eben, ich auch nicht. Soll man ja auch nicht. Gerade so, wie es der TO bei Effective Java gelesen hat.
Tja stell Dir das mal in einer Schleife vor und/oder in einer langlebigen Klasse vor. Dann wird Dein "höchstens" schnell zum Problem.
Ähhh, du meinst eigentlich doch eher sonst kurzlebige Klassen. Das Problem ist doch, dass manche Klassen nur deswegen so langlebig sind, weil irgend so 'n [IRONIE]Kasper einen dort definierten im Zweifelsfalle auch noch einen Leerstring in einer seiner Klassen als Konstante benutzt. Herzlichen Glückwunsch. :lol:[/IRONIE] Wär schön, wenn die VM solche Konstrukte wegoptimieren würde, keine Ahnung, ob sie das macht. Ansonsten werden langlebige Klassen ja eh' mehr oder weniger exessiv benutzt - z.B. String oder ganz oben auf der Liste Object.
 

Neue Themen


Zurück
Oben