Поиск…


Вступление

Неизменяемыми объектами являются экземпляры, состояние которых не изменяется после его инициализации. Например, String является неизменяемым классом, и после его создания значение никогда не изменяется.

замечания

Некоторые непреложные классы в Java:

  1. java.lang.String
  2. Классы-оболочки для примитивных типов: java.lang.Integer, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Boolean, java.lang.Long, java.lang.Double, java.lang.Float
  3. Большинство классов перечисления неизменяемы, но это фактически зависит от конкретного случая.
  4. java.math.BigInteger и java.math.BigDecimal (по крайней мере, объекты самих этих классов)
  5. java.io.File. Обратите внимание, что это представляет объект, внешний по отношению к виртуальной машине (файл в локальной системе), который может или не может существовать, и имеет некоторые методы, изменяющие и запрашивающие состояние этого внешнего объекта. Но сам объект File остается неизменным.

Правила определения неизменяемых классов

Следующие правила определяют простую стратегию создания неизменяемых объектов.

  1. Не предоставляйте методы «setter» - методы, которые изменяют поля или объекты, на которые ссылаются поля.
  2. Сделайте все поля окончательными и частными.
  3. Не допускайте переопределение подклассов. Самый простой способ сделать это - объявить класс окончательным. Более сложный подход заключается в том, чтобы сделать конструктор частным и построить экземпляры в заводских методах.
  4. Если поля экземпляра включают ссылки на изменяемые объекты, не разрешайте изменять эти объекты:
  5. Не предоставляйте методы, изменяющие изменяемые объекты.
  6. Не используйте ссылки на изменяемые объекты. Никогда не храните ссылки на внешние, изменяемые объекты, переданные конструктору; при необходимости, создавать копии и хранить ссылки на копии. Аналогичным образом создайте копии своих внутренних изменяемых объектов, когда это необходимо, чтобы избежать возврата оригиналов в ваши методы.

Пример без изменяемых ссылок

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);
    }
}

Пример с mutable refs

В этом случае класс Point изменен, и некоторый пользователь может изменить состояние объекта этого класса.

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;
    }

В чем преимущество неизменности?

Преимущество непреложности заключается в параллелизме. Трудно поддерживать правильность в изменяемых объектах, поскольку несколько потоков могут пытаться изменить состояние одного и того же объекта, приводя к тому, что некоторые потоки видят другое состояние одного и того же объекта, в зависимости от времени чтения и записи в упомянутый объект.

Имея неизменный объект, можно гарантировать, что все потоки, которые смотрят на объект, будут видеть одно и то же состояние, так как состояние неизменяемого объекта не изменится.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow