Что произойдёт, если подкласс объявит экземплярный метод с той же сигнатурой, что статический метод суперкласса?
Такой подкласс не скомпилируется: статический метод суперкласса нельзя переопределить экземплярным методом с той же сигнатурой. Java требует, чтобы соответствующие методы оставались методами одного вида: оба статическими или оба экземплярными.
В Java статические методы принадлежат классу, а экземплярные методы — объекту. Такое разделение позволяет однозначно определить, должен ли вызов использовать тип класса или динамический тип объекта.
Подмена статического метода полиморфным экземплярным методом создала бы неоднозначное правило разрешения: один метод выбирался бы по классу, другой — по объекту. Поэтому язык запрещает смешивать эти формы в иерархии с одинаковой сигнатурой.
Разработчик может ошибочно воспринимать одинаковые имя и параметры как возможность переопределения. Но статический метод не участвует в динамическом полиморфизме, поэтому экземплярный метод подкласса не может легально заменить его.
Это важно при изменении API базового класса. Если в суперклассе появился статический метод, уже существующий экземплярный метод в подклассе с той же сигнатурой может привести к ошибке компиляции. Обратная ситуация также запрещена.
Компилятор сравнивает не только имя и параметры, но и категорию метода. Если метод суперкласса статический, объявление в подклассе с той же сигнатурой допустимо только как статическое скрытие, а не как переопределение.
Если метод суперкласса экземплярный, объявление статического метода в подклассе также запрещено. Нельзя использовать аннотацию Override для статического метода: она предназначена для переопределения экземплярных методов и в таком случае вызовет ошибку компиляции.
В примере Child не компилируется. Метод Parent.run статический, а Child.run экземплярный; одинаковая сигнатура не превращает их в корректную пару для переопределения.
Если оба метода статические, Java допускает скрытие: выбор зависит от типа, через который обращаются к методу, а не от фактического объекта. Если оба метода экземплярные, возможно обычное переопределение с динамическим выбором реализации.
Практическое правило: при анализе метода в иерархии сначала проверьте его статический или экземплярный характер, затем уже рассматривайте доступность, возвращаемый тип и переопределение.
В базовом классе библиотеки объявили статический метод create, а в пользовательском подклассе уже существовал экземплярный метод create с теми же параметрами. После обновления зависимости сборка перестала проходить.
Вариант с сохранением обоих методов невозможен: сигнатуры конфликтуют, а статический метод нельзя переопределить экземплярным. Переименование метода устраняет конфликт, но может потребовать изменений во многих вызовах.
Другой вариант — сделать метод подкласса статическим. Это устраняет ошибку, однако меняет контракт: метод больше не сможет обращаться к состоянию объекта и не будет участвовать в полиморфизме.
На практике обычно выбирают переименование или изменение API базового класса, если экземплярное поведение действительно необходимо. Это сохраняет ясную семантику и не вводит пользователей класса в заблуждение ожиданием динамического dispatch.
Нет. Аннотация не меняет природу метода и не разрешает запрещённое сочетание. Более того, компилятор сообщит об ошибке, потому что статический метод суперкласса не может быть переопределён.
Аннотация только проверяет намерение переопределить доступный экземплярный метод. Она полезна для обнаружения опечаток в сигнатуре, но не превращает статический метод в полиморфный.
Ошибка исчезнет, но это будет скрытие метода, а не переопределение. Вызов выбирается по статическому типу, через который обращаются к методу; создание объекта подкласса само по себе не переключает реализацию.
Следовательно, такое решение подходит только для методов, поведение которых действительно должно зависеть от класса, а не от состояния конкретного объекта.
Да, если сигнатура отличается параметрами. Это будет отдельная перегрузка, а не переопределение и не конфликт со статическим методом суперкласса.
Однако при вызове нужно учитывать правила выбора перегрузки: доступный набор методов и подходящий вариант определяются на этапе компиляции. Поэтому одинаковое имя ещё не означает, что вызов будет связан с методом, который разработчик ожидал.