Java Language
Clase inmutable
Buscar..
Introducción
Los objetos inmutables son instancias cuyo estado no cambia después de que se haya inicializado. Por ejemplo, String es una clase inmutable y, una vez instanciada, su valor nunca cambia.
Observaciones
Algunas clases inmutables en Java:
- java.lang.String
- Las clases de envoltorio para los tipos primitivos: java.lang.Integer, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Boolean, java.lang.Long, java.lang.Double, java.lang.Float
- La mayoría de las clases de enumeración son inmutables, pero esto, de hecho, depende del caso concreto.
- java.math.BigInteger y java.math.BigDecimal (al menos objetos de esas clases en sí)
- java.io.File. Tenga en cuenta que esto representa un objeto externo a la VM (un archivo en el sistema local), que puede o no existir, y tiene algunos métodos para modificar y consultar el estado de este objeto externo. Pero el objeto File en sí permanece inmutable.
Reglas para definir clases inmutables.
Las siguientes reglas definen una estrategia simple para crear objetos inmutables.
- No proporcione métodos de "establecimiento": métodos que modifican campos u objetos a los que se hace referencia por campos.
- Hacer todos los campos finales y privados.
- No permitir que las subclases anulen los métodos. La forma más sencilla de hacer esto es declarar la clase como final. 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 se cambien esos objetos:
- No proporcione métodos que modifiquen los objetos mutables.
- No comparta referencias a los objetos mutables. Nunca almacene referencias a objetos mutables externos pasados al constructor; Si es necesario, cree copias y almacene referencias a las copias. Del mismo modo, cree copias de sus objetos mutables internos cuando sea necesario para evitar devolver los originales en sus métodos.
Ejemplo sin referencias mutables.
public final class Color {
final private int red;
final private int green;
final private int blue;
private void check(int red, int green, int blue) {
if (red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) {
throw new IllegalArgumentException();
}
}
public Color(int red, int green, int blue) {
check(red, green, blue);
this.red = red;
this.green = green;
this.blue = blue;
}
public Color invert() {
return new Color(255 - red, 255 - green, 255 - blue);
}
}
Ejemplo con referencias mutables
En este caso, la clase Point es mutable y algunos usuarios pueden modificar el estado del objeto de esta clase.
class Point {
private int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
//...
public final class ImmutableCircle {
private final Point center;
private final double radius;
public ImmutableCircle(Point center, double radius) {
// we create new object here because it shouldn't be changed
this.center = new Point(center.getX(), center.getY());
this.radius = radius;
}
¿Cuál es la ventaja de la inmutabilidad?
La ventaja de la inmutabilidad viene con la concurrencia. Es difícil mantener la corrección en objetos mutables, ya que varios subprocesos podrían estar intentando cambiar el estado del mismo objeto, lo que lleva a que algunos subprocesos vean un estado diferente del mismo objeto, dependiendo de la sincronización de las lecturas y escrituras a dicho objeto.
Al tener un objeto inmutable, uno puede asegurarse de que todos los subprocesos que miran el objeto verán el mismo estado, ya que el estado de un objeto inmutable no cambiará.