Почему мы говорим, что статический метод в Java не является виртуальным методом?

#java

#java

Вопрос:

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


Согласно определению, каждый нестатический метод в Java по умолчанию является виртуальным методом, за исключением final и private методов. Метод, который не может быть унаследован из-за полиморфного поведения, не является виртуальным методом.


Абстрактный класс в Java — это не что иное, как чистый виртуальный метод, эквивалентный C .


Почему мы говорим, что статический метод в Java не является виртуальным методом? Даже если мы можем переопределить статический метод и, следовательно, это может дать некоторые преимущества полиморфизма, а также статический метод в Java может быть вызван в основном с помощью связанного с ним имени класса, но также возможно вызвать его, используя объект связанного с ним класса в Java таким же образом, как вызывается метод экземпляра.

Ответ №1:

Вы не можете переопределять статические методы. Они связаны во время компиляции. Они не полиморфны. Даже если вы попытаетесь вызвать его, как если бы это был метод экземпляра (что, по-моему, вам не следует делать), он привязан к типу времени компиляции этого выражения, и значение времени выполнения полностью игнорируется (даже если оно равно null):

 Thread otherThread = null;
otherThread.sleep(1000); // No errors, equivalent to Thread.sleep(1000);
  

Такое поведение может сильно сбить с толку читателя, вот почему, по крайней мере, некоторые IDE позволяют генерировать предупреждения или ошибки для доступа к статическим элементам «через» ссылку. Это был недостаток в дизайне Java, чистый и простой — но это вообще не делает статические методы виртуальными.

Комментарии:

1. Некоторые IDE могут помечать ошибки или предупреждения, если вы вызываете статические методы таким образом. Я не уверен, существует ли флаг компилятора, который вызывал бы то же самое во время компиляции, хотя я подозреваю, что есть.

2. @Romain: Боюсь, я не знаю ничего подобного для javac.

3. Тогда должно быть … Да. Это было бы полезно, чтобы остановить людей от написания такого вводящего в заблуждение кода.

Ответ №2:

Предположим, у вас есть класс A

 public class A
{
    public static void doAStaticThing()
    {
        System.out.println("In class A");
    }
}
  

И B

 public class B extends A
{
    public static void doAStaticThing()
    {
        System.out.println("In class B");
    }
}
  

И метод в другом классе, подобный этому:

 public void foo()
{
    B aB = new B();
    bar(B);
}

public void bar(A anA)
{
    anA.doAStaticThing(); // gives a warning in Eclipse
}
  

Сообщение, которое вы увидите на консоли, является

 In class A
  

Компилятор просмотрел объявленный тип anA в method bar и статически привязал к реализации класса A doAStaticThing() . Метод не является виртуальным.

Ответ №3:

Это просто, статический метод не может быть переопределен наследующим классом, поскольку он не наследуется. Значит, он не виртуальный.

То, что вы называете «переопределением статического метода», на самом деле всего лишь определяет другой статический метод в другом классе. Он только «скроет» (и это на самом деле гораздо более сильное слово, чем то, что было бы на самом деле верно там) другой метод, а не переопределит его.

Ответ №4:

Абстрактный класс в Java — это не что иное, как чистый виртуальный метод, эквивалентный C .

Класс — это не метод. Абстрактный класс не обязательно должен иметь «виртуальные» или абстрактные методы или вообще какие-либо методы.

Что-то, что разработчики C называют функциями Java так же, как C переименован, не понимая различий. 😉

Почему мы говорим, что статический метод в Java не является виртуальным методом?

Не уверен, кто это говорит, но static методы не являются полиморфными.

Даже если мы можем переопределить статический метод

Мы не можем, вы можете только скрыть или перегрузить статический метод.

Используете ли вы класс, подкласс или экземпляр для вызова статического метода, фактический класс или экземпляр игнорируется. например, вы можете сделать

 ((Thread) null).yield();
  

Ответ №5:

Потому что полиморфизм применяется к объектам, в то время как статический метод относится не к какому-либо объекту (а к классу).