Qual è lo scopo dell’espressione “nuova stringa (…)” in Java?

Osservando gli esempi di codice online, a volte mi sono imbattuto in un’assegnazione di una costante String a un object String tramite l’utilizzo del nuovo operatore.

Per esempio:

String s; ... s = new String("Hello World"); 

Questo, ovviamente, rispetto a

 s = "Hello World"; 

Non ho familiarità con questa syntax e non ho idea di quale sarebbe lo scopo o l’effetto. Poiché le costanti String vengono tipicamente memorizzate nel pool costante e quindi in qualsiasi rappresentazione che la JVM ha per gestire le costanti String, qualcosa dovrebbe essere allocato anche nell’heap?

L’unico punto in cui potrebbe essere necessario il new String(String) consiste nel forzare una sottostringa a copiare in un nuovo array di caratteri sottostante, come in

 small=new String(huge.substring(10,20)) 

Tuttavia, questo comportamento è sfortunatamente non documentato e dipende dall’implementazione.

Sono stato bruciato da questo quando ho letto file di grandi dimensioni (alcuni fino a 20 MiB) in una stringa e lo ho intagliato in linee dopo il fatto. Ho finito con tutte le stringhe per le linee che fanno riferimento al carattere [] composto da un intero file. Sfortunatamente, questo involontariamente ha mantenuto un riferimento all’intero array per le poche righe a cui ero tenuto più a lungo dell’elaborazione del file – ero costretto a usare il new String() per aggirare il problema.

L’unico modo agnostico di implementazione è:

 small=new String(huge.substring(10,20).toCharArray()); 

Questo sfortunatamente deve copiare l’array due volte, una volta per toCharArray() e una volta nel costruttore String.

Deve esserci un modo documentato per ottenere una nuova stringa copiando i caratteri di uno esistente; o la documentazione di String(String) deve essere migliorata per renderla più esplicita (c’è un’implicazione in questo, ma è piuttosto vaga e aperta all’interpretazione).

Trappola di supporre ciò che il Doc non dice

In risposta ai commenti, che continuano ad arrivare, osserva quale implementazione Apache Harmony della new String() era:

 public String(String string) { value = string.value; offset = string.offset; count = string.count; } 

Esatto, nessuna copia dell’array sottostante lì. Eppure, è ancora conforms alla documentazione della stringa (Java 7), in quanto:

Inizializza un object String appena creato in modo che rappresenti la stessa sequenza di caratteri dell’argomento; in altre parole, la stringa appena creata è una copia della stringa argomento. A meno che non sia necessaria una copia esplicita dell’originale, l’uso di questo costruttore non è necessario poiché le stringhe sono immutabili.

Il pezzo saliente è “copia della stringa argomento”; non dice “copia della stringa argomento e dell’array di caratteri sottostante che supporta la stringa”.

Fai attenzione a programmare sulla documentazione e non su un’implementazione .

L’unica volta che ho trovato questo utile è nel dichiarare le variabili di blocco:

 private final String lock = new String("Database lock"); .... synchronized(lock) { // do something } 

In questo caso, gli strumenti di debug come Eclipse mostreranno la stringa quando si elenca ciò che blocca un thread attualmente in attesa o in attesa. Devi usare “new String”, cioè allocare un nuovo object String, perché altrimenti un letterale stringa condiviso potrebbe essere bloccato in qualche altro codice non correlato.

String s1 = “pippo”; letteral andrà in StringPool e s1 farà riferimento.

String s2 = “pippo”; questa volta controllerà che “foo” letteral sia già disponibile in StringPool o meno poiché ora esiste, quindi s2 farà riferimento allo stesso letterale.

String s3 = new String (“pippo”); “foo” letteral sarà creato in StringPool prima, quindi attraverso il costruttore di string arg verrà creato String Object cioè “foo” nell’heap a causa della creazione dell’object tramite il nuovo operatore, quindi s3 lo riferirà.

String s4 = new String (“pippo”); come s3

quindi System.out.println (s1 == s2); // true grazie al confronto letterale.

e System.out.println (s3 == s4); // false a causa del confronto tra oggetti (s3 e s4 vengono creati in punti diversi nell’heap)

L’unica utilità per questo costruttore descritta da Software Monkey e Ruggs sembra essere scomparsa da JDK7. Non esiste più un campo di offset nella stringa di class e la sottostringa viene sempre utilizzata

 Arrays.copyOfRange(char[] original, int from, int to) 

per tagliare il char array per la copia.

Bene, questo dipende da cosa “…” è nell’esempio. Se si tratta di un StringBuffer, per esempio, o di un array di byte, o qualcosa del genere, otterrai una stringa costruita dai dati che stai passando.

Ma se è solo un’altra stringa, come in una new String("Hello World!") , Allora dovrebbe essere sostituita semplicemente da "Hello World!" , in tutti i casi. Le stringhe sono immutabili, quindi la clonazione non ha alcuno scopo – è solo più prolissa e meno efficiente creare un nuovo object String solo per servire come duplicato di una stringa esistente (che sia una variabile letterale o un’altra variabile String già esistente).

Infatti, Effective Java (che consiglio vivamente) usa esattamente questo come uno dei suoi esempi di “Evita di creare oggetti non necessari”:


Come esempio estremo di cosa non fare, considera questa affermazione:

 String s = new String("stringette"); **//DON'T DO THIS!** 

(Efficace Java, Seconda edizione)

Generalmente, questo indica qualcuno che non si trova a proprio agio con lo stile C ++ di nuova generazione quando viene inizializzato.

Tornando ai giorni C, non era considerata una buona forma per definire le variabili automatiche in un ambito interno; C ++ ha eliminato la restrizione del parser e Java lo ha esteso.

Quindi vedi il codice che ha

 int q; for(q=0;q 

Nel caso estremo, tutte le dichiarazioni possono trovarsi all'inizio di una funzione e non in ambiti chiusi come il ciclo for qui.

In generale, tuttavia, l'effetto di ciò è di provocare una chiamata a un ctor di stringa una volta e la stringa risultante gettata via. (Il desiderio di evitare questo è solo ciò che ha portato Stroustrup a consentire dichiarazioni in qualsiasi parte del codice.) Quindi hai ragione sul fatto che sia uno stile non necessario e cattivo nel migliore dei casi, e possibilmente in realtà cattivo.

Credo che dipenderà dagli esempi di codice che stai vedendo.

La maggior parte delle volte che si utilizza il costruttore di classi “new String ()” nell’esempio di codice è solo per mostrare una class java molto ben nota invece di crearne una nuova.

Dovresti evitare di usarlo la maggior parte delle volte. Non solo perché i letterali delle stringhe sono internati, ma principalmente perché le string sono immutabili. Non ha senso avere due copie che rappresentano lo stesso object.

Mentre l’articolo mensionato da Ruggs è “interessante” non dovrebbe essere usato a meno di circostanze molto specifiche, perché potrebbe creare più danni che benefici. Dovrai codificare un’implementazione piuttosto che una specifica e lo stesso codice non potrebbe eseguire lo stesso, ad esempio in JRockit, IBM VM o altro.

Esistono due modi in cui è ansible creare stringhe in Java. Di seguito sono riportati gli esempi per entrambi i modi: 1) Dichiarare una variabile di tipo String (una class in Java) e assegnarla a un valore che deve essere inserito tra virgolette. Questo creerà una stringa nell’area di memoria della stringa. ad esempio: String str = “JAVA”;

2) Utilizzare il costruttore della class String e passare una stringa (tra virgolette doppie) come argomento. es .: String s = new String (“JAVA”); Questo creerà una nuova stringa JAVA nella memoria principale e anche nel pool di stringhe se questa stringa non è già presente nel pool di stringhe.