Inmutabilidad de cadenas en Java

Resuelto Light_handle asked hace 15 años • 26 respuestas

Considere el siguiente ejemplo.

String str = new String();

str  = "Hello";
System.out.println(str);  //Prints Hello

str = "Help!";
System.out.println(str);  //Prints Help!

Ahora, en Java, las cadenas son inmutables. Entonces, ¿cómo es posible que al objeto strse le pueda asignar un valor diferente como "¡Ayuda!". ¿No contradice esto la inmutabilidad de las cadenas en Java? ¿Alguien puede explicarme el concepto exacto de inmutabilidad?

Editar:

De acuerdo. Ahora lo entiendo, pero solo una pregunta de seguimiento. ¿Qué pasa con el siguiente código?

String str = "Mississippi"; 
System.out.println(str); // prints Mississippi 

str = str.replace("i", "!"); 
System.out.println(str); // prints M!ss!ss!pp! 

¿Significa esto que se crean dos objetos nuevamente ("Mississippi" y "M!ss!ss!pp!") y la referencia strapunta a un objeto diferente después del replace()método?

Light_handle avatar Oct 12 '09 08:10 Light_handle
Aceptado

strNo es un objeto, es una referencia a un objeto. "Hello"y "Help!"son dos objetos distintos String. Por tanto, str apunta a una cadena. Puedes cambiar lo que apunta , pero no aquello a lo que apunta .

Tome este código, por ejemplo:

String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"

Ahora bien, no hay nada que podamos hacer s1que afecte el valor de s2. Se refieren al mismo objeto (la cadena "Hello"), pero ese objeto es inmutable y, por tanto, no puede modificarse.

Si hacemos algo como esto:

s1 = "Help!";
System.out.println(s2); // still prints "Hello"

Aquí vemos la diferencia entre mutar un objeto y cambiar una referencia. s2todavía apunta al mismo objeto que inicialmente establecimos s1para apuntar. Establecer solo cambia la s1referencia , mientras que el objeto al que se refería originalmente permanece sin cambios."Help!"String

Si las cadenas fueran mutables, podríamos hacer algo como esto:

String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"

Edite para responder a la edición de OP:

Si observa el código fuente de String.replace(char,char) (también disponible en src.zip en su directorio de instalación de JDK; un consejo profesional es buscar allí cada vez que se pregunte cómo funciona algo realmente), puede ver qué lo que hace es lo siguiente:

  • Si hay una o más apariciones de oldCharen la cadena actual, haga una copia de la cadena actual donde todas las apariciones de oldCharse reemplacen con newChar.
  • Si oldCharno está presente en la cadena actual, devuelve la cadena actual.

Entonces sí, "Mississippi".replace('i', '!')crea un nuevo Stringobjeto. Nuevamente se cumple lo siguiente:

String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects

Tu tarea por ahora es ver qué hace el código anterior si lo cambias s1 = s1.replace('i', '!');a s1 = s1.replace('Q', '!');:)


1 En realidad, es posible mutar cadenas (y otros objetos inmutables). Requiere reflexión y es muy, muy peligroso y nunca debería usarse a menos que realmente esté interesado en destruir el programa.

gustafc avatar Oct 12 '2009 07:10 gustafc

El objeto al que strhace referencia puede cambiar, pero los Stringobjetos reales no pueden cambiar.

Los Stringobjetos que contienen la cadena "Hello"no "Help!"pueden cambiar sus valores, por lo que son inmutables.

La inmutabilidad de Stringlos objetos no significa que las referencias que apuntan al objeto no puedan cambiar.

Una forma de evitar que la strreferencia cambie es declararla como final:

final String STR = "Hello";

Ahora, intentar asignar otro Stringprovocará STRun error de compilación.

coobird avatar Oct 12 '2009 01:10 coobird