¿Por qué la clase String tiene un constructor de copia?

Posible duplicado:
¿Cuál es el propósito de la expresión “new String (…)” en Java?

Si las copias de objetos de clases inmutables serían iguales a los originales, ¿por qué la clase String en Java tiene un constructor de copia? ¿Es un error o hay una razón detrás de esta implementación? En los documentos de Java, se especifica que:

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

La razón principal para copiar una cuerda es “recortar el equipaje” , es decir, recortar la matriz de caracteres subyacente solo a lo necesario.

La matriz de caracteres subyacente puede ser principalmente demasiado grande porque cuando se crea una cadena llamando a una substring , la matriz char se puede compartir entre la nueva instancia de cadena y la instancia de la cadena fuente; un desplazamiento apunta al primer carácter y la longitud está incluida.

La expresión que uso, “recortar el equipaje” , se toma del código fuente del constructor de copia de cadenas:

  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; 

Esto es algo que muchos desarrolladores olvidan y es importante porque una pequeña cadena puede evitar que se acumule una matriz de caracteres más grande. Vea esta pregunta relacionada donde ya señalé esto: Java no recolección de basura . Muchos desarrolladores consideran que la decisión de los diseñadores de Java de utilizar este viejo truco de optimización que era familiar para los codificadores C hizo, de hecho, más daño que bien. Muchos de nosotros lo sabemos porque nos mordió y tuvimos que buscar en el código fuente de Sun para entender lo que sucedió …

Como señala Marko (ver comentarios a continuación), en OpenJDK, comenzando desde java 7 Actualización 6, la substring ya no comparte la matriz char y el constructor String(String) es, por lo tanto, inútil. Pero todavía es rápido (incluso más rápido de hecho) y como este cambio no se ha propagado a todas las VM (y probablemente no a todos sus clientes), recomiendo mantener esta práctica recomendada para utilizar una new String(substring) cuando la anterior el comportamiento lo justificaba.