¿Cómo crear una clase inmutable en Java?

La clase inmutable en Java significa que una vez que se crea un objeto, no podemos cambiar su contenido. En Java, todas las clases contenedoras (como Integer, Boolean, Byte, Short) y la clase String son inmutables. También podemos crear nuestra propia clase inmutable. Antes de continuar, revise las características de inmutabilidad para tener una buena comprensión al implementar lo mismo. Los siguientes son los requisitos: 

  • La clase debe declararse como final para que no se puedan crear clases secundarias.
  • Los miembros de datos de la clase deben declararse privados para que no se permita el acceso directo.
  • Los miembros de datos de la clase deben declararse como finales para que no podamos cambiar su valor después de la creación del objeto.
  • Un constructor parametrizado debe inicializar todos los campos realizando una copia profunda para que los miembros de datos no puedan modificarse con una referencia de objeto.
  • La copia profunda de los objetos debe realizarse en los métodos getter para devolver una copia en lugar de devolver la referencia real del objeto)

Nota: No debería haber setters o, en términos más simples, no debería haber ninguna opción para cambiar el valor de la variable de instancia.

Ejemplo

Java

// Java Program to Create An Immutable Class
 
// Importing required classes
import java.util.HashMap;
import java.util.Map;
 
// Class 1
// An immutable class
final class Student {
 
    // Member attributes of final class
    private final String name;
    private final int regNo;
    private final Map<String, String> metadata;
 
    // Constructor of immutable class
    // Parameterized constructor
    public Student(String name, int regNo,
                   Map<String, String> metadata)
    {
 
        // This keyword refers to current instance itself
        this.name = name;
        this.regNo = regNo;
 
        // Creating Map object with reference to HashMap
        // Declaring object of string type
        Map<String, String> tempMap = new HashMap<>();
 
        // Iterating using for-each loop
        for (Map.Entry<String, String> entry :
             metadata.entrySet()) {
            tempMap.put(entry.getKey(), entry.getValue());
        }
 
        this.metadata = tempMap;
    }
 
    // Method 1
    public String getName() { return name; }
 
    // Method 2
    public int getRegNo() { return regNo; }
   
    // Note that there should not be any setters
 
    // Method 3
    // User -defined type
    // To get meta data
    public Map<String, String> getMetadata()
    {
 
        // Creating Map with HashMap reference
        Map<String, String> tempMap = new HashMap<>();
 
        for (Map.Entry<String, String> entry :
             this.metadata.entrySet()) {
            tempMap.put(entry.getKey(), entry.getValue());
        }
        return tempMap;
    }
}
 
// Class 2
// Main class
class GFG {
 
    // Main driver method
    public static void main(String[] args)
    {
 
        // Creating Map object with reference to HashMap
        Map<String, String> map = new HashMap<>();
 
        // Adding elements to Map object
        // using put() method
        map.put("1", "first");
        map.put("2", "second");
 
        Student s = new Student("ABC", 101, map);
 
        // Calling the above methods 1,2,3 of class1
        // inside main() method in class2 and
        // executing the print statement over them
        System.out.println(s.getName());
        System.out.println(s.getRegNo());
        System.out.println(s.getMetadata());
 
        // Uncommenting below line causes error
        // s.regNo = 102;
 
        map.put("3", "third");
        // Remains unchanged due to deep copy in constructor
        System.out.println(s.getMetadata());
        s.getMetadata().put("4", "fourth");
        // Remains unchanged due to deep copy in getter
        System.out.println(s.getMetadata());
    }
}
Producción

ABC
101
{1=first, 2=second}
{1=first, 2=second}
{1=first, 2=second}

En este ejemplo, hemos creado una clase final llamada Estudiante. Tiene tres miembros de datos finales, un constructor parametrizado y métodos getter. Tenga en cuenta que no hay ningún método setter aquí. Además, tenga en cuenta que no necesitamos realizar una copia profunda o una clonación de miembros de datos de tipos de contenedores, ya que ya son inmutables.
Este artículo es una contribución de Abhishree Shetty . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *