¿Qué se entiende por inmutable?

Esta podría ser la pregunta más tonta jamás formulada, pero creo que es bastante confusa para un novato en Java.

  1. ¿Puede alguien aclarar qué se entiende por inmutable?
  2. ¿Por qué un String es inmutable?
  3. ¿Cuáles son las ventajas/desventajas de los objetos inmutables?
  4. ¿Por qué un objeto mutable como StringBuilder es preferible a String y viceversa?

Un buen ejemplo (en Java) será muy apreciado.

Comentarios sobre la pregunta (5)
Solución

Inmutable significa que una vez que el constructor de un objeto ha completado la ejecución, esa instancia no puede ser alterada.

Esto es útil ya que significa que puede pasar referencias al objeto alrededor, sin preocuparse de que alguien más vaya a cambiar su contenido. Especialmente cuando se trata de concurrencia, no hay problemas de bloqueo con objetos que nunca cambian

por ejemplo.

class Foo
{
     private final String myvar;

     public Foo(final String initialValue)
     {
         this.myvar = initialValue;
     }

     public String getValue()
     {
         return this.myvar;
     }
}

"Foo" no tiene que preocuparse de que la persona que llame a "getValue" pueda cambiar el texto de la cadena.

Si imaginas una clase similar a Foo, pero con un StringBuilder en lugar de un String como miembro, puedes ver que un llamador a getValue() podría alterar el atributo StringBuilder de una instancia Foo.

También ten cuidado con los diferentes tipos de inmutabilidad que puedes encontrar: Eric Lippert escribió un artículo de blog sobre esto. Básicamente puedes tener objetos cuya interfaz es inmutable pero que entre bastidores se mueven en un estado privado (y por lo tanto no pueden ser compartidos de forma segura entre hilos).

Comentarios (13)

Un objeto inmutable es un objeto en el que los campos internos (o al menos, todos los campos internos que afectan a su comportamiento externo) no pueden ser cambiados.

Hay muchas ventajas en las cadenas inmutables:

Rendimiento: Realiza la siguiente operación:

String substring = fullstring.substring(x,y);

El C subyacente para el método de subcadena() es probablemente algo como esto:

// Assume string is stored like this:
struct String { char* characters; unsigned int length; };

// Passing pointers because Java is pass-by-reference
struct String* substring(struct String* in, unsigned int begin, unsigned int end)
{
    struct String* out = malloc(sizeof(struct String));
    out->characters = in->characters + begin;
    out->length = end - begin;
    return out;
}

Tenga en cuenta que ¡no hay que copiar ninguno de los caracteres! Si el objeto String fuera mutable (los caracteres podrían cambiar más tarde) entonces tendría que copiar todos los caracteres, de lo contrario los cambios en los caracteres de la subcadena se verían reflejados en la otra cadena más tarde.

Concurrency: Si la estructura interna de un objeto inmutable es válida, siempre será válida. No hay posibilidad de que diferentes hilos puedan crear un estado inválido dentro de ese objeto. Por lo tanto, los objetos inmutables son Hilos seguros.

**Es mucho más fácil para el recolector de basura tomar decisiones lógicas sobre objetos inmutables.

Sin embargo, también hay desventajas en la inmutabilidad:

Rendimiento: Espera, ¡pensé que dijiste que el rendimiento era una ventaja de la inmutabilidad! Bueno, lo es a veces, pero no siempre. Toma el siguiente código:

foo = foo.substring(0,4) + "a" + foo.substring(5);  // foo is a String
bar.replace(4,5,"a"); // bar is a StringBuilder

Las dos líneas sustituyen el cuarto carácter por la letra "a". No sólo es más legible la segunda parte del código, sino que es más rápido. Mira cómo tendrías que hacer el código subyacente para el foo. Las subcadenas son fáciles, pero ahora porque ya hay un carácter en el espacio cinco y algo más podría estar haciendo referencia a foo, puedes... no sólo cambiarlo; tienes que copiar toda la cadena (por supuesto, parte de esta funcionalidad se abstrae en funciones en el C real subyacente, pero el punto aquí es mostrar el código que se ejecuta todo en un lugar).

struct String* concatenate(struct String* first, struct String* second)
{
    struct String* new = malloc(sizeof(struct String));
    new->length = first->length + second->length;

    new->characters = malloc(new->length);

    int i;

    for(i = 0; i < first->length; i++)
        new->characters[i] = first->characters[i];

    for(; i - first->length < second->length; i++)
        new->characters[i] = second->characters[i - first->length];

    return new;
}

// The code that executes
struct String* astring;
char a = 'a';
astring->characters = &a;
astring->length = 1;
foo = concatenate(concatenate(slice(foo,0,4),astring),slice(foo,5,foo->length));

Nótese que el concatenado se llama dos veces, lo que significa que toda la cuerda tiene que ser enlazada. Compara esto con el código C para la operación "bar":

bar->characters[4] = 'a';

La operación de la cuerda mutable es obviamente mucho más rápida.

En conclusión: En la mayoría de los casos, se quiere una cadena inmutable. Pero si se necesita hacer un montón de adición e inserción en una cuerda, se necesita la mutabilidad para la velocidad. Si quieres la seguridad de concurrencia y los beneficios de recolección de basura con ella la clave es mantener tus objetos mutables locales a un método:

// This will have awful performance if you don't use mutable strings
String join(String[] strings, String separator)
{
    StringBuilder mutable;
    boolean first = true;

    for(int i = 0; i < strings.length; i++)
    {
        if(!first) first = false;
        else mutable.append(separator);

        mutable.append(strings[i]);
    }

    return mutable.toString();
}

Como el objeto "mutable" es una referencia local, no tienes que preocuparte por la seguridad de la concurrencia (sólo un hilo lo toca). Y como no está referenciado en ningún otro sitio, sólo está asignado en la pila, así que se deslocaliza en cuanto termina la llamada a la función (no tienes que preocuparte por la recogida de basura). Y usted obtiene todos los beneficios de rendimiento tanto de la mutabilidad como de la inmutabilidad.

Comentarios (5)

En realidad String no es inmutable si se utiliza la definición de wikipedia sugerida anteriormente.

El estado de String&#39 sí cambia la construcción de la posteta. Echa un vistazo al método hashcode(). String cachea el valor del hashcode en un campo local pero no lo calcula hasta la primera llamada de hashcode(). Esta perezosa evaluación del hashcode coloca a String en una posición interesante como objeto inmutable cuyo estado cambia, pero no se puede observar que haya cambiado sin usar la reflexión.

Así que tal vez la definición de inmutable debería ser un objeto que no se puede observar que haya cambiado.

Si el estado cambia en un objeto inmutable después de su creación pero nadie puede verlo (sin reflexión), ¿sigue siendo el objeto inmutable?

Comentarios (2)

Los objetos inmutables son objetos que no pueden ser cambiados programáticamente. Son especialmente buenos para entornos con múltiples hilos u otros entornos donde más de un proceso es capaz de alterar (mutar) los valores de un objeto.

Sólo para aclarar, sin embargo, StringBuilder es en realidad un objeto mutable, no uno inmutable. Un String de Java normal es inmutable (lo que significa que una vez que se ha creado no se puede cambiar la cadena subyacente sin cambiar el objeto).

Por ejemplo, digamos que tengo una clase llamada ColoredString que tiene un valor String y un color String:

public class ColoredString {

    private String color;
    private String string;

    public ColoredString(String color, String string) {
        this.color  = color;
        this.string = string;
    }

    public String getColor()  { return this.color;  }
    public String getString() { return this.string; }

    public void setColor(String newColor) {
        this.color = newColor;
    }

}

En este ejemplo, se dice que la ColoredString es mutable porque se puede cambiar (mutar) una de sus propiedades clave sin crear una nueva clase de ColoredString. La razón por la que esto puede ser malo es, por ejemplo, digamos que tienes una aplicación GUI que tiene múltiples hilos y que estás usando ColoredStrings para imprimir datos en la ventana. Si tienes una instancia de ColoredString que fue creada como

new ColoredString("Blue", "This is a blue string!");

Entonces se esperaría que la cuerda siempre fuera "Azul". Si otro hilo, sin embargo, se apoderara de esta instancia y llamara

blueString.setColor("Red");

De repente, y probablemente de forma inesperada, ahora tienes un "Red" cuando querías un "Azul" una. Debido a esto, los objetos inmutables son casi siempre preferidos cuando se pasan instancias de objetos alrededor. Cuando se tiene un caso en el que los objetos mutables son realmente necesarios, entonces típicamente se protegería el objeto pasando sólo copias de su campo de control específico.

Para recapitular, en Java, java.lang.String es un objeto inmutable (no se puede cambiar una vez que se ha creado) y java.lang.StringBuilder es un objeto mutable porque se puede cambiar sin crear una nueva instancia.

Comentarios (4)
  1. En aplicaciones grandes es común que los literales de cuerda ocupen grandes cantidades de memoria. Así que para manejar eficientemente la memoria, la JVM asigna un área llamada "String constante pool".([Nótese que en la memoria incluso un String no referenciado lleva un char[}, un int para su longitud, y otro para su hashCode. Para un número, por el contrario, se requiere un máximo de ocho bytes inmediatos][1])
  2. Cuando el complier se encuentra con un literal de la cuerda, comprueba la piscina para ver si hay un literal idéntico ya presente. Y si se encuentra uno, la referencia al nuevo literal se dirige al String existente, y no al nuevo 'objeto literal del String' (el String existente simplemente obtiene una referencia adicional).

  3. Por lo tanto : La mutabilidad de la cadena ahorra memoria...

  4. Pero cuando cualquiera de las variables cambia de valor, en realidad - es sólo su referencia que's cambió, no el valor en la memoria(por lo tanto no afectará a las otras variables que la referencian) como se ve a continuación...


Cuerda s1 = "Vieja cuerda";

//s1 variable, refers to string in memory
        reference                 |     MEMORY       |
        variables                 |                  |

           [s1]   --------------->|   "Old String"   |

La cadena s2 = s1;

//s2 refers to same string as s1
                                  |                  |
           [s1]   --------------->|   "Old String"   |
           [s2]   ------------------------^

s1 = "Nueva Cuerda";

//s1 deletes reference to old string and points to the newly created one
           [s1]   -----|--------->|   "New String"   |
                       |          |                  |
                       |~~~~~~~~~X|   "Old String"   |
           [s2]   ------------------------^

...y la de los demás; La cadena original 'en memoria' no cambió, pero la ...y la de los demás; la variable de referencia fue cambiada para que se refiera a la nueva cadena. ...que se refiere a la nueva cadena; Y si no tuviéramos s2, "Vieja Cuerda"; todavía estaría en la memoria pero ...y la de los demás; no podremos acceder a ella...

[1]: https://stackoverflow.com/questions/20394116/java-why-is-constant-pool-maintained-only-for-string-values

Comentarios (0)

"inmutable" significa que no se puede cambiar el valor. Si tienes una instancia de la clase String, cualquier método que llames que parezca modificar el valor, en realidad creará otro String.


String foo = "Hello";
foo.substring(3);
Comentarios (0)

java.time

Puede que sea un poco tarde, pero para entender qué es un objeto inmutable, considere el siguiente ejemplo de la nueva API de fecha y hora de Java 8 ([java.time][1]). Como probablemente sepas, todos los objetos de fecha de Java 8 son inmutables, así que en el siguiente ejemplo

LocalDate date = LocalDate.of(2014, 3, 18); 
date.plusYears(2);
System.out.println(date);

Salida:

2014-03-18

Esto imprime el mismo año que la fecha inicial porque el plusYears(2) devuelve un nuevo objeto por lo que la antigua fecha sigue siendo la misma porque es un objeto inmutable. Una vez creado, no se puede seguir modificándolo y la variable de la fecha sigue apuntando a él.

Así que, ese código de ejemplo debe capturar y usar el nuevo objeto instanciado y devuelto por esa llamada a plusYears.

LocalDate date = LocalDate.of(2014, 3, 18); 
LocalDate dateAfterTwoYears = date.plusYears(2);

date.toString()… 2014-03-18

...dateAfterTwoYears.toString()... 2016-03-18

[1]: http://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html

Comentarios (0)

Me gusta mucho la explicación de [SCJP Sun Certified Programmer for Java 5 Study Guide][1]. ...de la guía de estudio de Java 5; Para hacer más eficiente la memoria de Java, la JVM reserva un área especial de memoria llamada "String constant pool." Cuando el compilador se encuentra con un literal de String, comprueba el pool para ver si ya existe un String idéntico. Si se encuentra una coincidencia, la referencia al nuevo literal se dirige al String existente, y no se crea ningún nuevo objeto literal de String. El literal de String es el mismo que el del String;

[1]: http://www.amazon.com/Certified-Programmer-310-055-Certification-Guides/dp/0072253606/ref=pd_bbs_sr_2?ie=UTF8&s=books&qid=1226363595&sr=8-2

Comentarios (1)

Los objetos que son inmutables no pueden cambiar su estado después de haber sido creados.

Hay tres razones principales para usar objetos inmutables siempre que se pueda, todo lo cual ayudará a reducir el número de errores que se introducen en el código:

  • Es mucho más fácil razonar sobre cómo funciona tu programa cuando sabes que el estado de un objeto no puede ser cambiado por otro método.
  • Los objetos inmutables se enhebran automáticamente (suponiendo que se publiquen de forma segura) por lo que nunca serán la causa de esos bichos multihilo difíciles de pinchar.
  • Los objetos inmutables siempre tendrán el mismo código Hash, por lo que pueden ser utilizados como las claves de un HashMap (o similar). Si el código hash de un elemento de una tabla hash cambiara, la entrada de la tabla se perdería efectivamente, ya que los intentos de encontrarla en la tabla terminarían buscando en el lugar equivocado. Esta es la razón principal por la que los objetos String son inmutables - se usan frecuentemente como claves HashMap.

También hay algunas otras optimizaciones que se pueden hacer en el código cuando se sabe que el estado de un objeto es inmutable - el almacenamiento en caché del hash calculado, por ejemplo - pero estas son optimizaciones y por lo tanto no son tan interesantes.

Comentarios (0)

Un significado tiene que ver con la forma en que el valor se almacena en la computadora, Para una cadena .Net por ejemplo, significa que la cadena en la memoria no puede ser cambiada, Cuando usted piensa que'está cambiándola, de hecho está creando una nueva cadena en la memoria y apuntando la variable existente (que es sólo un puntero a la colección real de caracteres en otro lugar) a la nueva cadena.

Comentarios (0)
String s1="Hi";
String s2=s1;
s1="Bye";

System.out.println(s2); //Hi  (if String was mutable output would be: Bye)
System.out.println(s1); //Bye

s1="Hi" : un objeto s1 fue creado con "Hi" valor en él.

s2=s1 : un objeto s2 se crea con referencia al objeto s1.

s1="Adiós" : el valor del anterior objeto s1 no cambia porque s1 tiene tipo String y el tipo String es un tipo inmutable, en su lugar el compilador crea un nuevo objeto String con "Bye" y s1 se refiere a él. Aquí cuando imprimimos el valor s2, el resultado será "Hi" no "Bye" porque "s2" se refería al objeto anterior "s1" que tenía "cuajada"; valor.

Comentarios (1)

Inmutable significa simplemente inalterable o no modificable. Una vez que se crea un objeto de cadena, sus datos o estado no pueden ser modificados.

Considere el siguiente ejemplo,

class Testimmutablestring{  
  public static void main(String args[]){  
    String s="Future";  
    s.concat(" World");//concat() method appends the string at the end  
    System.out.println(s);//will print Future because strings are immutable objects  
  }  
 }  

Tengamos una idea considerando el diagrama de abajo,

[![introduzca la descripción de la imagen aquí][1]][1]

En este diagrama, se puede ver el nuevo objeto creado como "Mundo Futuro". Pero no cambia "Futuro".Porque String es inmutable. s`, todavía se refieren a "Futuro". Si necesitas llamar a "Mundo Futuro"..,

String s="Future";  
s=s.concat(" World");  
System.out.println(s);//print Future World

**¿Por qué los objetos de cuerda son inmutables en Java?

...y no se puede hacer nada más; Porque Java utiliza el concepto de cadena literal. Supongamos que hay 5 variables de referencia, todas se refieren a un objeto "Futuro".Si una variable de referencia cambia el valor del objeto, se verá afectada a todas las variables de referencia. Por eso los objetos de cadena son inmutables en Java.

[1]: https://i.stack.imgur.com/8uIrk.png

Comentarios (0)

Inmutable significa que una vez creado el objeto, ninguno de sus miembros cambiará. La cadena es inmutable porque no se puede cambiar su contenido. Por ejemplo:

String s1 = "  abc  ";
String s2 = s1.trim();

En el código anterior, la cadena s1 no cambió, otro objeto (s2) fue creado usando s1.

Comentarios (0)

Una vez instanciada, no puede ser alterada. Considere una clase que una instancia de podría ser utilizado como la clave de un hashtable o similar. Consulta las mejores prácticas de Java.

Comentarios (0)

Objetos inmutables

Un objeto se considera inmutable si su estado no puede cambiar después de ser construido. La máxima confianza en los objetos inmutables es ampliamente aceptada como una sólida estrategia para crear un código simple y fiable.

Los objetos inmutables son particularmente útiles en aplicaciones concurrentes. Dado que no pueden cambiar de estado, no pueden ser corrompidos por la interferencia de un hilo u observados en un estado inconsistente.

Los programadores suelen ser reacios a emplear objetos inmutables, porque se preocupan por el coste de crear un nuevo objeto en lugar de actualizar un objeto ya existente. A menudo se sobreestima el impacto de la creación de un objeto, y puede ser compensado por algunas de las eficiencias asociadas a los objetos inmutables. Estas incluyen la disminución de los gastos generales debido a la recolección de basura, y la eliminación del código necesario para proteger los objetos inmutables de la corrupción.

En las siguientes subsecciones se toma una clase cuyas instancias son mutables y se deriva de ella una clase con instancias inmutables. Al hacerlo, dan reglas generales para este tipo de conversión y demuestran algunas de las ventajas de los objetos inmutables.

[Fuente] [1] [1]: https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html

Comentarios (0)

Un objeto inmutable es aquel que no puede modificarse después de crearlo. Un ejemplo típico son los literales de cadena.

Un lenguaje de programación D, que se hace cada vez más popular, tiene una noción de "inmutabilidad" a través de "invariante" palabra clave. Revise este artículo del Dr. Dobb's sobre ello - [http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29][1] . Explica el problema perfectamente.

[1]: http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29

Comentarios (1)