¿Qué se entiende por inmutable?

13 minutos de lectura

¿Que se entiende por inmutable
ashokgelal

Esta podría ser la pregunta más tonta que se haya hecho, pero creo que es bastante confuso para un novato en Java.

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

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

  • Mira, no era una pregunta tan tonta. ¡Me alegra que hayas preguntado!

    – DOK

    10 de noviembre de 2008 a las 23:14

  • Por cierto, no creo que sea la pregunta más tonta 🙂 Creo que es un concepto bastante importante de entender

    –Jason Coco

    10 de noviembre de 2008 a las 23:38

  • Cuando dijiste StringBuilder, ¿no te referías a la clase mutable StringBuffer? String y StringBuffer tienen una función más similar que String y StringBuilder. StringBuffer es efectivamente una cadena mutable.

    – Derek Mahar

    9 dic 2009 a las 15:30

  • ¿Puedo sugerir que agreguemos la etiqueta “principiante” a esta pregunta para que los programadores nuevos en Java puedan encontrarla en una búsqueda de otras preguntas introductorias?

    – Derek Mahar

    9 de diciembre de 2009 a las 15:31

  • stackoverflow.com/questions/2971315/…

    – Rajavel D.

    14 de agosto de 2014 a las 6:02

1646753179 38 ¿Que se entiende por inmutable
douglas leeder

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

Esto es útil ya que significa que puede pasar referencias al objeto, 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.

p.ej

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 llama a getValue() podría cambiar el texto en la cadena.

Si imaginas una clase similar a Foopero con un StringBuilder preferible a String como miembro, puede ver que una persona que llama a getValue() sería capaz de alterar la StringBuilder atributo de un Foo ejemplo.

También tenga cuidado con los diferentes tipos de inmutabilidad que puede encontrar: Eric Lippert escribió un artículo de blog sobre esto. Básicamente, puede tener objetos cuya interfaz es inmutable, pero detrás de escena el estado privado mutable real (y, por lo tanto, no se puede compartir de forma segura entre subprocesos).

  • Creo que debería agregar un constructor de un argumento para asignar valor al menos una vez. El punto del código actual no está claro ya que no hay valor para cambiar realmente :).

    – Georgy Bolyuba

    10 de noviembre de 2008 a las 23:21

  • Debe hacer que el campo sea de solo lectura. Hace completamente explícito que el campo es inmutable. Ahora mismo es inmutable por convención.

    – JaredPar

    11 de noviembre de 2008 a las 0:15

  • El miembro myVar debe ser final para que esto sea realmente inmutable.

    – laz

    9 de enero de 2009 a las 21:16

  • Tiene razón en que myVar no es accesible fuera de Foo. Sin embargo, la presencia de final indica a cualquiera que pueda estar modificando la clase en el futuro que su valor no debe cambiar. Tiendo a preferir ser lo más explícito posible en tales circunstancias.

    – laz

    12 de enero de 2009 a las 21:41

  • ¿Qué tal “Los tipos de referencia no se pueden hacer inmutables simplemente usando la palabra clave final. final solo evita la reasignación”. desde en.wikipedia.org/wiki/Immutable_object

    – Yousha Aleayoub

    17 abr 2015 a las 17:08

¿Que se entiende por inmutable
imaginista

Un objeto inmutable es un objeto donde los campos internos (o al menos, todos los campos internos que afectan su comportamiento externo) no se pueden cambiar.

Las cadenas inmutables tienen muchas ventajas:

Rendimiento: Tome la siguiente operación:

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

La C subyacente para el método substring() 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 ¡Ninguno de los personajes tiene que ser copiado! Si el objeto String fuera mutable (los caracteres podrían cambiar más tarde), tendría que copiar todos los caracteres; de lo contrario, los cambios en los caracteres de la subcadena se reflejarían en la otra cadena más adelante.

Concurrencia: Si la estructura interna de un objeto inmutable es válida, siempre lo será. No hay posibilidad de que diferentes subprocesos puedan crear un estado no válido dentro de ese objeto. Por lo tanto, los objetos inmutables son A salvo de amenazas.

Recolección de basura: 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 habías dicho que el rendimiento era una ventaja de la inmutabilidad! Bueno, a veces lo es, pero no siempre. Tome 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 reemplazan el cuarto carácter con la letra “a”. El segundo fragmento de código no solo es más legible, sino que también es más rápido. Mira cómo tendrías que hacer el código subyacente para foo. Las subcadenas son fáciles, pero ahora que ya hay un carácter en el espacio cinco y algo más podría estar haciendo referencia a foo, no puedes simplemente cambiarlo; tiene que copiar toda la cadena (por supuesto, parte de esta funcionalidad se abstrae en funciones en el C subyacente real, pero el punto aquí es mostrar el código que se ejecuta en un solo 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));

Tenga en cuenta que concatenar se llama dos veces ¡lo que significa que toda la cadena debe pasar por un bucle! Compare esto con el código C para el bar operación:

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

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

En conclusión: En la mayoría de los casos, desea una cadena inmutable. Pero si necesita agregar e insertar mucho en una cadena, necesita la mutabilidad para la velocidad. Si desea la seguridad de concurrencia y los beneficios de recolección de basura, la clave es mantener sus objetos mutables locales en 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();
}

Desde el mutable object es una referencia local, no tiene que preocuparse por la seguridad de la concurrencia (solo un hilo lo toca). Y dado que no se hace referencia a ella en ningún otro lugar, solo se asigna en la pila, por lo que se desasigna tan pronto como finaliza la llamada a la función (no tiene que preocuparse por la recolección de elementos no utilizados). Y obtiene todos los beneficios de rendimiento tanto de la mutabilidad como de la inmutabilidad.

  • ¡Gran lectura! solo una cosa que creo que debería ser si (primero) y no si (! primero)

    – Siddhartha

    27 de octubre de 2012 a las 4:50

  • Lo que es necesario no es que los campos sean inmutables, sino que el estado observable definido del objeto sea inmutable; un objeto que contiene una referencia a otro objeto como medio de encapsular el estado contenido en él solo puede ser inmutable si todos los aspectos encapsulados del estado que expone al mundo exterior son igualmente inmutables. Tenga en cuenta que no es necesario ni suficiente que los campos sean de tipos inmutables. Lo que importa es el estado visible.

    – Super gato

    6 de enero de 2014 a las 21:19

  • Passing pointers because Java is pass-by-reference ¿No es java “pasar por valor”?

    – Cristian Gutú

    2 de octubre de 2014 a las 1:31


  • @CristianGutu, sí, tiene razón, JAVA es “Pasar por valor”, no “Pasar por REFERENCIA”

    –Arsh Kaushal

    16 de mayo de 2017 a las 7:15

  • ¡La referencia se pasa como el valor!

    – devv

    15 de enero de 2019 a las 1:47

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

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

Entonces, 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 que se haya creado pero nadie puede verlo (sin reflejo), ¿el objeto sigue siendo inmutable?

  • Buena idea: un objeto que no se puede observar que haya cambiado, así como tampoco hay forma de cambiarlo desde el exterior. El campo privado para hashCode() es un cambio interno que no es material para el estado visible externamente del objeto.

    – mparaz

    22 de febrero de 2009 a las 15:55

  • en realidad lata se observará que ha cambiado si usa la reflexión. Ver más en Sedgewick’s Las cadenas son mutables si permites la reflexión..

    – miguel

    4 de julio de 2013 a las 8:42

1646753180 988 ¿Que se entiende por inmutable
jason coco

Los objetos inmutables son objetos que no se pueden cambiar mediante programación. Son especialmente buenos para entornos de subprocesos múltiples u otros entornos en los que más de un proceso puede alterar (mutar) los valores de un objeto.

Sin embargo, solo para aclarar, StringBuilder es en realidad un objeto mutable, no inmutable. Una cadena Java regular es inmutable (lo que significa que una vez que se crea, no puede cambiar la cadena subyacente sin cambiar el objeto).

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

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 ColoredString es mutable porque puede cambiar (mutar) una de sus propiedades clave sin crear una nueva clase ColoredString. La razón por la que esto puede ser malo es, por ejemplo, supongamos que tiene una aplicación GUI que tiene varios subprocesos y está utilizando ColoredStrings para imprimir datos en la ventana. Si tiene una instancia de ColoredString que se creó como

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

Entonces esperaría que la cadena fuera siempre “Azul”. Sin embargo, si otro subproceso se apoderara de esta instancia y llamara

blueString.setColor("Red");

De repente, y probablemente inesperadamente, ahora tendrías una cadena “Roja” cuando querías una “Azul”. Debido a esto, casi siempre se prefieren los objetos inmutables cuando se pasan instancias de objetos. Cuando tiene un caso en el que los objetos mutables son realmente necesarios, normalmente protegería el objeto pasando solo copias desde su campo de control específico.

En resumen, en Java, java.lang.String es un objeto inmutable (no no poder cambiarse una vez creado) y java.lang.StringBuilder es un objeto mutable porque se puede cambiar sin crear una nueva instancia.

1646753181 762 ¿Que se entiende por inmutable
Shanaka Jayalath

  1. En aplicaciones grandes, es común que los literales de cadena ocupen grandes bits de memoria. Entonces, para manejar la memoria de manera eficiente, la JVM asigna un área llamada “Conjunto de constantes de cadena”. (Tenga en cuenta que en la memoria, incluso una Cadena sin referencia lleva un carácter[], un int para su longitud y otro para su hashCode. Para un número, en cambio, se requiere un máximo de ocho bytes inmediatos)
  2. Cuando el compilador se encuentra con un literal de cadena, verifica el grupo para ver si ya hay un literal idéntico presente. Y si se encuentra uno, la referencia al nuevo literal se dirige a la Cadena existente, y no se crea ningún ‘objeto literal de Cadena’ nuevo (la Cadena existente simplemente obtiene una referencia adicional).
  3. Por eso : La mutabilidad de cadenas ahorra memoria…
  4. Pero cuando cualquiera de las variables cambia de valor, en realidad, solo cambia su referencia, no el valor en la memoria (por lo tanto, no afectará a las otras variables que hacen referencia a ella) como se ve a continuación….

Cadena s1 = “Cadena antigua”;

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

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

Cadena s2 = s1;

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

s1 = “Nueva cadena”;

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

La cadena original ‘en memoria’ no cambió, pero la variable de referencia se cambió para que se refiera a la nueva cadena. Y si no tuviéramos s2, “Old String” todavía estaría en la memoria pero no podríamos acceder a él…

1646753181 442 ¿Que se entiende por inmutable
ROMANIA_ingeniero

“inmutable” significa que no puede cambiar el valor. Si tiene una instancia de la clase String, cualquier método al que llame que parezca modificar el valor, en realidad creará otra String.

String foo = "Hello";
foo.substring(3);
<-- foo here still has the same value "Hello"

Para conservar los cambios deberías hacer algo como esto foo = foo.sustring(3);

Inmutable vs mutable puede ser divertido cuando trabajas con colecciones. Piense en lo que sucederá si usa un objeto mutable como clave para el mapa y luego cambia el valor (consejo: piense en equals y hashCode).

¿Que se entiende por inmutable
albahaca bourque

java.tiempo

Puede que sea un poco tarde, pero para comprender qué es un objeto inmutable, considere el siguiente ejemplo de la nueva API de fecha y hora de Java 8 (java.tiempo). Como probablemente sepa, todos los objetos de fecha de Java 8 son inmutable entonces en el siguiente ejemplo

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

Producción:

2014-03-18

Esto imprime el mismo año que la fecha inicial porque el plusYears(2) devuelve un objeto nuevo, por lo que la fecha anterior sigue sin cambios porque es un objeto inmutable. Una vez creado, no puede modificarlo más y la variable de fecha todavía apunta a él.

Entonces, ese ejemplo de código debería 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);

fecha.toString()… 2014-03-18

dateAfterTwoYears.toString()… 2016-03-18

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad