Perché la class String ha un costruttore di copie?

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

Se le classi immutabili, le copie sarebbero uguali agli originali, allora perché la class String in Java ha un costruttore di copie? È un errore o c’è una ragione dietro questa implementazione? Nei documenti Java è specificato che:

 /** * 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) { .... ....} 

Il motivo principale per copiare una stringa è “tagliare il bagaglio” , cioè tagliare il char array sottostante solo per ciò che è necessario.

Il char array sottostante può essere principalmente troppo grande perché quando si crea una stringa chiamando la substring , il char array può essere condiviso tra la nuova istanza della stringa e l’istanza della stringa di origine; un offset punta al primo carattere e la lunghezza è inclusa.

L’espressione che uso, “ritaglia il bagaglio” , è presa dal codice sorgente del costruttore di copia String:

  164 public String(String original) { 165 int size = original.count; 166 char[] originalValue = original.value; 167 char[] v; 168 if (originalValue.length > size) { 169 // The array representing the String is bigger than the new 170 // String itself. Perhaps this constructor is being called 171 // in order to trim the baggage, so make a copy of the array. 172 int off = original.offset; 173 v = Arrays.copyOfRange(originalValue, off, off+size); 174 } else { 175 // The array representing the String is the same 176 // size as the String, so no point in making a copy. 177 v = originalValue; 178 } 179 this.offset = 0; 180 this.count = size; 181 this.value = v; 

Questo è qualcosa che molti sviluppatori dimenticano ed è importante perché una piccola stringa può impedire il garbaging di un array di caratteri più grande. Vedi questa domanda correlata in cui ho già sottolineato questo: Java non garbage collecting memory . Molti sviluppatori considerano che la decisione dei progettisti Java di utilizzare questo vecchio trucco di ottimizzazione che era familiare ai programmatori C, in effetti, faceva più male che bene. Molti di noi lo sanno perché siamo stati morsi e abbiamo dovuto esaminare il codice sorgente di Sun per capire cosa è successo …

Come sottolinea Marko (vedi commenti sotto), in OpenJDK, a partire da java 7 Update 6, la substring non condivide più il char array e il costruttore String(String) è, quindi, inutile. Ma è ancora veloce (anzi addirittura più veloce) e poiché questa modifica non è stata propagata a tutta la VM (e probabilmente non a tutti i tuoi clienti), consiglierei di mantenere questa best practice per usare la new String(substring) quando la vecchia il comportamento lo stava giustificando.