Нет, ваш класс Animal не является неизменным, потому что он позволяет создавать подклассы.
Почему бы и нет?
Смотрите этот пример подкласса:
public class ExceptionalAnimal extends Animal {
public ExceptionalAnimal() {
super(null);
}
@Override
public String getName() {
throw new AssertionError("Oops.. where did that come from?");
}
}
Почему это важно?
Неизменяемость обычно используется для гарантии:
- что состояние объекта не меняется после постройки
- объекты являются поточно-ориентированными
- что объекты ведут себя определенным образом
Если класс допускает создание подклассов, нельзя полагаться ни на одну из этих гарантий. Если у вас есть метод, принимающий Animal
в качестве параметра, любой может передать подкласс, который нарушает эти гарантии.
Исправлено: нет открытых или защищенных конструкторов
Один из часто используемых методов - не иметь конструкторов public
или protected
. Это предотвращает создание подклассов вне вашего пакета, и внутри вашего пакета вы все равно можете иметь свои собственные внутренние подклассы. Что вы не можете, если класс final
.
Классы неизменяемой коллекции из библиотеки Google Guava используют эту технику. Из Javadoc :
Хотя этот класс не является окончательным, его нельзя разделить на подклассы, так как он не имеет
общественные или защищенные конструкторы. Таким образом, экземпляры этого типа
гарантированно будет неизменным.
Клиент может создавать ImmutableList
с использованием статических методов of()
и copyOf
.
См. Также Effective Java , пункт 4: принудительное использование неотъемлемой части с помощью частного конструктора.
Имейте в виду, что гарантировать неизменность при отсутствии конструкторов public
или protected
проще, чем создать класс final
. Например, Mockito позволит вам по умолчанию имитировать эти случаи:
ImmutableList notSoImmutable = mock(ImmutableList.class)
when(notSoImmutable.size()).thenThrow(new AssertionError("Oops.. where did that come from?"));
На пакетных индивидуальных занятиях
Поскольку ваш класс Animal
является частным пакетом, невозможно создать его подклассы вне его пакета. Таким образом, предполагая, что в его пакете вы создаете только подклассы Animal
, которые соответствуют его контракту, класс фактически неизменен.
В качестве ответа я предположил, что Animal
равно public
. Если вы были заинтересованы именно в частных закрытых классах, игнорируйте мой ответ; -)