Унаследованы ли статические методы в Java?

149

Я читал «Руководство программиста по сертификации Java ™ SCJP » Халида Могала .

В главе о наследовании объясняется, что

Наследование членов тесно связано с их заявленной доступностью. Если член суперкласса доступен по своему простому имени в подклассе (без использования какого-либо дополнительного синтаксиса, такого как super), этот член считается унаследованным

Также упоминается, что статические методы не наследуются. Но приведенный ниже код прекрасен:

class A
{
    public static void display()
    {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A
{
    public void show()
    {
        // This works - accessing display() by its simple name -
        // meaning it is inherited according to the book.
        display();
    }
}

Как я могу напрямую использовать display()в классе B? Более того, B.display()тоже работает.

Применимо ли объяснение в книге только к методам экземпляра?

Алгоритмист
источник
stackoverflow.com/questions/4716040/… имеет интересную информацию.
Мат
Это не то, что написано в моем экземпляре 1-го издания. Пожалуйста, предоставьте актуальную цитату.
Маркиз Лорн,
связанные: stackoverflow.com/questions/25169175/…
jaco0646 07

Ответы:

184

Все доступные методы наследуются подклассами.

От Sun Java Tutorials :

Подкласс наследует все открытые и защищенные члены своего родителя, независимо от того, в каком пакете находится подкласс. Если подкласс находится в том же пакете, что и его родительский класс, он также наследует частные члены пакета родительского класса. Вы можете использовать унаследованные элементы как есть, заменять их, скрывать или дополнять новыми членами.

Единственное отличие от унаследованных статических (классовых) методов и унаследованных нестатических (экземпляров) методов состоит в том, что когда вы пишете новый статический метод с той же сигнатурой, старый статический метод просто скрывается, а не переопределяется.

Со страницы о разнице между переопределением и скрытием.

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

инкраш
источник
так унаследовано относится к тому, можем ли мы переопределить этот член в подклассе?
Алгоритмист
Что ж, это часть наследства, но не все. Я бы сказал, что другие важные части наследования - это повторное использование кода и полиморфизм.
yincrash
Есть ли у переопределения некоторые правила, например, у переопределения?
Surender Thakran
2
@Algorithmist нет, не совсем. Все, что ваш подкласс видит дальше по иерархии, - это то, что унаследовано вашим классом. Но статические методы, которые унаследованы, не могут быть переопределены, а только скрыты («повторно объявлены» с той же подписью). Поэтому вы также можете объявить свои статические методы окончательными, это не имеет значения. Какой статический метод будет вызван, известно во время компиляции. При использовании неокончательных методов экземпляра разрешение должно быть отложено до времени выполнения, поскольку оно может быть отменено.
Мартин Андерссон
1
Ваш последний абзац полностью подорван !!! «Вызываемая версия замещающего метода находится в подклассе», это неверно: Скажем, вызываемая версия замещающего метода определяется только во время выполнения JVM, связанной с тем, какой объект сделал звоните :)
mounaim
16

Вы можете почувствовать разницу в следующем коде, который немного отличается от вашего кода.

class A {
    public static void display() {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A {
    public void show() {
        display();
    }

    public static void display() {
        System.out.println("Inside static method of this class");
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        // prints: Inside static method of this class
        b.display();

        A a = new B();
        // prints: Inside static method of superclass
        a.display();
    }
}

Это связано с тем, что статические методы являются методами класса.

A.display () и B.display () будут вызывать методы своих соответствующих классов.

Гаурав
источник
1
Вызов статического метода для экземпляра, как вы пытаетесь, не будет работать в java.
Лукас К. Фейджо,
Это то, что объясняет эта программа, создание экземпляра объекта B и ожидание работы наследования невозможно со статическими членами. Попробуйте взять тот же код в своем eclipse / any ide или скомпилировать с помощью javac и выполнить его
Gaurav
3
@ LucasC.Feijo на самом деле у меня это работает. По крайней мере, в моей IDE (eclipse). Я просто получаю предупреждение. Хотя это может быть не очень хороший стиль ... но это другая история.
dingalapadum
3
@ LucasC.Feijo вызывать статический метод для экземпляра не рекомендуется. Но он работает так же, как вызов статического метода для имени класса.
Ziyang Zhang
14

Если это действительно то, что книга говорит, это неправильно. [1]

Спецификация языка Java # 8.4.8 гласит:

8.4.8 Наследование, переопределение и скрытие

Класс C наследует от своего прямого суперкласса все конкретные методы m (как статические, так и экземпляры) суперкласса, для которых выполняются все следующие условия:

  • m является членом прямого суперкласса C.

  • m является общедоступным, защищенным или объявлен с пакетным доступом в том же пакете, что и C.

  • Ни один из методов, объявленных в C, не имеет подписи, которая является дополнительной подписью (§8.4.2) подписи m.

[1] Это не сказано в моем экземпляре, 1-е издание, 2000 г.

Маркиз Лорн
источник
5

B.display () работает, потому что статическое объявление делает метод / член принадлежащим классу, а не какому-либо конкретному экземпляру класса (он же Object). Вы можете прочитать об этом здесь .

Также следует отметить, что вы не можете переопределить статический метод, вы можете сделать так, чтобы ваш подкласс объявлял статический метод с той же сигнатурой, но его поведение может отличаться от ожидаемого. Вероятно, это причина, по которой он не считается унаследованным. Вы можете ознакомиться с проблемным сценарием и объяснением здесь .

Кай
источник
4

Статические методы в Java наследуются, но не могут быть переопределены. Если вы объявляете тот же метод в подклассе, вы скрываете метод суперкласса, а не переопределяете его. Статические методы не полиморфны. Во время компиляции статический метод будет статически связан.

Пример:

public class Writer {
    public static void write() {
        System.out.println("Writing");
    }
}

public class Author extends Writer {
    public static void write() {
        System.out.println("Writing book");
    }
}

public class Programmer extends Writer {

    public static void write() {
        System.out.println("Writing code");
    }

    public static void main(String[] args) {
        Writer w = new Programmer();
        w.write();

        Writer secondWriter = new Author();
        secondWriter.write();

        Writer thirdWriter = null;
        thirdWriter.write();

        Author firstAuthor = new Author();
        firstAuthor.write();
    }
}

Вы получите следующее:

Writing
Writing
Writing
Writing book

источник
2

Статические методы наследуются в Java, но не участвуют в полиморфизме. Если мы попытаемся переопределить статические методы, они просто скроют статические методы суперкласса вместо их переопределения.

Правин Кумар
источник
Я не вижу причин отклонять этот ответ. Она четкая и ясная, по крайней мере, первая часть. Вторую часть не стоит воспринимать слишком технически, иначе все нормально. Чтобы уточнить, в методах переопределения тип возвращаемого значения может измениться (на подтип), в то время как это не относится к статическим методам. Технически «попытка переопределения» неприменима к статическим методам, поэтому все, что мы можем сказать, это то, что мы не можем.
Sharhp
2

Эта концепция не так проста, как кажется. Мы можем получить доступ к статическим членам без наследования, которое является отношением HasA. Мы можем получить доступ к статическим членам, также расширив родительский класс. Это не означает, что это ISA-отношение (наследование). Фактически статические члены принадлежат классу, а статические не являются модификатором доступа. Пока модификаторы доступа разрешают доступ к статическим членам, мы можем использовать их в других классах. Например, если он общедоступный, он будет доступен внутри того же пакета, а также вне пакета. Для личного пользования мы не можем нигде использовать. По умолчанию мы можем использовать его только внутри пакета. Но для защиты мы должны расширить суперкласс. Таким образом, получение статического метода для другого класса не зависит от того, является ли он статическим. Это зависит от модификаторов доступа. Итак, на мой взгляд, Статические члены могут получить доступ, если модификаторы доступа позволяют. В противном случае мы можем использовать их так, как мы используем отношение Хаса. И имеет отношение не по наследству. Опять же, мы не можем переопределить статический метод. Если мы можем использовать другой метод, но не можем его переопределить, то это отношение HasA. Если мы не сможем их переопределить, это не будет наследованием, значит, автор был на 100% прав.

Noman_ibrahim
источник
Расширение родительского класса - это отношение «есть». Если доступ является частным, вы можете использовать его из класса. «protected» включает производные классы и классы в текущем пакете. Здесь слишком много ошибок.
Marquis of Lorne
0

Статический метод наследуется в подклассе, но это не полиморфизм. Когда вы пишете реализацию статического метода, метод родительского класса скрывается, а не переопределяется. Подумайте, если он не передается по наследству, то как можно получить доступ без него classname.staticMethodname();?

user4016405
источник
0

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

Но верно также и то, что статические функции-члены не участвуют в динамической привязке. Если сигнатура этого статического метода одинакова как в родительском, так и в дочернем классе, тогда применяется концепция Shadowing, а не полиморфизм.

Шубхам
источник
0

Вы можете переопределить статические методы, но если вы попытаетесь использовать полиморфизм, они будут работать в соответствии с областью действия класса (вопреки тому, что мы обычно ожидаем).

public class A {

    public static void display(){
        System.out.println("in static method of A");
    }
}

public class B extends A {

    void show(){
        display();
    }

     public static void display(){
        System.out.println("in static method of B");
    }

}
public class Test {

    public static void main(String[] args){
        B obj =new B();
        obj.show();

        A a_obj=new B();
        a_obj.display();


    }


}

В первом случае o / p является «статическим методом B» # успешное переопределение Во втором случае o / p является «статическим методом A» # Статический метод - полиморфизм не учитывается.

Манав Гарекар
источник
-1

Мы можем объявить статические методы с той же сигнатурой в подклассе, но это не считается переопределяющим, так как не будет никакого полиморфизма во время выполнения, потому что все статические члены класса загружаются во время загрузки класса, поэтому он решает при компиляции time (переопределение во время выполнения) Следовательно, ответ - «Нет».

NGK
источник
2
Я не знаю, почему люди всегда голосуют против и не указывают причину, по которой они голосуют против.
surajs1n
Этот ответ касается переопределения. Вопрос в наследовании.
Marquis of Lorne
-1

Многие выразили свой ответ словами. Это расширенное объяснение в кодах:

public class A {
    public static void test() {
        System.out.println("A");
    }
    public static void test2() {
        System.out.println("Test");
    }
}

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

// Called statically
A.test();
B.test();
System.out.println();

// Called statically, testing static inheritance
A.test2();
B.test2();
System.out.println();

// Called via instance object
A a = new A();
B b = new B();
a.test();
b.test();
System.out.println();

// Testing inheritance via instance call
a.test2();
b.test2();
System.out.println();

// Testing whether calling static method via instance object is dependent on compile or runtime type
((A) b).hi();
System.out.println();

// Testing whether null instance works
A nullObj = null;
nullObj.hi();

Полученные результаты:

A
B

Test
Test

A
B

Test
Test

A

A

Отсюда вывод:

  1. Когда мы вызываем static статическим образом через., Он будет искать static, определенный в этом классе, или ближайший к нему класс в цепочке наследования. Это доказывает, что статические методы наследуются.
  2. Когда статический метод вызывается из экземпляра, он вызывает статический метод, определенный в типе времени компиляции.
  3. Статический метод можно вызвать из nullэкземпляра. Я предполагаю, что компилятор будет использовать тип переменной, чтобы найти класс во время компиляции и преобразовать его в соответствующий вызов статического метода.
Джай
источник
1
Простой код - это не объяснение, это демонстрация. Ответ на этот вопрос должен указывать на нормативные ссылки, а не просто демонстрировать поведение некоторой неустановленной реализации.
Marquis of Lorne
-2

Статические члены - это универсальные члены. К ним можно получить доступ откуда угодно.

Паван
источник
4
можно получить доступ из любого места, если понимать буквально, это неправильно: static! = scope. возможно, вы захотите уточнить :-)
kleopatra 08
На самом деле, этот ответ хорош, если понимать его буквально. Я не могу придумать ни одного места в коде, где мог бы быть код, который не мог бы получить доступ к статическому члену класса. Вы можете получить к ним доступ в статических инициализаторах, статических конструкторах, конструкторах экземпляров, методах, свойствах, в разных классах, в любой области. Пока класс и статический метод являются общедоступными, к ним можно получить доступ из любого места, при условии, что нет циклических зависимостей от статических инициализаторов. По сути, статические члены не наследуются, это просто методы уровня класса (то есть универсальные), доступные из любого места.
Трийнко
@Triynko Ответ неверен в случае методов, которые являются частными или защищенными пакетами, доступ к которым осуществляется извне.
Marquis of Lorne
@kleopatra - не по теме. качели java? люди действительно используют это в наши дни?
MasterJoe
@Pavan попробуйте вызвать частную статику извне класса. Это не сработает.
Ракеш Ядав
-3

Статические члены не будут унаследованы в подкласс, потому что наследование предназначено только для нестатических членов. И статические члены будут загружены в статический пул загрузчиком класса. Наследование возможно только для тех членов, которые загружены внутри объекта.

Ашвини Э
источник
Совершенно неверно. См. JLS № 8.4.8 .
Marquis of Lorne
неверно, пожалуйста, обновите свой ответ, если теперь все понятно :)
iprashant