2013-01-23 11 views
8

Ho letto questo Questions about Java's String pool e ho compreso il concetto di base del pool di stringhe ma ancora non capisco il comportamento.Stringa Comportamento pool

Primo: funziona se si assegna direttamente il valore e sia S1 e S2 riferiscono allo stesso oggetto in piscina

String s1 = "a" + "bc"; 
String s2 = "ab" + "c"; 
System.out.println("s1 == s2? " + (s1 == s2)); 

Ma poi se cambio la stringa s1 + = "d", poi la piscina dovrebbe avere un oggetto stringa "abcd"? poi quando cambio s2 + = "d", dovrebbe trovare l'oggetto stringa "abcd" nel pool e dovrebbe assegnare l'oggetto a s2? ma non lo fa e non si riferiscono allo stesso oggetto. Perché?

String s1 = "abc"; 
String s2 = "abc"; 
System.out.println("s1 == s2? " + (s1 == s2)); 

s1 += "d";     
s2 += "d"; 
System.out.println("s1 == s2? " + (s1 == s2)); 
+0

possibile duplicato di [Domande su Java's String pool] (http://stackoverflow.com/questions/1881922/questions-about-javas-string-pool) – EJP

+0

@EJP Asker menziona proprio questo argomento e dice di no rispondi alle sue domande. – glomad

risposta

7

stringhe sono garantiti per essere messe in comune quando si chiama String.intern() su una stringa.

String s1 = "abcd".intern(); 
String s2 = "abc"; 
s2 += "d"; 
s2 = s2.intern(); 
s1 == s2 // returns true 

Quando compilatore vede una costante è abbastanza intelligente per ottimizzare e riunire la stringa letterale, vale a dire:

String s1 = "abcd"; 
String s2 = "abcd"; 
s1 == s2 // returns true 

Java Language Specification stati:

Ogni stringa letterale è un riferimento (§ 4.3) a un'istanza (§4.3.1, §12.5) di classe String (§4.3.3). Gli oggetti stringa hanno un valore costante. Stringhe letterali o, più in generale, stringhe che sono i valori di costante espressioni (§15.28) -aggiungere "internato" in modo da in modo da condividere istanze univoche, utilizzando il metodo String.intern.

Quindi, nel caso di s2 += "d", compilatore non era così intelligente come sei e solo in pool "d".

+2

Mentre questa risposta afferma un fatto reale, non spiega la * perché * base della domanda. – Vulcan

+0

Interessante, così l'intera stringa del pool manca il punto? se ho bisogno di aggiungere .intern() a ogni singola stringa? – Jaxox

+5

@ user2005443 Generalmente non si dovrebbe aggiungere 'intern()' a ogni stringa. Questa è l'ottimizzazione prematura. Se ci sono determinate stringhe che si conoscono (o che si scoprono tramite la profilazione) che verranno utilizzate molto, potrebbero migliorare le prestazioni, ma se la si utilizza indiscriminatamente può [essere abbastanza pericolosa] (http: //www.codeinstructions. com/2009/01/busting-javalangstringintern-myths.html). – Jeff

0

Questa è la mia ipotesi:

String s1 = "a" + "bc"; Stringa s2 = "ab" + "c";

Penso che siano tempo di compilazione questi sono determinati a produrre la stessa stringa e quindi solo un oggetto è fatto per entrambi.

Ma quando si aggiunge "d" ad entrambi, questo viene fatto separatamente per entrambe le stringhe (poiché è fatto in tempo reale, potrebbero esserci cose come eccezioni che lo interrompono ecc., Quindi non può pre-farlo) e quindi non fa automaticamente riferimento a un oggetto.

+0

Perché indovinare? È tutto descritto nel JLS. – EJP

3

Non ne sono sicuro, quindi si tratta di speculazioni, ma ho il sospetto che nel primo esempio potrebbe esserci qualche trucco del compilatore (dove è in linea e abbastanza ovvio cosa sta succedendo), ma non è abbastanza intelligente da farlo uscire nel secondo esempio (dove non è così ovvio).

Se ho ragione, il compilatore vede "a" + "bc" e lo comprime semplicemente in fase di compilazione a "abc" oppure vede le due linee e raggruppa le stringhe perché si rende conto che verranno utilizzate. Sto scommettendo sul primo ..

Non tutte le stringhe vengono necessariamente raggruppate.

+7

Questo è corretto, il compilatore si piega costantemente sulle costanti in fase di compilazione e mette una sola stringa, "abc", nel pool costante per la classe. Credo che tutte le stringhe che provengono dal pool costante vengano internate. Altre stringhe, create in fase di esecuzione, non sono internate a meno che non si chiami esplicitamente String # intern su di esse. –

+0

Questo è davvero quello che succede. Se controlli il bytecode, vedrai che "a" + "bc" è tradotto in una singola istruzione ldc (premendo una costante), mentre l'altra istruzione s1 + "d" si traduce in una chiamata a StringBuilder. – Gothmog

2

Vedere la documentazione per String#intern(). L'ultima riga indica:

Tutte le stringhe letterali e le espressioni costanti a valori stringa sono internate.

L'esempio += non è una stringa letterale né un'espressione costante con valori stringa, pertanto non viene inserita nel pool String.

2

Il compilatore in grado di eseguire la valutazione costante, ma non nel caso in cui si modificano i valori

Prova invece segue e vedere cosa succede se si lascia cadere final da entrambi variabile.

final String s1 = "abc"; 
final String s2 = "abc"; 
System.out.println("s1 == s2? " + (s1 == s2)); 

String s3 = s1 + "d";     
String s4 = s2 + "d"; 
System.out.println("s3 == s4? " + (s3 == s4)); 
0

Credo che quello che succede qui è: 1. per String s1 = "a" + "bc"; Stringa s2 = "ab" + "c"; Java compilatore è abbastanza intelligente per sapere che il valore letterale di S1 ​​e S2 sono gli stessi, in modo che il compilatore li indica lo stesso valore letterale nel pool di stringa di

  1. per s1 + = "d";
    s2 + = "d";

non c'è modo il compilatore sa se S1 ed S2 finirebbe per essere lo stesso valore, In fase di esecuzione, a meno che non si chiama String.Intern(), JVM non controllerà il pool stringa letterale per vedere se il valore è già lì.