Рубрики
Без рубрики

Неизменяемые объекты в Java

Узнайте о неизменяемости и о том, как ее можно достичь в объекте Java.

Автор оригинала: baeldung.

1. Обзор

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

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

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

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

Если мы взглянем на класс String , мы увидим, что даже когда его API, по-видимому, предоставляет нам изменяемое поведение с помощью метода replace , исходная Строка не меняется:

String name = "baeldung";
String newName = name.replace("dung", "----");

assertEquals("baeldung", name);
assertEquals("bael----", newName);

Если мы взглянем на класс || String || , мы увидим, что даже когда его API, по-видимому, предоставляет нам изменяемое поведение с помощью метода || replace||, исходная || Строка || не меняется:

3. Последнее ключевое слово в Java

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

В Java переменные по умолчанию изменяемы, что означает, что мы можем изменить значение, которое они содержат|/.

Используя ключевое слово final при объявлении переменной, компилятор Java не позволит нам изменить значение этой переменной. Вместо этого он сообщит об ошибке во время компиляции:

final String name = "baeldung";
name = "bael...";

Обратите внимание, что final запрещает нам изменять только ссылку, содержащуюся в переменной, но не защищает нас от изменения внутреннего состояния объекта, на который она ссылается, с помощью своего общедоступного API:

final List strings = new ArrayList<>();
assertEquals(0, strings.size());
strings.add("baeldung");
assertEquals(0, strings.size());

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

4. Неизменяемость в Java

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

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

Шагом вперед в правильном направлении является использование final при объявлении его атрибутов:

class Money {
    private final double amount;
    private final Currency currency;

    // ...
}

Обратите внимание, что Java гарантирует нам, что значение сумма не изменится, это относится ко всем переменным примитивного типа.

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

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

class Money {
    // ...
    public Money(double amount, Currency currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public Currency getCurrency() {
        return currency;
    }

    public double getAmount() {
        return amount;
    }
}

Как мы уже говорили ранее, для удовлетворения требований неизменяемого API наш класс Money имеет методы только для чтения.

5. Преимущества

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

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

6. Заключение

Неизменяемые объекты не изменяют свое внутреннее состояние во времени, они потокобезопасны и не имеют побочных эффектов. Благодаря этим свойствам неизменяемые объекты также особенно полезны при работе с многопоточными средами.

Вы можете найти примеры, используемые в этой статье на GitHub .