# Strings erzeugen



## Generic1 (23. Apr 2012)

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!


----------



## tfa (23. Apr 2012)

Ja  und nein.


----------



## Generic1 (23. Apr 2012)

Das heißt jetzt was?


----------



## Tomate_Salat (23. Apr 2012)

Es ist nicht das gleiche:

```
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:

```
true
false
```

test1 und test2 referenzieren das gleiche Objekt. test1 und test3 nicht. Man soll eben die Variante hier nehmen:

```
String stringValue="value";
```

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


----------



## fidibus (23. Apr 2012)

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


----------



## tfa (23. Apr 2012)

> 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.


----------



## bygones (23. Apr 2012)

fidibus hat gesagt.:


> 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.


----------



## fidibus (23. Apr 2012)

Hallo,



> Zitat: fidibus
> 
> Beitrag anzeigen
> 
> ...



Diesbezüglich liegt der Fehler natürlich auf meiner Seite. Aber danke für die Korrektur. Man lernt halt nie aus. 
Grüße


----------



## fastjack (23. Apr 2012)

@tfa Bleibt bei 
	
	
	
	





```
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...


----------



## tfa (23. Apr 2012)

Ja, der wird irgendwann vom GC abgeräumt. Aber in diesem Beispiel gibt es kein Leak.


----------



## PollerJava (27. Apr 2012)

werden bei


```
String s = new String("test");
```

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


----------



## pl4gu33 (27. Apr 2012)

PollerJava hat gesagt.:


> werden bei
> 
> 
> ```
> ...



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"


----------



## fastjack (27. Apr 2012)

ähhh, laßt uns doch einfach wieder bei Posting 0 anfangen ok?


----------



## PollerJava (27. Apr 2012)

pl4gu33 hat gesagt.:


> 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?


----------



## ...ButAlive (27. Apr 2012)

Ja 
	
	
	
	





```
String test = new String("test");
```
 erzeugt zwei String-Objekte. Wobei "test" eine Konstante ist, und im Constantpool der Classfile "lebt". 
	
	
	
	





```
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 
	
	
	
	





```
String test = "test";
```
. 

Wobei ich mich frage, wieso String einen Copy-Konstruktor braucht, diese sind eigentlich bei Immutablen überflüssig.


----------



## Spacerat (28. Apr 2012)

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.

```
/**
     * 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;
    }
```


----------



## fastjack (29. Apr 2012)

Ich denke richtig ist aber, das dabei zwei String-Objekte entstehen und darum ging es im ganzen Thread.


```
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..


----------



## Spacerat (30. Apr 2012)

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.


----------



## fastjack (30. Apr 2012)

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.


----------



## xehpuk (30. Apr 2012)

Da hier der Zweck des Konstruktors noch nicht so wirklich genannt wurde:
Bei einer Methode wie 
	
	
	
	





```
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.


----------



## Spacerat (30. Apr 2012)

fastjack hat gesagt.:


> 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.


fastjack hat gesagt.:


> 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.


----------

