¿Cómo debo copiar cadenas en Java?

198
    String s = "hello";
    String backup_of_s = s;
    s = "bye";

En este punto, la variable de copia de seguridad todavía contiene el valor original "hola" (esto se debe a la inmutabilidad de String, ¿verdad?).

Pero, ¿es realmente seguro copiar cadenas con este método (que por supuesto no es seguro copiar objetos mutables normales), o es mejor escribir esto? :

    String s = "hello";
    String backup_of_s = new String(s);
    s = "bye";

En otras palabras, ¿cuál es la diferencia (si la hay) entre estos dos fragmentos?


EDITAR: la razón por la cual el primer fragmento es seguro:

Permítanme explicar las cosas con un poco más de detalle, en función de las buenas respuestas ya proporcionadas (que se centraron esencialmente en la cuestión de la diferencia de rendimiento entre los 2 fragmentos):

Las cadenas son inmutables en Java, lo que significa que un objeto String no se puede modificar después de su construcción. Por lo tanto,

String s = "hello";crea una nueva instancia de String y asigna su dirección a s( ssiendo una referencia a la instancia / objeto)

String backup_of_s = s;crea una nueva variable backup_of_sy la inicializa para que haga referencia al objeto al que hace referencia actualmente s.

Nota: la inmutabilidad de cadena garantiza que este objeto no se modificará: nuestra copia de seguridad es segura

Nota 2: el mecanismo de recolección de basura de Java garantiza que este objeto no se destruirá siempre y cuando se haga referencia al menos a una variable ( backup_of_sen este caso)

Finalmente, s = "bye";crea otra instancia de String (debido a la inmutabilidad, es la única forma) y modifica la svariable para que ahora haga referencia al nuevo objeto.

Sébastien
fuente

Respuestas:

139

Como las cadenas son inmutables, ambas versiones son seguras. Sin embargo, este último es menos eficiente (crea un objeto adicional y, en algunos casos, copia los datos del personaje).

Con esto en mente, se debe preferir la primera versión.

NPE
fuente
15
La inmutabilidad no tiene nada que ver con eso. Es simplemente cómo funcionan las referencias a objetos. Podría proporcionar un ejemplo de StringBuilder equivalente.
GriffeyDog
1
@BalusC, no puedo ver cómo el nuevo String () podría crear algo en el grupo de String de la JVM. Solo los literales de cadena y aquellos comprometidos con el grupo a través de intern () están en el grupo.
Snicolas
3
@GriffeyDog: estoy leyendo la pregunta menos literalmente. Lo que digo es que es seguro dar referencias a un objeto de cadena sin temor a que alguien pueda modificar la cadena.
NPE
2
@GriffeyDog Encuentro su comentario muy engañoso: la inmutabilidad es lo que hace que el primer fragmento sea seguro, ¿por qué diría que no tiene nada que ver con "eso"?
Sébastien
55
@Sebastien Todo lo que está haciendo es reasignar la variable de referencia spara referirse a un objeto diferente (el String"adiós"). Eso no afecta a lo que se refiere la variable de backup_of_sreferencia (el String"hola"). Como dije, podría proporcionar un ejemplo equivalente con StringBuilders, que no son inmutables. Mi comentario se refiere principalmente a la declaración de OP: en este punto, la variable de copia de seguridad todavía contiene el valor original "hola" (esto se debe a la inmutabilidad de String, ¿verdad?).
GriffeyDog
22

Las cadenas son objetos inmutables, por lo que puede copiarlas simplemente haciendo referencia a la referencia a ellas, porque el objeto al que se hace referencia no puede cambiar ...

Entonces puede copiar como en su primer ejemplo sin ningún problema:

String s = "hello";
String backup_of_s = s;
s = "bye";
aleroot
fuente
10

Su segunda versión es menos eficiente porque crea un objeto de cadena adicional cuando simplemente no hay necesidad de hacerlo.

La inmutabilidad significa que su primera versión se comporta de la manera esperada y, por lo tanto, es el enfoque preferido.

David Heffernan
fuente
0

El segundo caso también es ineficiente en términos del conjunto de cadenas, debe llamar explícitamente a intern () en la referencia de retorno para hacerlo interno.

Amit Yadav
fuente
-16
String str1="this is a string";
String str2=str1.clone();

¿Qué tal una copia como esta? Creo que obtener una nueva copia es mejor, para que los datos de str1no se vean afectados cuando str2se haga referencia y se modifique en otra acción.

Cqiao13
fuente
3
StringEs inmutable. clonar cadenas no tiene mucho sentido.
Vladimir