Неизменный класс? - PullRequest
       11

Неизменный класс?

80 голосов
/ 02 июля 2010

Как можно сделать класс Java неизменяемым, зачем нужна неизменность и есть ли какое-то преимущество в его использовании?

Ответы [ 8 ]

127 голосов
/ 02 июля 2010

Что такое неизменный объект?

Неизменяемый объект - это объект, который не изменит состояние после создания его экземпляра.

Как создать объектimmutable?

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

Следующий класссоздаст неизменный объект:

class ImmutableInt {
  private final int value;

  public ImmutableInt(int i) {
    value = i;
  }

  public int getValue() {
    return value;
  }
}

Как видно из приведенного выше примера, значение ImmutableInt может быть установлено только при создании экземпляра объекта и при наличии только геттера (getValue) состояние объекта не может быть изменено после создания экземпляра.

Однако необходимо позаботиться о том, чтобы все объекты, на которые ссылается объект, также были неизменяемыми, иначе можно было бы изменить состояние объекта.объект.

Например, разрешение получения ссылки на массив или ArrayList через геттер позволит изменить внутреннее состояние путем изменения массива или коллекции:

class NotQuiteImmutableList<T> {
  private final List<T> list;

  public NotQuiteImmutableList(List<T> list) {
    // creates a new ArrayList and keeps a reference to it.
    this.list = new ArrayList(list); 
  }

  public List<T> getList() {
    return list;
  }
}

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

// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));

// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");

В одну сторонуЧтобы обойти эту проблему, нужно вернуть копию массива или коллекции при вызове из получателя:

public List<T> getList() {
  // return a copy of the list so the internal state cannot be altered
  return new ArrayList(list);
}

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

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

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

18 голосов
/ 02 июля 2010

В дополнение к уже приведенным ответам, я бы рекомендовал прочитать об неизменяемости в Effective Java, 2-е изд., Поскольку есть некоторые детали, которые легко пропустить (например, защитные копии). Плюс, эффективная Java 2-е изд. необходимо прочитать каждому разработчику Java.

6 голосов
/ 02 июля 2010

Вы делаете неизменяемый класс следующим образом:

public final class Immutable
{
    private final String name;

    public Immutable(String name) 
    {
        this.name = name;
    }

    public String getName() { return this.name; } 

    // No setter;
}

Ниже приведены требования для того, чтобы сделать класс Java неизменным:

  • Класс должен быть объявлен как final (чтобы дочерние классы не могли быть созданы)
  • Члены в классе должны быть объявлены как final (чтобы мы не могли изменить его значение после создания объекта)
  • Запишите методы Getter для всех переменных в нем, чтобы получить Члены значения
  • Нет методов Setters

Неизменяемые классы полезны, потому что
- Они потокобезопасны.
- Они также выражают что-то глубокое в вашем дизайне: «Не могу изменить это». Когда это применимо, это именно то, что вам нужно.

5 голосов
/ 02 июля 2010

Неизменяемость может быть достигнута в основном двумя способами:

  • с использованием final атрибутов экземпляра, чтобы избежать переназначения
  • с использованием интерфейса класса, который просто не допускает никаких операций, способных изменить то, что находится внутри вашего класса (просто getters и не setters

Преимущества неизменности - это предположения, которые вы можете сделать для этих объектов:

  • вы получаете правило отсутствия побочных эффектов (которое действительно популярно в функциональных языках программирования) и позволяет вам проще использовать объекты в параллельной среде, поскольку вы знаете, что их нельзя изменить атомарным или неатомарным способом когда они используются многими потоками
  • реализации языков могут обрабатывать эти объекты по-другому, помещая их в зоны памяти, которые используются для статических данных, обеспечивая более быстрое и безопасное использование этих объектов (это то, что происходит внутри JVM для строк)
3 голосов
/ 02 августа 2014

Неизменяемые классы не могут переназначать значения после его создания. Конструктор присваивает значения своим закрытым переменным.Пока объект не станет нулевым, значения не могут быть изменены из-за недоступности методов установки.

для того, чтобы быть неизменным, должно удовлетворять следующим условиям,

  • Все переменные должны быть private .
  • Нет mutator предоставляются методы (сеттеры).
  • Избегайте переопределения метода, сделав класс final (Сильная неизменность) или методы final (Неделя неизменяемости).
  • Клонируйте глубоко, если он содержит не примитивные или изменяемые классы.

/**
* Strong immutability - by making class final
*/
public final class TestImmutablity {

// make the variables private
private String Name;

//assign value when the object created
public TestImmutablity(String name) {
this.Name = name;
}

//provide getters to access values
public String getName() {

return this.Name;
}
}

Преимущества: неизменяемые объекты содержат свои инициализированные значения до тех пор, пока не умрут.

Java-неизменяемые классы-короткое примечание

1 голос
/ 14 марта 2017

Неизменяемый класс - это те, чьи объекты нельзя изменить после создания.

Неизменяемые классы полезны для

  • Цель кэширования
  • Одновременныйсреда (ThreadSafe)
  • Хард для наследования
  • Значение не может быть изменено в любой среде

Пример

String Class

Пример кода

public final class Student {
    private final String name;
    private final String rollNumber;

    public Student(String name, String rollNumber) {
        this.name = name;
        this.rollNumber = rollNumber;
    }

    public String getName() {
        return this.name;
    }

    public String getRollNumber() {
        return this.rollNumber;
    }
}
0 голосов
/ 15 октября 2017

Как не говорящий по-английски, мне не нравится общепринятое толкование «неизменяемый класс» как «построенные объекты класса неизменны»;скорее я сам склоняюсь к тому, чтобы интерпретировать это как «сам объект класса неизменный».

При этом «неизменный класс» является своего рода неизменным объектом.Разница заключается в ответе на вопрос, в чем выгода.Насколько мне известно / интерпретация, неизменный класс предотвращает изменение его объектов во время выполнения.

0 голосов
/ 23 июня 2017

Еще один способ создать неизменный объект - использовать Immutables.org библиотека:

Предполагая, что необходимые зависимости были добавлены, создайте реферат класс с абстрактными методами доступа. Вы можете сделать то же самое, аннотирование с помощью интерфейсов или даже аннотаций (@interface):

package info.sample;

import java.util.List;
import java.util.Set;
import org.immutables.value.Value;

@Value.Immutable
public abstract class FoobarValue {
  public abstract int foo();
  public abstract String bar();
  public abstract List<Integer> buz();
  public abstract Set<Long> crux();
}

Теперь можно генерировать, а затем использовать сгенерированный неизменяемый реализация:

package info.sample;

import java.util.List;

public class FoobarValueMain {
  public static void main(String... args) {
    FoobarValue value = ImmutableFoobarValue.builder()
        .foo(2)
        .bar("Bar")
        .addBuz(1, 3, 4)
        .build(); // FoobarValue{foo=2, bar=Bar, buz=[1, 3, 4], crux={}}

    int foo = value.foo(); // 2

    List<Integer> buz = value.buz(); // ImmutableList.of(1, 3, 4)
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...