¿Cómo crear objetos inmutables en Java?

¿Cómo crear objetos inmutables en Java?

¿Qué objetos deberían llamarse inmutables?

Si tengo una clase con todos los miembros estáticos ¿es inmutable?

Debajo están los requisitos duros de un objeto inmutable.

  1. Haz la clase final
  2. hacer que todos los miembros sean definitivos, establecerlos explícitamente, en un bloque estático o en el constructor
  3. Haga que todos los miembros sean privados
  4. No hay métodos que modifiquen el estado
  5. Tenga mucho cuidado de limitar el acceso a los miembros mutables (recuerde que el campo puede ser final pero el objeto aún puede ser mutable, es decir, private final Date imStillMutable ). Debes hacer defensive copies en estos casos.

El razonamiento detrás de hacer que la clase sea final es muy sutil y a menudo se pasa por alto. Si no es definitivo, las personas pueden extender libremente su clase, anular public comportamiento public o protected , agregar propiedades modificables y luego proporcionar su subclase como sustituto. Al declarar la clase final , puede asegurarse de que esto no suceda.

Para ver el problema en acción, considere el siguiente ejemplo:

 public class MyApp{ /** * @param args */ public static void main(String[] args){ System.out.println("Hello World!"); OhNoMutable mutable = new OhNoMutable(1, 2); ImSoImmutable immutable = mutable; /* * Ahhhh Prints out 3 just like I always wanted * and I can rely on this super immutable class * never changing. So its thread safe and perfect */ System.out.println(immutable.add()); /* Some sneak programmer changes a mutable field on the subclass */ mutable.field3=4; /* * Ahhh let me just print my immutable * reference again because I can trust it * so much. * */ System.out.println(immutable.add()); /* Why is this buggy piece of crap printing 7 and not 3 It couldn't have changed its IMMUTABLE!!!! */ } } /* This class adheres to all the principles of * good immutable classes. All the members are private final * the add() method doesn't modify any state. This class is * just a thing of beauty. Its only missing one thing * I didn't declare the class final. Let the chaos ensue */ public class ImSoImmutable{ private final int field1; private final int field2; public ImSoImmutable(int field1, int field2){ this.field1 = field1; this.field2 = field2; } public int add(){ return field1+field2; } } /* This class is the problem. The problem is the overridden method add(). Because it uses a mutable member it means that I can't guarantee that all instances of ImSoImmutable are actually immutable. */ public class OhNoMutable extends ImSoImmutable{ public int field3 = 0; public OhNoMutable(int field1, int field2){ super(field1, field2); } public int add(){ return super.add()+field3; } } 

En la práctica, es muy común encontrar el problema anterior en entornos de Inyección de Dependencia. No estás instanciando explícitamente cosas y la referencia de superclase que se te da puede ser en realidad una subclase.

La conclusión es que para garantizar la inmutabilidad tienes que marcar la clase como final . Esto está cubierto en profundidad en Java efectivo de Joshua Bloch y se hace referencia explícita en la especificación para el modelo de memoria de Java .

Las clases no son inmutables, los objetos sí lo son.

Inmutable significa: mi estado visible público no puede cambiar después de la inicialización.

Los campos no tienen que declararse definitivos, aunque puede ser de gran ayuda garantizar la seguridad de los hilos.

Si su clase tiene solo miembros estáticos, entonces los objetos de esta clase son inmutables, porque no puede cambiar el estado de ese objeto (probablemente tampoco pueda crearlo :))

Simplemente no agregue métodos públicos de mutador (setter) a la clase.

Para hacer una clase inmutable en Java, puede tener en cuenta los siguientes puntos:

1. No proporcione métodos setter para modificar los valores de ninguna de las variables de instancia de la clase.

2. Declara la clase como ‘final’ . Esto evitaría que cualquier otra clase lo extendiera y, por lo tanto, evitara cualquier método que pudiera modificar los valores de las variables de instancia.

3. Declare las variables de instancia como privadas y finales .

4. También puede declarar el constructor de la clase como privado y agregar un método de fábrica para crear una instancia de la clase cuando sea necesario.

¡Estos puntos deberían ayudar!

Para crear una clase inmutable, debe seguir los siguientes pasos:

 Declare the class as final so it can't be extended. Make all fields private so that direct access is not allowed. Don't provide setter methods for variables Make all mutable fields final so that it's value can be assigned only once. Initialize all the fields via a constructor performing deep copy. Perform cloning of objects in the getter methods to return a copy rather than returning the actual object reference. 

Desde el sitio Oracle, cómo crear objetos inmutables en Java.

  1. No proporcione métodos “setter”: métodos que modifican campos u objetos a los que se hace referencia por campos.
  2. Haga todos los campos finales y privados.
  3. No permita que las subclases anulen los métodos. La forma más sencilla de hacerlo es declarar la clase como definitiva. Un enfoque más sofisticado es hacer que el constructor sea privado y construir instancias en métodos de fábrica.
  4. Si los campos de la instancia incluyen referencias a objetos mutables, no permita que esos objetos sean cambiados:
    I. No proporcione métodos que modifiquen los objetos mutables.
    II. No comparta referencias a los objetos mutables. Nunca almacene referencias a objetos externos y mutables pasados ​​al constructor; si es necesario, cree copias y almacene referencias a las copias. De forma similar, cree copias de sus objetos mutables internos cuando sea necesario para evitar devolver los originales en sus métodos.
  • No proporcione métodos “setter”: métodos que modifican campos u objetos a los que se hace referencia por campos.
  • Haga todos los campos finales y privados.
  • No permita que las subclases anulen los métodos. La forma más sencilla de hacerlo es declarar la clase como definitiva. Un enfoque más sofisticado es hacer que el constructor sea privado y construir instancias en métodos de fábrica.
  • Si los campos de la instancia incluyen referencias a objetos mutables, no permita que esos objetos sean cambiados:
    • No proporcione métodos que modifiquen los objetos mutables.
    • No comparta referencias a los objetos mutables. Nunca almacene referencias a objetos externos y mutables pasados ​​al constructor; si es necesario, cree copias y almacene referencias a las copias. De forma similar, cree copias de sus objetos mutables internos cuando sea necesario para evitar devolver los originales en sus métodos.

Antes que nada, sabes por qué necesitas crear objetos inmutables y cuáles son las ventajas del objeto inmutable.

Ventajas de un objeto inmutable

Simultaneidad y multiproceso Se trata de un problema automático de sincronización de sincronización, etc.

No es necesario copiar el constructor No es necesario implementar el clon. La clase no se puede sobrescribir Hacer que el campo sea privado y final Forzar llamadas para construir un objeto completamente en un solo paso, en lugar de utilizar un constructor sin argumento

Los objetos inmutables son simplemente objetos cuyo estado significa que los datos del objeto no pueden cambiar después de que se construye el objeto inmutable.

por favor mira el código a continuación.

 public final class ImmutableReminder{ private final Date remindingDate; public ImmutableReminder (Date remindingDate) { if(remindingDate.getTime() < System.currentTimeMillis()){ throw new IllegalArgumentException("Can not set reminder" + " for past time: " + remindingDate); } this.remindingDate = new Date(remindingDate.getTime()); } public Date getRemindingDate() { return (Date) remindingDate.clone(); } } 

Minimiza la mutabilidad

Una clase inmutable es simplemente una clase cuyas instancias no se pueden modificar. Toda la información contenida en cada instancia se proporciona cuando se crea y se corrige durante el tiempo de vida del objeto.

Clases inmutables JDK: String, las clases primitivas en recuadro (clases contenedoras), BigInteger y BigDecimal, etc.

¿Cómo hacer que una clase sea inmutable?

  1. No proporcione ningún método que modifique el estado del objeto (conocido como mutadores).
  2. Asegúrese de que la clase no se pueda extender.
  3. Haz que todos los campos sean finales.
  4. Haga que todos los campos sean privados Esto evita que los clientes obtengan acceso a los objetos mutables a los que se hace referencia en los campos y modifica estos objetos directamente.
  5. Haga copias defensivas. Asegure el acceso exclusivo a cualquier componente mutable.

    public List getList () {return Collections.unmodifiableList (list); < === copia defensiva del campo mutable antes de devolverlo al llamante}

Si su clase tiene campos que hacen referencia a objetos mutables, asegúrese de que los clientes de la clase no puedan obtener referencias a estos objetos. Nunca inicie dicho campo en una referencia de objeto proporcionada por el cliente ni devuelva la referencia del objeto desde un descriptor de acceso.

 import java.util.Date; public final class ImmutableClass { public ImmutableClass(int id, String name, Date doj) { this.id = id; this.name = name; this.doj = doj; } private final int id; private final String name; private final Date doj; public int getId() { return id; } public String getName() { return name; } /** * Date class is mutable so we need a little care here. * We should not return the reference of original instance variable. * Instead a new Date object, with content copied to it, should be returned. * */ public Date getDoj() { return new Date(doj.getTime()); // For mutable fields } } import java.util.Date; public class TestImmutable { public static void main(String[] args) { String name = "raj"; int id = 1; Date doj = new Date(); ImmutableClass class1 = new ImmutableClass(id, name, doj); ImmutableClass class2 = new ImmutableClass(id, name, doj); // every time will get a new reference for same object. Modification in reference will not affect the immutability because it is temporary reference. Date date = class1.getDoj(); date.setTime(date.getTime()+122435); System.out.println(class1.getDoj()==class2.getDoj()); } } 

Para más información, mira mi blog:
http://javaexplorer03.blogspot.in/2015/07/minimize-mutability.html

un objeto se llama inmutable si su estado no se puede cambiar una vez creado. Una de las formas más simples de crear clases inmutables en Java es estableciendo que todos sus campos son finales. Si necesita escribir una clase inmutable que incluya clases variables como “java.util.Date”. Para preservar la inmutabilidad en tales casos, se aconseja devolver una copia del objeto original,

Los objetos inmutables son aquellos cuyo estado no se puede cambiar una vez que se crean, por ejemplo, la clase String es una clase inmutable. Los objetos inmutables no se pueden modificar, por lo que también son seguros para la ejecución concurrente.

Características de las clases inmutables:

  • simple de construir
  • hilo de seguridad automático
  • buen candidato para las teclas de mapa y establecer como su estado interno no cambiaría durante el procesamiento
  • no necesita implementación de clon ya que siempre representan el mismo estado

Claves para escribir una clase inmutable:

  • asegurarse de que la clase no pueda ser anulada
  • hacer que todas las variables miembro sean privadas y finales
  • no le des sus métodos setter
  • la referencia del objeto no se debe filtrar durante la fase de construcción

Deben tenerse en cuenta los siguientes pasos, cuando desee que cualquier clase sea una clase inmutable.

  1. La clase debe marcarse como final
  2. Todos los campos deben ser privados y finales
  3. Reemplace setters con constructor (para asignar un valor a una variable).

Vamos a echar un vistazo a lo que hemos escrito arriba:

 //ImmutableClass package younus.attari; public final class ImmutableExample { private final String name; private final String address; public ImmutableExample(String name,String address){ this.name=name; this.address=address; } public String getName() { return name; } public String getAddress() { return address; } } //MainClass from where an ImmutableClass will be called package younus.attari; public class MainClass { public static void main(String[] args) { ImmutableExample example=new ImmutableExample("Muhammed", "Hyderabad"); System.out.println(example.getName()); } } 

Propiedades comúnmente ignoradas pero importantes en objetos inmutables

Añadiendo a la respuesta proporcionada por @ nsfyn55, los siguientes aspectos también deben tenerse en cuenta para la inmutabilidad del objeto, que son de primordial importancia

Considere las siguientes clases:

 public final class ImmutableClass { private final MutableClass mc; public ImmutableClass(MutableClass mc) { this.mc = mc; } public MutableClass getMutClass() { return this.mc; } } public class MutableClass { private String name; public String getName() { return this.name; } public void setName(String name) { this.name = name; } } public class MutabilityCheck { public static void main(String[] args) { MutableClass mc = new MutableClass(); mc.setName("Foo"); ImmutableClass iMC = new ImmutableClass(mc); System.out.println(iMC.getMutClass().getName()); mc.setName("Bar"); System.out.println(iMC.getMutClass().getName()); } } 

Lo siguiente será el resultado de MutabilityCheck:

  Foo Bar 

Es importante observar que,

  1. Construir objetos mutables en un objeto inmutable (a través del constructor), ya sea ‘copiando’ o ‘cloing’ a variables de instancia de lo inmutable descrito por los siguientes cambios:

     public final class ImmutableClass { private final MutableClass mc; public ImmutableClass(MutableClass mc) { this.mc = new MutableClass(mc); } public MutableClass getMutClass() { return this.mc; } } public class MutableClass { private String name; public MutableClass() { } //copy constructor public MutableClass(MutableClass mc) { this.name = mc.getName(); } public String getName() { return this.name; } public void setName(String name) { this.name = name; } } 

aún no garantiza la inmutabilidad completa ya que lo siguiente sigue siendo válido de la clase MutabilityCheck:

  iMC.getMutClass().setName("Blaa"); 
  1. Sin embargo, ejecutar MutabilityCheck con los cambios realizados en 1. dará como resultado que el resultado sea:

     Foo Foo 
  2. Para lograr la inmutabilidad completa de un objeto, todos sus objetos dependientes también deben ser inmutables