Я играл с модификаторами со статическим методом и обнаружил странное поведение.
Как мы знаем, статические методы нельзя переопределить, поскольку они связаны с классом, а не с экземпляром.
Итак, если у меня есть приведенный ниже фрагмент, он отлично компилируется
//Snippet 1 - Compiles fine
public class A {
static void ts() {
}
}
class B extends A {
static void ts() {
}
}
Но если я добавлю модификатор final к статическому методу в классе A, то компиляция завершится неудачно, ts () в B не может переопределить ts () в A; переопределенный метод является статическим окончательным .
Почему это происходит, когда статический метод вообще нельзя переопределить?
Ответы:
Статические методы нельзя переопределить, но их можно скрыть.
ts()
Метод B не перекрывая (не подлежит полиморфизм)ts()
А , но она будет скрыть. Если вы вызываетеts()
B (НЕA.ts()
илиB.ts()
... простоts()
), будет вызываться один из B, а не A. Поскольку он не подвергается полиморфизму, вызовts()
в A никогда не будет перенаправлен на тот, который находится в B.Ключевое слово
final
отключит скрытие метода. Поэтому они не могут быть скрыты, и попытка сделать это приведет к ошибке компилятора.Надеюсь это поможет.
источник
A#ts
он наследуется и такой метод уже существуетB
, просто наличие двух методов с одинаковой сигнатурой и другим модификатором (final
) не будет работать как перегрузка .. Я хотел бы придумать для этого простое сообщениеЭто не совсем так. Пример кода действительно означает, что метод ts в B скрывает метод ts в A. Так что это не совсем переопределение. На Джаваранче есть хорошее объяснение.
источник
Статические методы принадлежат классу, а не экземпляру.
A.ts()
иB.ts()
всегда будут отдельными методами.Настоящая проблема в том, что Java позволяет вам вызывать статические методы для объекта-экземпляра. Статические методы с той же сигнатурой родительского класса скрываются при вызове из экземпляра подкласса. Однако вы не можете переопределить / скрыть методы final .
Можно подумать, что в сообщении об ошибке будет использоваться слово «скрыто», а не «переопределено» ...
источник
Вы можете подумать о том, чтобы сделать статический метод final, учитывая следующее:
Имея следующие классы:
Теперь "правильный" способ вызова этих методов был бы
что приведет к тому,
AB
но вы также можете вызвать методы для экземпляров:что также приведет
AB
к.Теперь рассмотрим следующее:
что бы напечатать
A
. Это может вас удивить, поскольку на самом деле у вас есть объект классаB
. Но поскольку вы вызываете его из ссылки типаA
, он вызоветA.ts()
. Вы можете печататьB
с помощью следующего кода:В обоих случаях объект, который у вас есть, действительно принадлежит классу
B
. Но в зависимости от указателя, указывающего на объект, вы будете вызывать метод fromA
или fromB
.Теперь предположим, что вы разработчик класса
A
и хотите разрешить подклассы. Но вам действительно нужен методts()
, когда бы он ни вызывался, даже из подкласса, который делал бы то, что вы хотите, а не был бы скрыт версией подкласса. Тогда вы можете сделать этоfinal
и предотвратить его скрытие в подклассе. И вы можете быть уверены, что следующий код вызовет метод из вашего классаA
:Хорошо, по общему признанию, это каким-то образом сконструировано, но в некоторых случаях это может иметь смысл.
Вы должны вызывать статические методы не в экземплярах, а непосредственно в классах - тогда у вас не будет этой проблемы. Также IntelliJ IDEA, например, покажет вам предупреждение, если вы вызовете статический метод в экземпляре, а также если вы сделаете статический метод final.
источник
Метод ts () в B не отменяет метод ts () в A, это просто другой метод. Класс B не видит метод ts () в A, поскольку он статический, поэтому он может объявить свой собственный метод с именем ts ().
Однако, если метод является окончательным, компилятор обнаружит, что в A есть метод ts (), который не следует переопределять в B.
источник
Я думаю, что здесь ошибка компиляции вводила в заблуждение. Он не должен был сказать, что «переопределенный метод является статическим окончательным», но вместо этого должен был сказать «переопределенный метод является окончательным». Статический модификатор здесь не имеет значения.
источник
Статический метод не может быть переопределен в Java, в отличие от нестатических методов. Но они наследуются как статические и нестатические элементы данных. Поэтому в родительском классе нельзя создать нестатический метод с таким же именем.
В
final
ключевых словах гарантирует , что метод конкретного орган будет запускать каждый раз, когда вызов метода. Теперь, если статический метод создается в дочернем классе с тем же именем и выполняется вызов метода, выполняется метод в подклассе, чего не должно быть, если final имеет префикс перед именем статического метода в родительском классе. , Следовательно, ключевое слово final ограничивает создание метода с тем же именем в дочернем классе.источник