Чи є у Java успадковані статичні методи?


142

Я читав Посібник програміста до сертифікації Java ™ SCJP від Халіда Магала .

У розділі "Спадщина" це пояснюється

Спадщина членів тісно пов'язана з їх заявленою доступністю. Якщо учасник надкласового класу доступний за допомогою його простого імені в підкласі (без використання жодного додаткового синтаксису, як супер), цей член вважається спадковим

Він також згадує, що статичні методи не успадковуються. Але код нижче ідеально:

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-е видання. Будь ласка, надайте фактичну пропозицію.
Маркіз Лорн

Відповіді:


179

Усі доступні методи успадковуються підкласами.

З навчальних посібників Sun Sun :

Підклас успадковує всі відкриті та захищені члени свого батьківського, незалежно від того, в якому пакеті знаходиться підклас. Якщо підклас знаходиться в тому ж пакеті, що і його батьківський, він також успадковує приватно-пакетні члени батьків. Ви можете використовувати успадковані члени як є, замінити їх, приховати або доповнити їх новими членами

Єдина відмінність від успадкованих статичних (класових) методів та успадкованих нестатичних (екземплярів) методів полягає в тому, що коли ви пишете новий статичний метод з тим самим підписом, старий статичний метод просто прихований, а не перекритий.

Зі сторінки на різницю між перекриттям і приховуванням.

Різниця між приховуванням і переосмисленням має важливе значення. Версія заміненого методу, яка викликається, - це версія в підкласі. Версія прихованого методу, до якого визываются, залежить від того, на нього буде викликано надклас або підклас


настільки успадковане стосується того, чи можемо ми замінити цього члена в підкласі?
Алгоритміст

Ну, це частина спадщини, але не все це. Я б сказав, що інші основні частини спадкування - це повторне використання коду та поліморфізм.
yincrash

Чи має також переосмислення деякі правила, такі як переосмислення?
Surender Thakran

2
@Algorithmist ні точно. Все, що ваш підклас бачить далі в ієрархії, - це речі, які ваш клас успадкував. Але статичні методи, які успадковуються, не можуть бути відмінені, лише приховані ("передекларовані" з тим же підписом). Тому ви також можете оголосити свої статичні методи як остаточні, це не має значення. Який статичний метод буде застосовано, відомо під час компіляції. Для методів, що не є кінцевими екземплярами, роздільну здатність має бути відкладено на час виконання, оскільки вони можуть бути переоформлені.
Мартін Андерссон

1
Ваш останній абзац повністю підірваний !!! "Версія методу переопределення, яка отримує виклик, є тією, що знаходиться в підкласі". Це неправда. Скажімо: Версія методу переопределення, яка отримує виклик, визначається лише під час виконання JVM, пов'язаного з тим, який об'єкт зробив зателефонуйте :)
mounaim

14

Якщо це справді говорить книга, це неправильно. [1]

Специфікація мови Java # 8.4.8 говорить:

8.4.8 Наслідування, переосмислення та приховування

Клас C успадковує від свого прямого суперкласу всі конкретні методи m (як статичні, так і екземплярні) надкласу, для яких справедливі всі наступні дії:

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

  • m є загальнодоступним, захищеним або оголошеним з доступом до пакету в тому ж пакеті, що і C.

  • Жоден спосіб, оголошений в C, не має підпису, який є підписом (§ 8.4.2) підпису m.

[1] Це не говорить про те, що в моєму примірнику, 1-е видання, 2000р.


13

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

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.
Lucas C. Feijo

Ось, що пояснює ця програма, інстанціювати об'єкт B і очікувати, що спадщина працюватиме, неможливо зі статичними членами. Спробуйте взяти той самий код у своєму затемненні / будь-якій ідеї або скласти за допомогою javac і виконати його
Gaurav

2
@ LucasC.Feijo насправді я це працює. Принаймні в моєму IDE (затемнення). Я просто отримую попередження. Це, мабуть, не буде гарним стилем ... але це вже інша історія.
dingalapadum

2
@ LucasC.Feijo викликати статичний метод на екземплярі не рекомендується. Але це працює так само, як викликати статичний метод на ім'я класу.
Ziyang Zhang

5

B.display () працює тому, що статична декларація робить метод / член належністю до класу, а не будь-якого конкретного екземпляра класу (він же Object). Більше про це можна прочитати тут .

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


3

Статичні методи на 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, але вони не беруть участі в поліморфізмі. Якщо ми спробуємо замінити статичні методи, вони просто приховатимуть статичні методи надкласу, а не переосмислювати їх.


Я не бачу причин для спростування цієї відповіді. Чітка і чітка, принаймні перша частина. Другу частину не слід сприймати занадто технічно, інакше це нормально. Для уточнення, у переосмислювальних методах тип повернення може змінюватися (на підтип), тоді як у статичних методів це не так. Технічно "спроба змінити" не стосується статичних методів, тому все, що ми можемо сказати, - це не можемо.
шархп

2

Ця концепція не така проста, як виглядає. Ми можемо отримати доступ до статичних членів без успадкування, що є HasA-відношенням. Ми можемо отримати доступ до статичних членів, розширивши також батьківський клас. Це не означає, що це відношення ISA (Спадщина). Насправді статичні члени належать до класу, а статичні не є модифікатором доступу. Поки модифікатори доступу дозволяють отримувати доступ до статичних членів, ми можемо використовувати їх в інших класах. Як і якщо він є загальнодоступним, він буде доступний всередині одного пакета, а також поза пакетом. Для приватних ми не можемо його використовувати ніде. За замовчуванням ми можемо використовувати його лише в пакеті. Але для захисту ми повинні розширити супер клас. Тож отримання статичного методу до іншого класу не залежить від статичності. Це залежить від модифікаторів доступу. Отже, на мій погляд, Статичні члени можуть отримати доступ, якщо модифікатори доступу дозволяють. В іншому випадку ми можемо використовувати їх так, як ми використовуємо Hasa-відношення. І має відношення - це не спадщина. Знову ми не можемо перекрити статичний метод. Якщо ми можемо скористатися іншим методом, але не можемо його змінити, то це HasA-відношення. Якщо ми не зможемо їх перемогти, це не буде спадщиною. Отже, письменник був на 100% правильним.


Розширення батьківського класу є співвідношенням "є-а". Якщо доступ приватний, ви можете використовувати його з класу. "захищений" включає похідні класи та класи в поточному пакеті. Тут занадто багато помилок.
Маркіз Лорн

0

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


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

Ми можемо оголосити статичні методи з однаковою підписом у підкласі, але це не вважається переосмислювальним, оскільки не буде поліморфізму під час виконання. Тому що всі статичні члени класу завантажуються під час завантаження класу, тому він вирішує при компіляції час (переосмислюючи час виконання) Отже, відповідь - «Ні».


2
Я не знаю, чому люди завжди знижують голоси і не наводять причину неухильного голосування.
surajs1n

Ця відповідь стосується переваги. Питання стосується спадкування.
Маркіз Лорн

-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. Коли ми називаємо статику статичним способом через., Він шукатиме статику, визначену в цьому класі, або клас, найближчий до цього, у ланцюжку успадкування. Це доводить, що статичні методи успадковуються.
  2. Коли статичний метод викликається з екземпляра, він викликає статичний метод, визначений у типі часу компіляції.
  3. Статичний метод можна викликати з nullекземпляра. Я здогадуюсь, що компілятор буде використовувати тип змінної для пошуку класу під час компіляції та перекладе це у відповідний виклик статичного методу.

1
Простий код - це не пояснення, це демонстрація. Відповідь на це питання має наводити нормативні посилання, а не лише демонструвати поведінку деякої нестабільної реалізації.
Маркіз Лорнський

-2

Статичні члени є універсальними членами. До них можна отримати доступ з будь-якого місця.


4
Ви можете отримати доступ з будь-якого місця в прямому сенсі, це неправильно: статичний! ви можете уточнити :-)
kleopatra

Насправді ця відповідь чудова, якщо сприймати буквально. Я не можу придумати єдиного місця в коді, куди може перейти код, який не може отримати доступ до статичного члена класу. Ви можете отримати доступ до них у статичних ініціалізаторах, статичних конструкторах, конструкторах екземплярів, методах, властивостях у різних класах, у будь-якій області. Поки клас і статичний метод є загальнодоступними, до них можна отримати доступ з будь-якого місця, якщо припустити, що немає статичних ініціалізаторів. По суті, статичні члени не успадковуються, вони є просто класовими (тобто універсальними) методами, які доступні з будь-якого місця.
Трайнко

@Triynko Відповідь неправильна у випадку приватних або захищених пакунками пакетів, доступ до яких знаходиться поза межами пакету.
Маркіз Лорн

@kleopatra - поза темою. java swing? чи справді люди цим користуються в наші дні?
MasterJoe2

@Pavan спробуйте викликати приватну статику поза класом. Це не спрацює.
Ракеш Ядав

-2

Статичні члени не будуть успадковані підкласові, тому що успадковується лише для нестатичних членів .. А статичні члени завантажуватимуться у статичний пул навантажувачем класів. Спадщина лише для тих членів, які завантажені всередині об'єкта


Зовсім неправильно. Див. JLS № 8.4.8 .
Маркіз Лорн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.