¿Por qué las cadenas no pueden ser mutables en Java y .NET?
¿Por qué decidieron hacer String
inmutable en Java y .NET (y algunos otros lenguajes)? ¿Por qué no lo hicieron mutable?
Según Effective Java , capítulo 4, página 73, 2.ª edición:
"Hay muchas buenas razones para esto: las clases inmutables son más fáciles de diseñar, implementar y usar que las clases mutables. Son menos propensas a errores y son más seguras.
[...]
" Los objetos inmutables son simples. Un objeto inmutable puede estar exactamente en un estado, el estado en el que fue creado. Si se asegura de que todos los constructores establezcan invariantes de clase, entonces se garantiza que estos invariantes permanecerán verdaderos para siempre, con ningún esfuerzo de tu parte.
[...]
Los objetos inmutables son inherentemente seguros para subprocesos; no requieren sincronización. No pueden corromperse si varios subprocesos acceden a ellos simultáneamente. Este es de lejos el enfoque más sencillo para lograr la seguridad de los subprocesos. De hecho, ningún hilo puede observar ningún efecto de otro hilo sobre un objeto inmutable. Por lo tanto, los objetos inmutables se pueden compartir libremente.
[...]
Otros pequeños puntos del mismo capítulo:
No solo puedes compartir objetos inmutables, sino que también puedes compartir sus partes internas.
[...]
Los objetos inmutables son excelentes bloques de construcción para otros objetos, ya sean mutables o inmutables.
[...]
La única desventaja real de las clases inmutables es que requieren un objeto separado para cada valor distinto.
Hay al menos dos razones.
Primero: seguridad http://www.javafaq.nu/java-article1060.html
La razón principal por la que String se hizo inmutable fue la seguridad. Mire este ejemplo: Tenemos un método de apertura de archivos con verificación de inicio de sesión. Pasamos una cadena a este método para procesar la autenticación que es necesaria antes de que la llamada pase al sistema operativo. Si String era mutable, era posible modificar de alguna manera su contenido después de la verificación de autenticación antes de que el sistema operativo reciba la solicitud del programa, entonces es posible solicitar cualquier archivo. Entonces, si tiene derecho a abrir un archivo de texto en el directorio de usuario pero luego, sobre la marcha, cuando de alguna manera logra cambiar el nombre del archivo, puede solicitar abrir el archivo "passwd" o cualquier otro. Luego se podrá modificar un archivo y será posible iniciar sesión directamente en el sistema operativo.
Segundo: eficiencia de la memoria http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html
JVM mantiene internamente el "String Pool". Para lograr la eficiencia de la memoria, JVM referirá el objeto String del grupo. No creará los nuevos objetos String. Entonces, cada vez que crea un nuevo literal de cadena, JVM verificará en el grupo si ya existe o no. Si ya está presente en el grupo, simplemente proporcione la referencia al mismo objeto o cree el nuevo objeto en el grupo. Habrá muchas referencias que apuntan a los mismos objetos String, si alguien cambia el valor, afectará a todas las referencias. Entonces, el sol decidió hacerlo inmutable.
En realidad, las razones por las que las cadenas son inmutables en Java no tienen mucho que ver con la seguridad. Las dos razones principales son las siguientes:
Seguridad de la cabeza:
Las cadenas son un tipo de objeto muy utilizado. Por lo tanto, está más o menos garantizado su uso en un entorno multiproceso. Las cadenas son inmutables para garantizar que sea seguro compartir cadenas entre subprocesos. Tener cadenas inmutables garantiza que al pasar cadenas del hilo A a otro hilo B, el hilo B no pueda modificar inesperadamente la cadena del hilo A.
Esto no sólo ayuda a simplificar la ya bastante complicada tarea de la programación multiproceso, sino que también ayuda con el rendimiento de las aplicaciones multiproceso. El acceso a objetos mutables debe sincronizarse de alguna manera cuando se puede acceder a ellos desde múltiples subprocesos, para garantizar que un subproceso no intente leer el valor de su objeto mientras otro subproceso lo modifica. La sincronización adecuada es difícil de realizar correctamente para el programador y costosa en tiempo de ejecución. Los objetos inmutables no se pueden modificar y, por lo tanto, no necesitan sincronización.
Actuación:
Si bien se ha mencionado la pasantía de String, solo representa una pequeña ganancia en la eficiencia de la memoria para los programas Java. Sólo se internan cadenas literales. Esto significa que sólo las cadenas que son iguales en su código fuente compartirán el mismo objeto de cadena. Si su programa crea dinámicamente cadenas que son iguales, se representarán en objetos diferentes.
Más importante aún, las cadenas inmutables les permiten compartir sus datos internos. Para muchas operaciones de cadenas, esto significa que no es necesario copiar la matriz de caracteres subyacente. Por ejemplo, digamos que desea tomar los cinco primeros caracteres de String. En Java, llamarías myString.substring(0,5). En este caso, lo que hace el método substring() es simplemente crear un nuevo objeto String que comparte el char[] subyacente de myString, pero quién sabe si comienza en el índice 0 y termina en el índice 5 de ese char[]. Para poner esto en forma gráfica, terminarías con lo siguiente:
| myString |
v v
"The quick brown fox jumps over the lazy dog" <-- shared char[]
^ ^
| | myString.substring(0,5)
Esto hace que este tipo de operaciones sean extremadamente económicas, y O(1), ya que la operación no depende de la longitud de la cadena original ni de la longitud de la subcadena que necesitamos extraer. Este comportamiento también tiene algunos beneficios de memoria, ya que muchas cadenas pueden compartir su carácter subyacente [].
Seguridad y rendimiento del hilo. Si una cadena no se puede modificar, es seguro y rápido pasar una referencia entre varios subprocesos. Si las cadenas fueran mutables, siempre tendría que copiar todos los bytes de la cadena a una nueva instancia o proporcionar sincronización. Una aplicación típica leerá una cadena 100 veces por cada vez que sea necesario modificarla. Ver wikipedia sobre inmutabilidad .
Uno realmente debería preguntarse: "¿por qué X debería ser mutable?" Es mejor optar por la inmutabilidad por defecto, debido a los beneficios ya mencionados por Princess Fluff . Debería ser una excepción que algo sea mutable.
Desafortunadamente, la mayoría de los lenguajes de programación actuales tienen por defecto la mutabilidad, pero es de esperar que en el futuro el valor predeterminado sea más la inmutabilidad (consulte Una lista de deseos para el próximo lenguaje de programación convencional ).