¿Por qué String es inmutable en Java?

177

Me preguntaron en una entrevista por qué String es inmutable

Respondí así:

Cuando creamos una cadena en Java como String s1="hello";entonces, se creará un objeto en el conjunto de cadenas (hola) y s1 apuntará a hola . Ahora, si lo hacemos nuevamente, no String s2="hello";se creará otro objeto, pero s2 señalará hello porque JVM primero comprobará si el mismo objeto está presente en el conjunto de cadenas o no. Si no está presente, solo se crea uno nuevo o no.

Ahora, si supongamos que java permite una cadena mutable, entonces si cambiamos s1 a hello worldentonces el valor s2 también será hello worldasí que java String es inmutable.

¿Puede alguien decirme si mi respuesta es correcta? o incorrecta ?

balanceo
fuente
46
Por qué siempre es difícil de responder. La respuesta más correcta es probablemente: porque los diseñadores de idiomas pensaron que era una buena idea.
Keppil
1
vea también esta respuesta
3
Tu respuesta no está en el punto. C ++ std::stringes mutable, pero también tienen un grupo de cadenas (bueno, más correctamente, grupo de matriz de caracteres).
Siyuan Ren
1
@rocking Para ser honesto, si es correcto o no depende de cómo lo lean. La cuestión es que Java puede tener un conjunto de cadenas porque las cadenas son inmutables. Si decidieran hacer que las cadenas sean mutables, entonces no habrían usado un conjunto de cadenas; por lo tanto, puede no ser exacto decir "conjunto de cadenas, por lo tanto cadenas inmutables"; es más al revés. Las razones para elegir cadenas inmutables se describen a continuación, y el conjunto de cadenas es una estrategia de trabajo debido a eso. Aún así, su respuesta no es incorrecta , simplemente no parece completa. Solo tendrás que esperar y ver lo que dicen.
Jason C
34
Simplemente no puedo entender por qué esta pregunta se cerró. La supuesta respuesta relacionada ni siquiera es sobre Java y no aborda el tema principal de esta pregunta, que es "por qué". Para mí este es uno de esos casos de una comunidad irresponsable que actúa sobre una cuestión de la que no saben nada. Lo he nominado para reabrir.
Edwin Dalorzo

Respuestas:

163

String es inmutable por varias razones, aquí hay un resumen:

  • Seguridad : los parámetros generalmente se representan como Stringen conexiones de red, URL de conexión de base de datos, nombres de usuario / contraseñas, etc. Si fuera mutable, estos parámetros podrían cambiarse fácilmente.
  • Sincronización y concurrencia: hacer que String sea inmutable automáticamente los hace seguros para subprocesos, lo que resuelve los problemas de sincronización.
  • Almacenamiento en caché : cuando el compilador optimiza sus objetos de cadena, ve que si dos objetos tienen el mismo valor (a = "prueba" yb = "prueba") y, por lo tanto, solo necesita un objeto de cadena (para ambos ayb, estos dos tendrán apunte al mismo objeto).
  • Carga de clases : Stringse utiliza como argumentos para la carga de clases. Si es mutable, podría provocar que se cargue una clase incorrecta (porque los objetos mutables cambian su estado).

Dicho esto, la inmutabilidad de Stringsolo significa que no puede cambiarlo utilizando su API pública. De hecho, puede omitir la API normal utilizando la reflexión. Mira la respuesta aquí .

En su ejemplo, si Stringera mutable, considere el siguiente ejemplo:

  String a="stack";
  System.out.println(a);//prints stack
  a.setValue("overflow");
  System.out.println(a);//if mutable it would print overflow
Comunidad
fuente
14
¿Cómo podría afectar la seguridad?
Archit Maheshwari
2
¿Alguien puede explicar la carga de clases con un ejemplo si es posible?
Viraj
66
En cuanto a la seguridad, si estoy interesado en cambiar los parámetros de conexión, es sencillo en tiempo de ejecución (con un depurador, etc.). Sobre la carga de clases, siString es mutable, el cargador de clases tomaría la cadena que se pasaba, haría una copia y no cambiaría su copia. Cuando piense en un problema con java.lang.Strings mutable , piense en cómo C ++ resuelve este problema (ya que tiene std::strings mutable .
Expiación limitada el
Con respecto a la seguridad, ¿cómo se puede cambiar una cadena mutable cuando se ejecuta el programa?
MasterJoe2
Como String es inmutable, su código hash se almacena en caché en el momento de la creación y no necesita calcularse nuevamente.
Abdul Alim Shakir
45

Los desarrolladores de Java deciden que las cadenas son inmutables debido al siguiente diseño de aspecto , eficiencia y seguridad .

Las cadenas de diseño se crean en un área de memoria especial en el montón de Java conocida como "grupo interno de cadenas". Mientras crea una nueva cadena (no en el caso de usar el constructor String () o cualquier otra función String que internamente use el constructor String () para crear un nuevo objeto String; el constructor String () siempre crea una nueva cadena constante en el grupo a menos que llame al método interno () ) variable que busca en el grupo para verificar si ya existe. Si existe, devuelva la referencia del objeto String existente. Si la cadena no es inmutable, cambiar la cadena con una referencia conducirá al valor incorrecto para las otras referencias.

De acuerdo con este artículo en DZone:

Security String se usa ampliamente como parámetro para muchas clases de Java, por ejemplo, conexión de red, apertura de archivos, etc. Si String no fuera inmutable, una conexión o un archivo se cambiarían y darían lugar a graves amenazas de seguridad. Las cadenas mutables también pueden causar problemas de seguridad en Reflection, ya que los parámetros son cadenas.

Eficiencia El código hash de cadena se usa con frecuencia en Java. Por ejemplo, en un HashMap. Ser inmutable garantiza que el código hash siempre será el mismo, por lo que se puede almacenar en caché sin preocuparse por los cambios. Eso significa que no es necesario calcular el código hash cada vez que se usa.

Alex Mathew
fuente
77
Su comprensión del conjunto de cadenas es incorrecta. Las constantes de cadena se crean en el grupo interno, pero es perfectamente posible tener más de un objeto de cadena con el mismo texto. Estoy de acuerdo en que las cadenas son inmutables permite la agrupación, pero no hay tanta agrupación como usted ha indicado.
Jon Skeet
@ JonSkeet Tienes razón. Cadena s1 = nueva Cadena ("prueba"); La instrucción crea una nueva cadena constante en el grupo interno a menos que llamemos al método intern (). Gracias por profundizar mi conocimiento sobre el grupo interno de cadenas.
Alex Mathew
2
Es más que simplemente usar el constructor de cadenas: casi todo lo que crea una nueva cadena, por ejemplo, subcadena, división, concat, etc. creará nuevas cadenas. Las constantes de tiempo de compilación son el caso especial aquí, no la norma ...
Jon Skeet
@JonSkeet substring (), concat (), replace (), etc. utilizan internamente el constructor de cadenas para crear un nuevo objeto de cadena. Gracias por mejorar mi respuesta.
Alex Mathew
2
@ JonSkeet: todas estas respuestas dicen que la inmutabilidad mejora la "seguridad", pero no explican cómo. Todos enlazan con un artículo vago de dzone que tampoco ayuda. Las respuestas / el enlace no explican cómo se puede cambiar una cadena mutable cuando se ejecuta el código. Podría explicar por favor ?
MasterJoe2
25

No podemos estar seguros de qué pensaban realmente los diseñadores de Java mientras diseñaban, Stringpero solo podemos concluir estas razones en función de las ventajas que obtenemos de la inmutabilidad de cadenas, algunas de las cuales son

1. Existencia del conjunto constante de cadenas

Como se discutió en Por qué String se almacena en String Constant Pool , cada aplicación crea demasiados objetos de cadena y para evitar que JVM cree primero muchos objetos de cadena y luego los recolecte basura. JVM almacena todos los objetos de cadena en un área de memoria separada llamada Grupo constante de cadenas y reutiliza los objetos de ese grupo en caché.

Siempre que creamos un literal de cadena, JVM ve primero si ese literal ya está presente en un grupo constante o no, y si está allí, la nueva referencia comenzará a apuntar al mismo objeto en SCP.

String a = "Naresh";
String b = "Naresh";
String c = "Naresh";

En el ejemplo anterior, con objeto de cadena de valor Nareshserá creado en el SCP sólo una vez y toda referencia a, b, capuntará al mismo objeto, pero lo que si tratamos de hacer un cambio en apor ejemplo a.replace("a", "").

Idealmente, adebería tener valor , Nreshpero debería permanecer sin cambios porque, como usuario final, solo estamos haciendo el cambio . Y sabemos , , todos apuntan al mismo objeto por lo que si hacemos un cambio enbcaabca , otros también debe reflejar el cambio.

Pero la inmutabilidad de cadena nos salva de este escenario y, debido a la inmutabilidad del objeto de cadena, el objeto de cadena Nareshnunca cambiará. Entonces, cuando hacemos algún cambio en alugar de un cambio en el objeto de cadena, NareshJVM crea un nuevo objeto al que se lo asigna ay luego realiza un cambio en ese objeto.

Entonces, el conjunto de cadenas solo es posible debido a la inmutabilidad de String y si String no hubiera sido inmutable, entonces el almacenamiento en caché de los objetos de cadena y su reutilización no tendrían la posibilidad de que ninguna variable hubiera cambiado el valor y corrompido a otros.

Y es por eso que JVM lo maneja de manera muy especial y se le ha dado un área de memoria especial.

2. Seguridad del hilo

Un objeto se llama seguro para subprocesos cuando varios subprocesos están operando en él, pero ninguno de ellos puede corromper su estado y el objeto mantiene el mismo estado para cada subproceso en cualquier momento.

Como nosotros, un objeto inmutable no puede ser modificado por nadie después de su creación, lo que hace que cada objeto inmutable sea seguro para subprocesos de forma predeterminada. No necesitamos aplicarle ninguna medida de seguridad de subprocesos, como crear métodos sincronizados.

Entonces, debido a su naturaleza inmutable, el objeto de cadena puede ser compartido por múltiples hilos e incluso si está siendo manipulado por muchos hilos, no cambiará su valor.

3. Seguridad

En cada aplicación, necesitamos pasar varios secretos, por ejemplo, nombre de usuario \ contraseñas del usuario, URL de conexión y, en general, toda esta información se pasa como el objeto de cadena.

Ahora suponga que si String no hubiera sido inmutable por naturaleza, causaría una seria amenaza a la seguridad de la aplicación porque estos valores pueden modificarse y si se permite, estos podrían modificarse debido a un código escrito incorrectamente o cualquier otra persona que tener acceso a nuestras referencias variables.

4. Carga de clase

Como se discutió en Crear objetos a través de Reflection en Java con Example , podemos usarClass.forName("class_name") método para cargar una clase en la memoria que nuevamente llama a otros métodos para hacerlo. E incluso JVM usa estos métodos para cargar clases.

Pero si ve claramente que todos estos métodos aceptan el nombre de la clase como un objeto de cadena, por lo que las cadenas se usan en la carga de clases de Java y la inmutabilidad proporciona seguridad por la que se carga la clase correcta ClassLoader.

Supongamos que String no hubiera sido inmutable y estamos tratando de cargar los java.lang.Objectque se han cambiado org.theft.OurObjecten el medio y ahora todos nuestros objetos tienen un comportamiento que alguien puede usar para cosas no deseadas.

5. Almacenamiento en caché de HashCode

Si vamos a realizar operaciones relacionadas con el hash en cualquier objeto, debemos anular el hashCode()método e intentar generar un código hash preciso utilizando el estado del objeto. Si se cambia el estado de un objeto, lo que significa que su código hash también debería cambiar.

Debido a que String es inmutable, el valor que tiene un objeto de cadena nunca cambiará, lo que significa que su código hash tampoco cambiará, lo que le da a la clase String la oportunidad de almacenar en caché su código hash durante la creación del objeto.

Sí, el objeto String almacena en caché su código hash en el momento de la creación del objeto, lo que lo convierte en el gran candidato para operaciones relacionadas con el hash porque el código hash no necesita calcularse nuevamente, lo que nos ahorra algo de tiempo. Es por eso que String se usa principalmente como HashMapteclas.

Lea más sobre por qué String es inmutable y final en Java .

Naresh Joshi
fuente
1
Respecto a la seguridad: ¿cómo se puede cambiar el valor de la cadena mutable en la memoria? ¿Cómo puede otra persona tener acceso a nuestras referencias variables?
MasterJoe2
No se trata de cómo se puede acceder a las referencias, ¿qué sucede si alguien tiene acceso a ellas? como se mencionó "si String no hubiera sido inmutable por naturaleza, entonces causaría una seria amenaza a la seguridad de la aplicación porque estos valores se pueden cambiar y si se permite, estos podrían cambiar debido a un código escrito incorrectamente o cualquier otra persona que tienen acceso a nuestras referencias variables ".
Naresh Joshi
El cómo importa aquí. Es posible obtener acceso a las referencias o no. Si es posible, ¿puedes nombrar 1-2 técnicas *** (es decir, cómo) que se pueden usar para hacerlo? Si no es posible, entonces el punto sobre seguridad no es aplicable. *** Ejemplo: nombre una técnica para atacar la base de datos de una aplicación web -> Inyección SQL. ¿Conoces alguna técnica como esta para atacar las referencias?
MasterJoe2
Como se mencionó, "Puede suceder debido a un código escrito incorrectamente o cualquier cambio realizado por otra persona que tenga acceso a nuestras referencias variables". por ejemplo, suponga que String es mutable y está escribiendo algún método que usa una cadena, un secreto de cadena y nuevamente esa cadena se pasa a varios métodos intermedios y uno de esos métodos no lo escribe usted y ese método realizó algunos cambios en ese cadena ahora después de llamar a todos estos métodos, el control devolvió su método y está utilizando esa cadena nuevamente, pero se ha cambiado.
Naresh Joshi
2
Revele cualquier afiliación y no use el sitio como una forma de promocionar su sitio a través de la publicación. Vea ¿Cómo escribo una buena respuesta? .
Yvette
21

La razón más importante según este artículo en DZone:

Conjunto de cadenas constantes ... Si la cadena es mutable, cambiar la cadena con una referencia conducirá al valor incorrecto para las otras referencias.

Seguridad

La cadena se usa ampliamente como parámetro para muchas clases de Java, por ejemplo, conexión de red, abrir archivos, etc. ...

Espero que te ayude.

JDGuide
fuente
@JasonC Yo sólo quiero saber si mi respuesta es incorrecta o not.I ya había asistido a la entrevista ya la espera de la respuesta result.If les dijo que es correcto entonces se seleccionarán
oscilante
1
Según mi conocimiento, su respuesta es correcta, pero inmutable significa que la referencia nunca cambiará la ubicación de señalización. Todo lo mejor para su entrevista.
JDGuide
1
Si acepta su punto # 1, todos los objetos deben ser inmutables.
nicomp
Hola JDeveloper, edité tu respuesta para dar la atribución adecuada a la fuente de tu respuesta. Recuerde usar siempre comillas en bloque para copias literales de contenido. ¡Gracias!
NickL
El artículo de DZone contiene errores importantes sobre el funcionamiento del conjunto de Strign. Es solo para constantes. Ergo, la justificación declarada no es válida.
Marqués de Lorne
4

Leí esta publicación Por qué String es inmutable o final en Java y supongo que lo siguiente puede ser la razón más importante:

La cadena es inmutable en Java porque los objetos de cadena se almacenan en caché en el grupo de cadenas . Dado que los literales de cadena en caché se comparten entre varios clientes, siempre existe el riesgo de que la acción de un cliente afecte a todos los demás clientes.

aunque
fuente
1

Tienes razón. Stringen java usa el concepto de String Poolliteral. Cuando se crea una cadena y si la cadena ya existe en el grupo, se devolverá la referencia de la cadena existente, en lugar de crear un nuevo objeto y devolver su referencia. Si una cadena no es inmutable, cambiar la cadena con una referencia conducir al valor incorrecto para las otras referencias.

Agregaría una cosa más, ya que Stringes inmutable, es seguro para subprocesos múltiples y una sola instancia de String se puede compartir entre diferentes subprocesos. Esto evita el uso de la sincronización para la seguridad del subproceso, las cadenas están implícitamente thread safe.

Akshay
fuente
0

La clase de cadena FINALsignifica que no puede crear ninguna clase para heredarla y cambiar la estructura básica y hacer que Sting sea mutable.

Otra cosa, la variable de instancia y los métodos de la clase String que se proporcionan son tales que no puede cambiar el Stringobjeto una vez creado.

La razón por la que ha agregado no hace que la cadena sea inmutable en absoluto. Todo esto dice cómo se almacena la cadena en el montón. También el conjunto de cadenas hace la gran diferencia en el rendimiento

Golpear
fuente
11
Si la clase se declara como final, significa que la clase no se puede heredar, pero no significa que los campos de instancias de la clase no se puedan cambiar, por lo que la clase es inmutable.
Dmitry Bychenko
@ Zeehan: Las clases de ejemplo que das son todas inmutables.
Siyuan Ren
0

La cadena se da como inmutable por los micro sistemas de Sun, porque la cadena se puede usar para almacenar como clave en la colección de mapas. StringBuffer es mutable. Esa es la razón, no se puede usar como clave en el objeto de mapa

chaithanya krishna gogineni
fuente
0

La razón más importante de que una cadena se haga inmutable en Java es la consideración de seguridad . El siguiente sería el almacenamiento en caché .

Creo que otras razones dadas aquí, como la eficiencia, la concurrencia, el diseño y el conjunto de cadenas se derivan del hecho de que String in inmutable. Por ej. String Pool podría crearse porque String era inmutable y no al revés.

Verifique la transcripción de la entrevista de Gosling aquí

Desde un punto de vista estratégico, tienden a estar más libres de problemas. Y generalmente hay cosas que puede hacer con inmutables que no puede hacer con cosas mutables, como almacenar en caché el resultado. Si pasa una cadena a un método de apertura de archivo, o si pasa una cadena a un constructor para una etiqueta en una interfaz de usuario, en algunas API (como en muchas de las API de Windows) pasa una matriz de caracteres. El receptor de ese objeto realmente tiene que copiarlo, porque no saben nada sobre la vida útil del almacenamiento. Y no saben qué le está sucediendo al objeto, si se está cambiando bajo sus pies.

Terminas siendo casi forzado a replicar el objeto porque no sabes si serás el dueño o no. Y una de las cosas buenas de los objetos inmutables es que la respuesta es: "Sí, por supuesto que sí". Porque la cuestión de la propiedad, quién tiene el derecho de cambiarla, no existe.

Una de las cosas que obligó a Strings a ser inmutable fue la seguridad. Tienes un método para abrir archivos. Le pasas una cadena. Y luego está haciendo todo tipo de verificaciones de autenticación antes de realizar la llamada del sistema operativo. Si logras hacer algo que mute efectivamente el String, después de la verificación de seguridad y antes de la llamada del sistema operativo, entonces estás listo. Pero los Strings son inmutables, por lo que ese tipo de ataque no funciona. Ese ejemplo preciso es lo que realmente exigió que las cadenas sean inmutables

Sameer Sinha
fuente
0

Además de las excelentes respuestas, quería agregar algunos puntos. Al igual que Strings, Array contiene una referencia al inicio de la matriz, por lo que si crea dos matrices arr1e arr2hizo algo así arr2 = arr1, la referencia será la arr2misma, arr1por lo que cambiar el valor en una de ellas dará como resultado el cambio de la otra, por ejemplo

public class Main {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4};
        int[] b = a;
        a[0] = 8;
        b[1] = 7;
        System.out.println("A: " + a[0] + ", B: " + b[0]);
        System.out.println("A: " + a[1] + ", B: " + b[1]);
        //outputs
        //A: 8, B: 8
        //A: 7, B: 7
    }
}

No solo eso causaría errores en el código, sino que también puede (y será) explotado por un usuario malintencionado. Supongamos que tiene un sistema que cambia la contraseña de administrador. El usuario tiene que ingresar primero el newPasswordy luego el oldPasswordsi el oldPasswordmismo que adminPassel programa cambia la contraseña adminPass = newPassword. supongamos que la nueva contraseña tiene la misma referencia que la contraseña de administrador, por lo que un mal programador puede crear una tempvariable para mantener la contraseña de administrador antes de que los usuarios ingresen datos si oldPasswordes igual atemp si cambia la contraseña.adminPass = temp. Alguien que sepa que podría ingresar fácilmente la nueva contraseña y nunca ingresar la contraseña anterior y abracadabra tiene acceso de administrador. Otra cosa que no entendí cuando aprendí sobre Strings es por qué JVM no crea una nueva cadena para cada objeto y tiene un lugar único en la memoria para ello y puede hacerlo usando new String("str");la razón por la que no querría usar siempre newes porque no es eficiente en memoria y es más lento en la mayoría de los casos leer más .

Qeaxe
fuente
0

Si HELLOes la cadena de entonces no se puede cambiar HELLOa HILLO. Esta propiedad se llama propiedad de inmutabilidad.

Puede tener una variable de cadena de puntero múltiple para apuntar HOLA cadena.

Pero si HOLA es char Array, entonces puedes cambiar HOLA a HILLO. P.ej,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

Responder:

Los lenguajes de programación tienen variables de datos inmutables para que puedan usarse como claves en clave, par de valores. Las variables de cadena se usan como claves / índices, por lo que son inmutables .

Uddhav Gautam
fuente
-1

Desde el Securitypunto de vista podemos usar este ejemplo práctico:

DBCursor makeConnection(String IP,String PORT,String USER,String PASS,String TABLE) {

    // if strings were mutable IP,PORT,USER,PASS can be changed by validate function
    Boolean validated = validate(IP,PORT,USER,PASS);

    // here we are not sure if IP, PORT, USER, PASS changed or not ??
    if (validated) {
         DBConnection conn = doConnection(IP,PORT,USER,PASS);
    }

    // rest of the code goes here ....
}
darxtrix
fuente