Che cos’è il pool di stringhe in Java?

Sono confuso su StringPool in Java. Mi sono imbattuto in questo mentre leggevo il capitolo String in Java. Per favore aiutami a capire, in parole povere, cosa fa effettivamente StringPool.

Stampa true (anche se non usiamo il metodo equals : modo corretto per confrontare le stringhe)

  String s = "a" + "bc"; String t = "ab" + "c"; System.out.println(s == t); 

Quando il compilatore ottimizza i valori letterali delle stringhe, vede che entrambi s hanno lo stesso valore e quindi è necessario un solo object stringa. È sicuro perché String è immutabile in Java.
Come risultato, sia s che t puntano allo stesso object e qualche piccola memoria salvata.

Il nome ‘pool di stringhe’ deriva dall’idea che tutte le stringhe già definite siano memorizzate in un ‘pool’ e prima di creare un nuovo compilatore di oggetti String controlla se tale stringa è già definita.

Non penso che in realtà faccia molto, sembra che sia solo una cache per stringhe letterali. Se si hanno più stringhe con valori uguali, puntano tutti alla stessa stringa letterale nel pool di stringhe.

 String s1 = "Arul"; //case 1 String s2 = "Arul"; //case 2 

Nel caso 1, letteralmente s1 viene creato di recente e tenuto in piscina. Ma nel caso 2, letteralmente s2 si riferisce a s1, non ne creerà uno nuovo.

 if(s1 == s2) System.out.println("equal"); //Prints equal. String n1 = new String("Arul"); String n2 = new String("Arul"); if(n1 == n2) System.out.println("equal"); //No output. 

http://p2p.wrox.com/java-espanol/29312-string-pooling.html

Iniziamo con una citazione dalle specifiche della macchina virtuale:

Il caricamento di una class o di un’interfaccia che contiene un valore letterale String può creare un nuovo object String (§2.4.8) per rappresentare quel letterale. Ciò potrebbe non verificarsi se l’object String è già stato creato per rappresentare un’occorrenza precedente di tale valore letterale o se il metodo String.intern è stato richiamato su un object String che rappresenta la stessa stringa del letterale.

Questo potrebbe non accadere – Questo è un suggerimento, che c’è qualcosa di speciale negli oggetti String . Di solito, il richiamo di un costruttore creerà sempre una nuova istanza della class. Questo non è il caso delle stringhe, specialmente quando gli oggetti stringa sono “creati” con valori letterali. Quelle stringhe sono memorizzate in un archivio globale (pool) – o almeno i riferimenti sono conservati in un pool, e ogni volta che è necessaria una nuova istanza di una stringa già nota, la vm restituisce un riferimento all’object dal pool. In pseudo codice, può andare così:

 1: a := "one" --> if(pool[hash("one")] == null) // true pool[hash("one") --> "one"] return pool[hash("one")] 2: b := "one" --> if(pool[hash("one")] == null) // false, "one" already in pool pool[hash("one") --> "one"] return pool[hash("one")] 

Quindi in questo caso, le variabili a e b contengono riferimenti allo stesso object. In questo caso, abbiamo (a == b) && (a.equals(b)) == true .

Questo non è il caso se usiamo il costruttore:

 1: a := "one" 2: b := new String("one") 

Di nuovo, "one" viene creato nel pool ma poi creiamo una nuova istanza dallo stesso valore letterale, e in questo caso, porta a (a == b) && (a.equals(b)) == false

Quindi, perché abbiamo un pool di stringhe? Le stringhe e soprattutto i letterali String sono ampiamente usati nel tipico codice Java. E sono immutabili. Ed essere immutabili ha permesso di mettere in cache la stringa per risparmiare memoria e aumentare le prestazioni (meno sforzo per la creazione, meno rifiuti da raccogliere).

Come programmatori non ci dobbiamo preoccupare molto del pool di stringhe, a patto che teniamo a mente:

  • (a == b) && (a.equals(b)) può essere true o false (usa sempre equals per confrontare le stringhe)
  • Non utilizzare reflection per modificare il char[] backing char[] di una stringa (poiché non si sa chi è in esecuzione utilizzando quella stringa)

Quando la JVM carica le classi, o altrimenti vede una stringa letterale o una stringa intern codice, aggiunge la stringa a una tabella di ricerca per lo più nascosta che ha una copia di ciascuna di tali stringhe. Se viene aggiunta un’altra copia, il runtime dispone in modo tale che tutti i valori letterali si riferiscano allo stesso object stringa. Questo è chiamato “internare”. Se dici qualcosa del genere

 String s = "test"; return (s == "test"); 

tornerà true , perché il primo e il secondo “test” sono in realtà lo stesso object. Confrontare le stringhe internate in questo modo può essere molto, molto più veloce di String.equals , in quanto esiste un confronto di riferimento singolo piuttosto che un mucchio di confronti tra char .

Puoi aggiungere una stringa al pool chiamando String.intern() , che ti restituirà la versione pooled della stringa (che potrebbe essere la stessa stringa che stai internando, ma sarebbe pazzesco affidarti a questo – – spesso non si può essere sicuri di quale codice è stato caricato ed eseguito fino ad ora e internato la stessa stringa). La versione raggruppata (la stringa restituita da intern ) sarà uguale a qualsiasi letterale identico. Per esempio:

 String s1 = "test"; String s2 = new String("test"); // "new String" guarantees a different object System.out.println(s1 == s2); // should print "false" s2 = s2.intern(); System.out.println(s1 == s2); // should print "true"