¿Por qué las cadenas son inmutables en algunos idiomas?

9

String es una clase inmutable en Java. Una clase inmutable es simplemente una clase cuyas instancias no pueden modificarse. ¿Por qué el lenguaje de programación Java elige hacer que los objetos de clase String sean inmutables?

Tupledev
fuente
2
@PJTraill No parece inevitable en absoluto. Los literales de cadena en otros lenguajes no son inmutables, por ejemplo, en C, y los objetos de otras clases en Java no son inmutables.
David Richerby
2
Esta es una pregunta sobre el diseño del lenguaje de programación. Parece sobre el tema, para mí.
David Richerby
2
@DavidRicherby, los literales de cadena son inmutables en C (en términos de C90: si el programa intenta modificar un literal de cadena de cualquier forma, el comportamiento no está definido. Algunas versiones anteriores lo aceptaron debido a la falta de const en el lenguaje, y lo hizo a veces lo que el programador esperaba, pero no creo que haya sido admitido) Creo que todos han aprendido del error en FORTRAN temprano que permitió cambiar los literales. Tener literales que crean un nuevo objeto mutable cuyo valor inicial es el mismo que el literal, por otro lado, si no algo incorrecto.
Programador del
1
@AProgrammer Plenty se ha escrito sobre por qué Java se diseñó de la manera en que estaba: me sorprendería si no hay nada autoritario sobre las decisiones de diseño en torno a la clase String. Pero, incluso si los diseñadores de idiomas nunca dijeron por qué String es inmutable, eso no hace que la pregunta esté fuera de tema o incluso sea mala: solo significa que, desafortunadamente, la única respuesta correcta es "No sabemos".
David Richerby
1
@DavidRicherby Sin embargo, sería mejor si la pregunta fuera independiente del idioma. Este puede ser respondido citando una declaración de un desarrollador de Java; Queremos respuestas que expliquen los conceptos.
Raphael

Respuestas:

9

Este problema está fuertemente relacionado con la noción de lo que significa ser una instancia de una clase. En términos estrictos orientados a objetos, una clase tiene un invariante asociado: un predicado que siempre es válido al salir de un método (público) de la clase. Tal noción es fundamental para garantizar que la herencia esté bien definida, por ejemplo (es parte del Principio de sustitución de Liskov ).

Uno de los problemas más perniciosos con Java es que es difícil evitar que el código del cliente rompa invariantes de clase.

Por ejemplo, considere la siguiente clase 'ZipCode':

class ZipCode {
    private String zipCode;

    public ZipCode(String value){
        if(!isValidZipCode(value))
            throw new IllegalArgumentException();
        zipCode = value;
        assert(invariant());
    }

    public String get() { return zipCode; }

    public boolean invariant() {
        return isValidZipCode( zipCode );
    }
}

Si String no fuera inmutable, un usuario de ZipCode podría llamar a 'get' y cambiar los caracteres en cualquier momento posterior, rompiendo así la invariante y destruyendo la integridad conceptual que ofrece la encapsulación del concepto ZipCode.

Dado que este tipo de integridad es esencial para garantizar que los sistemas grandes sean válidos, esta respuesta a su pregunta realmente exige la más amplia de:

"¿Por qué Java no admite un análogo de C ++ const, o al menos ofrece versiones inmutables de más de sus clases de biblioteca?"

NietzscheanAI
fuente
7

Cosas como cadenas y fechas son valores naturales. En términos de C ++, esperamos que tengan un constructor de copia, un operador de asignación y un operador de igualdad, pero nunca esperamos tomar su dirección. Por lo tanto, no esperamos que se asignen individualmente en el montón. Los métodos virtuales no tienen sentido.

Los objetos de dominio son referencias naturales. Los C ++ no tienen constructor de copia, operador de asignación u operador de igualdad (son iguales solo si son idénticos). Podemos tomar su dirección y esperamos que se les asigne un montón. Los métodos son generalmente virtuales.

Java no tiene clases de valor, solo clases de referencia. Los valores están falsificados con objetos inmutables. Esto es cierto para las cadenas, pero desafortunadamente no para las fechas. La mutabilidad de las fechas de Java ha causado problemas frecuentes y ahora está en desuso. Los valores mutables no se pueden usar como base para un hash, por ejemplo.

Miniatura
fuente
Bueno, los valores mutables se pueden usar para el hash, ¡pero es mejor no mutarlos después si se basó en el código hash!
gnasher729
6

Java fue diseñado para permitir la ejecución de subsecciones del código de un programa en entornos con restricciones de seguridad. La forma en que se implementó este requisito fue estableciendo un "SecurityManager" en un subproceso que tiene acceso a los parámetros de ciertas operaciones críticas (por ejemplo, abrir un archivo) y se le preguntó si la operación debería permitirse o no. Si las cadenas de Java fueran mutables, un programa podría eludir tales restricciones creando dos hilos, uno que realizara una operación de archivo abierto que se permitiría mientras que el otro modificaba la cadena en la que almacenaba el nombre de archivo en uno que no se permitiría. Existe entonces la posibilidad de que el administrador de seguridad lea la cadena original, acepte la operación, que se pasaría al código de apertura del archivo que luego precedería a abrir el segundo archivo (no permitido).

  • cuerdas inmutables
  • realizar copias defensivas de cualquier cadena crítica de seguridad antes de verificar su aceptabilidad.

La última posibilidad haría que todas estas operaciones se ejecuten más lentamente y sería más probable que la implementación contenga errores, por lo que el uso de cadenas inmutables fue la decisión más sensata.

En términos más generales, los objetos inmutables son útiles porque permiten compartir sin necesidad de hacer copias defensivas (lo que puede ser necesario incluso en un código no crítico para la seguridad para evitar errores cuando cambian los datos de origen), por lo que incluso sin este requisito la decisión aún sería Una razonable.

Jules
fuente
1
Me alegra que alguien haya señalado esto, porque James Gosling fue completamente claro acerca de esta decisión de diseño. Java fue diseñado para que pueda ejecutar código no confiable enviado a través de una red (por ejemplo, en un navegador web o decodificador digital). La razón principal para hacer que las cadenas sean inmutables fue facilitar a los proveedores o administradores del sitio (¡y a los implementadores de la biblioteca estándar de Java!) Implementar sus propias políticas de seguridad personalizadas. Las cadenas inmutables efectivamente cierran un vector de ataque potencial por diseño.
Seudónimo