Когда наследование от класса в Java невозможно или нежелательно?

«Когда наследование от класса в Java невозможно или нежелательно?» — вопрос из категории ООП, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Технические ограничения (невозможно):

  1. Класс объявлен как final. Ключевое слово final запрещает наследование.
    final class UtilityClass { }
    // Ошибка компиляции: Cannot inherit from final 'UtilityClass'
    class SubClass extends UtilityClass { }
  2. Все конструкторы класса являются private. Если у класса нет доступных конструкторов, его нельзя инстанцировать или наследовать.
  3. Класс имеет модификатор доступа package-private (по умолчанию), а попытка наследования происходит из другого пакета.
  4. Использование sealed-классов (Java 17+). Класс, объявленный как sealed, явно указывает, какие классы могут от него наследоваться с помощью ключевого слова permits.
    sealed class Shape permits Circle, Square { }
    // Только Circle и Square могут наследовать Shape

Архитектурные причины (нежелательно):

  • Нарушение принципа подстановки Барбары Лисков (LSP). Если подкласс не может полноценно заменить суперкласс в любом контексте (например, изменяет или ослабляет постусловия, выбрасывает непредусмотренные исключения), наследование ошибочно.
  • Отношение «has-a» вместо «is-a». Если цель — повторное использование кода, а не установление иерархии типов, предпочтительнее использовать композицию.
  • Класс не предназначен для расширения. Например, класс может быть частью внутренней реализации, и его изменение нарушит инварианты.