Inmutabilidad de cadenas en Java
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 str
se 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 str
apunta a un objeto diferente después del replace()
método?
str
No 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 s1
que 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. s2
todavía apunta al mismo objeto que inicialmente establecimos s1
para apuntar. Establecer solo cambia la s1
referencia , 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
oldChar
en la cadena actual, haga una copia de la cadena actual donde todas las apariciones deoldChar
se reemplacen connewChar
. - Si
oldChar
no está presente en la cadena actual, devuelve la cadena actual.
Entonces sí, "Mississippi".replace('i', '!')
crea un nuevo String
objeto. 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.
El objeto al que str
hace referencia puede cambiar, pero los String
objetos reales no pueden cambiar.
Los String
objetos que contienen la cadena "Hello"
no "Help!"
pueden cambiar sus valores, por lo que son inmutables.
La inmutabilidad de String
los objetos no significa que las referencias que apuntan al objeto no puedan cambiar.
Una forma de evitar que la str
referencia cambie es declararla como final
:
final String STR = "Hello";
Ahora, intentar asignar otro String
provocará STR
un error de compilación.