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


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

9 69

9 ответов:

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

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

Как сделать объект неизменяемым?

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

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

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

один из способов обойти эту проблему-возвращать копию массива или коллекции при вызове из метода GET:

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

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

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

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

в дополнение к уже данным ответам я бы рекомендовал прочитать о неизменности в эффективной Java, 2nd Ed. как есть некоторые детали, которые легко пропустить (например, защитные копии). Кроме того, эффективная Java 2-е изд. это должен прочитать каждый Java-разработчик.

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

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

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

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

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

public final class Immutable
{
    private final String name;

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

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

    // No setter;
}

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

Q1) что такое неизменяемый класс и объект?

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

Q2) как создать неизменяемый класс?

Ans) для создания неизменяемого класса необходимо выполнить следующие действия:

  • создать окончательную класс.

  • установите значения свойств, используя только конструктор.

  • сделать свойства класса окончательными и частными

  • не предоставляйте никаких установщиков для этих свойств.

  • Если поля экземпляра содержат ссылки на изменяемые объекты, не разрешить изменение этих объектов:

    • не предоставлять методы, которые изменяют изменяемые объекты.

    • Не делитесь ссылками на изменяемые объекты. Никогда не храните ссылки к внешним, изменяемым объектам, передаваемым конструктору; при необходимости, создание копий и хранение ссылок на копии. Аналогично, создайте копии ваших внутренних изменяемых объектов, когда это необходимо, чтобы избежать возврат оригиналов в ваших методах.

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

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

  • все переменные должны быть частная.
  • нет мутатор методы (сеттеры) предоставляются.
  • избежать переопределения метода путем создания класса финал (сильная неизменность) или методы окончательные (недельная неизменность).
  • клонировать глубоко, если он содержит не примитивные или изменяемые классы.

/**
* 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-immutable-classes-short-note

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

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

  • кэширование цели
  • Параллельная Среда (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;
}
}

другой способ сделать неизменяемый объект-это использовать 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)
  }
}

как неродной носитель английского языка, мне не нравится общая интерпретация "неизменяемого класса", являющегося" сконструированными объектами класса неизменяемыми"; скорее, я сам склоняюсь к интерпретации этого как"сам объект класса неизменен".

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