Czy metody statyczne są dziedziczone w Javie?

142

Czytałem Podręcznik programisty po certyfikacji Java ™ SCJP autorstwa Khalida Mughala.

W rozdziale Dziedziczenie wyjaśnia to

Dziedziczenie członków jest ściśle związane z ich deklarowaną dostępnością. Jeśli element członkowski nadklasy jest dostępny poprzez swoją prostą nazwę w podklasie (bez użycia dodatkowej składni, takiej jak super), ten element członkowski jest uznawany za dziedziczony

Wspomina również, że metody statyczne nie są dziedziczone. Ale poniższy kod jest w porządku:

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();
    }
}

Jak mogę używać bezpośrednio display()w klasie B? Co więcej, B.display()też działa.

Czy wyjaśnienie w książce dotyczy tylko metod instancji?

Algorytmista
źródło
stackoverflow.com/questions/4716040/… zawiera interesujące informacje.
Mat
Nie to jest napisane w moim egzemplarzu, 1. wydanie. Proszę podać aktualną ofertę.
Markiz Lorne

Odpowiedzi:

179

Wszystkie dostępne metody są dziedziczone przez podklasy.

Z samouczków Sun Java :

Podklasa dziedziczy wszystkich publicznych i chronionych członków swojego rodzica, bez względu na to, w jakim pakiecie znajduje się podklasa. Jeśli podklasa znajduje się w tym samym pakiecie co jej element nadrzędny, dziedziczy również prywatne elementy pakietu macierzystego. Możesz używać odziedziczonych członków w niezmienionej postaci, zastępować je, ukrywać lub uzupełniać o nowych członków

Jedyną różnicą w przypadku dziedziczonych metod statycznych (klasowych) i dziedziczonych metod statycznych (instancji) jest to, że podczas pisania nowej metody statycznej z tym samym podpisem stara metoda statyczna jest po prostu ukrywana, a nie zastępowana.

Ze strony na temat różnicy między nadpisywaniem a ukrywaniem.

Rozróżnienie między ukrywaniem a zastępowaniem ma ważne konsekwencje. Wywoływana jest wersja przesłoniętej metody, która znajduje się w podklasie. Wywoływana wersja metody ukrytej zależy od tego, czy jest ona wywoływana z nadklasy czy z podklasy

yincrash
źródło
tak dziedziczony odnosi się do tego, czy możemy zastąpić ten element członkowski w podklasie?
Algorithmist
Cóż, to jest część dziedziczenia, ale nie wszystko. Powiedziałbym, że inne główne elementy dziedziczenia to ponowne wykorzystanie kodu i polimorfizm.
yincrash
Czy przedefiniowanie ma również pewne zasady, takie jak nadpisywanie?
Surender Thakran
2
@Algorithmist no nie dokładnie. Wszystkie rzeczy, które twoja podklasa widzi dalej w hierarchii, są dziedziczone przez twoją klasę. Ale metody statyczne, które są dziedziczone, nie mogą być przesłonięte, tylko ukryte („ponownie zadeklarowane” z tym samym podpisem). Dlatego możesz również zadeklarować swoje metody statyczne jako ostateczne, to nie ma znaczenia. Która metoda statyczna zostanie wywołana, jest znana w czasie kompilacji. W przypadku metod instancji innych niż końcowe rozstrzygnięcie musi zostać odroczone do czasu wykonywania, ponieważ mogą zostać zastąpione.
Martin Andersson
1
Twój ostatni akapit jest całkowicie podważony !!! „Wywoływana wersja metody zastępowanej jest tą z podklasy” to nieprawda: Powiedzmy: wywoływana wersja metody zastępowanej jest określana tylko w czasie wykonywania przez maszynę JVM powiązaną z obiektem, zadzwoń :)
mounaim
14

Jeśli tak naprawdę mówi książka, to źle. [1]

Java Language Specification # 8.4.8 stanowi:

8.4.8 Dziedziczenie, nadpisywanie i ukrywanie

Klasa C dziedziczy ze swojej bezpośredniej nadklasy wszystkie konkretne metody m (zarówno statyczne, jak i instancyjne) z superklasy, dla których spełnione są wszystkie poniższe warunki:

  • m jest członkiem bezpośredniej nadklasy C.

  • m jest publiczny, chroniony lub zadeklarowany z dostępem do pakietu w tym samym pakiecie co C.

  • Żadna metoda zadeklarowana w C nie ma podpisu będącego podpisem (§ 8.4.2) podpisu M.

[1] Nie jest powiedziane, że w moim egzemplarzu, wydanie 1, 2000.

Markiz Lorne
źródło
13

Możesz zauważyć różnicę w następującym kodzie, który jest nieznaczną modyfikacją w stosunku do twojego kodu.

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();
    }
}

Wynika to z faktu, że metody statyczne są metodami klasowymi.

A.display () i B.display () wywołają metody swoich klas.

Gaurav
źródło
1
Wywołanie metody statycznej na instancji, takiej jak próbujesz, nie zadziała w Javie.
Lucas C. Feijo
To właśnie wyjaśnia ten program, tworzenie instancji obiektu B i oczekiwanie, że dziedziczenie zadziała, nie będzie możliwe w przypadku statycznych elementów członkowskich. Spróbuj wziąć ten sam kod w swoim eclipse / dowolnym ide lub skompiluj go za pomocą javac i uruchom go
Gaurav
2
@ LucasC.Feijo właściwie to działa. Przynajmniej w moim IDE (eclipse). Po prostu dostaję ostrzeżenie. Może to jednak nie jest dobry styl ... ale to już inna historia.
dingalapadum
2
@LucasC.Feijo wywołanie metody statycznej na instancji nie jest zalecane. Ale działa to tak samo, jak wywołanie metody statycznej na nazwie klasy.
Ziyang Zhang
5

B.display () działa, ponieważ deklaracja statyczna sprawia, że ​​metoda / element członkowski należy do klasy, a nie do żadnej konkretnej instancji klasy (aka Object). Więcej na ten temat przeczytasz tutaj .

Inną rzeczą, na którą należy zwrócić uwagę, jest to, że nie można przesłonić metody statycznej, można zadeklarować metodę statyczną z taką samą sygnaturą w swojej podklasie, ale jej zachowanie może być inne niż oczekiwane. Prawdopodobnie jest to powód, dla którego nie uważa się go za dziedziczony. Możesz sprawdzić problematyczny scenariusz i wyjaśnienie tutaj .

Kai
źródło
3

Metody statyczne w Javie są dziedziczone, ale nie można ich przesłonić. Jeśli deklarujesz tę samą metodę w podklasie, ukrywasz metodę nadklasy zamiast ją przesłonić. Metody statyczne nie są polimorficzne. W czasie kompilacji metoda statyczna zostanie połączona statycznie.

Przykład:

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();
    }
}

Otrzymasz:

Writing
Writing
Writing
Writing book

źródło
2

Metody statyczne są dziedziczone w Javie, ale nie biorą udziału w polimorfizmie. Jeśli spróbujemy przesłonić metody statyczne, po prostu ukryją one statyczne metody nadklasy zamiast je przesłonić.

Praveen Kumar
źródło
Nie widzę powodu, by odrzucać tę odpowiedź. Jest ostry i wyraźny, przynajmniej pierwsza część. Drugiej części nie należy traktować zbyt technicznie, w przeciwnym razie jest w porządku. Aby wyjaśnić, w metodach przesłaniania zwracany typ może się zmienić (na podtyp), podczas gdy nie ma to miejsca w przypadku metod statycznych. Technicznie rzecz biorąc, „próba zastąpienia” nie ma zastosowania do metod statycznych, więc jedyne, co możemy powiedzieć, to to, że nie możemy.
sharhp
2

Ta koncepcja nie jest taka prosta, jak się wydaje. Możemy uzyskać dostęp do statycznych elementów członkowskich bez dziedziczenia, co jest relacją HasA. Możemy uzyskać dostęp do statycznych elementów członkowskich, rozszerzając również klasę nadrzędną. Nie oznacza to, że jest to relacja ISA (dziedziczenie). W rzeczywistości statyczne elementy członkowskie należą do klasy, a static nie jest modyfikatorem dostępu. Dopóki modyfikatory dostępu pozwalają na dostęp do statycznych elementów członkowskich, możemy ich używać w innych klasach. Na przykład jeśli jest publiczny, będzie dostępny w tym samym pakiecie, a także poza pakietem. Prywatnie nie możemy go nigdzie używać. Domyślnie możemy go używać tylko w pakiecie. Ale dla chronionych musimy przedłużyć superklasę. Zatem przeniesienie metody statycznej do innej klasy nie zależy od bycia statycznym. To zależy od modyfikatorów dostępu. Tak więc moim zdaniem Statyczne elementy członkowskie mogą uzyskać dostęp, jeśli pozwalają na to modyfikatory dostępu. W przeciwnym razie możemy ich używać tak, jak używamy w relacji Hasa. A związek nie jest dziedzictwem. Ponownie nie możemy przesłonić metody statycznej. Jeśli możemy użyć innej metody, ale nie możemy jej zastąpić, to jest to relacja HasA. Jeśli nie możemy ich zastąpić, nie będzie to dziedziczenie, więc autor miał 100% racji.

Noman_ibrahim
źródło
Rozszerzenie klasy nadrzędnej jest relacją typu „jest-a”. Jeśli dostęp jest prywatny, możesz go używać z poziomu zajęć. „protected” obejmuje klasy pochodne i klasy w bieżącym pakiecie. Za dużo błędów.
Markiz Lorne
0

Metoda statyczna jest dziedziczona w podklasie, ale nie jest to polimorfizm. Podczas pisania implementacji metody statycznej metoda klasy nadrzędnej jest ukryta, a nie nadpisana. Pomyśl, jeśli nie jest dziedziczony, jak możesz uzyskać dostęp bez classname.staticMethodname();?

user4016405
źródło
0

Wszyscy publiczni i chronieni członkowie mogą być dziedziczeni z dowolnej klasy, podczas gdy domyślni lub członkowie pakietu mogą być również dziedziczeni z klasy w tym samym pakiecie, co klasa nadrzędna. Nie zależy od tego, czy jest to element statyczny, czy niestatyczny.

Ale prawdą jest również, że statyczne funkcje składowe nie biorą udziału w dynamicznym wiązaniu. Jeśli sygnatura tej metody statycznej jest taka sama zarówno w klasie nadrzędnej, jak i podrzędnej, wówczas obowiązuje koncepcja cieniowania, a nie polimorfizmu.

shubham
źródło
0

Możesz przesłonić metody statyczne, ale jeśli spróbujesz użyć polimorfizmu, będą one działać zgodnie z zakresem klasy (w przeciwieństwie do tego, czego zwykle oczekujemy).

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();


    }


}

W pierwszym przypadku o / p jest "w statycznej metodzie B" # pomyślne zastąpienie W drugim przypadku o / p jest "w statycznej metodzie A" # Metoda statyczna - nie będzie uwzględniać polimorfizmu

Manav Garekar
źródło
-1

Możemy zadeklarować metody statyczne z tą samą sygnaturą w podklasie, ale nie jest to uważane za nadpisanie, ponieważ nie będzie żadnego polimorfizmu w czasie wykonywania, ponieważ wszystkie statyczne elementy członkowskie klasy są ładowane w momencie ładowania klasy, więc decyduje o kompilacji czas (nadpisywanie w czasie wykonywania) Dlatego odpowiedź brzmi „nie”.

NGK
źródło
2
Nie wiem, dlaczego ludzie zawsze głosują przeciw i nie podają powodu tego głosowania.
surajs1n
Ta odpowiedź dotyczy nadpisywania. Pytanie dotyczy dziedziczenia.
Markiz Lorne
-1

Wielu wyraziło swoją odpowiedź słowami. To jest rozszerzone wyjaśnienie w kodach:

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();

Wyniki:

A
B

Test
Test

A
B

Test
Test

A

A

Dlatego taki wniosek:

  1. Kiedy wywołujemy statyczną wartość statyczną za pośrednictwem., Będzie szukać wartości statycznej zdefiniowanej w tej klasie lub najbliższej klasie w łańcuchu dziedziczenia. Dowodzi to dziedziczenia metod statycznych.
  2. Gdy metoda statyczna jest wywoływana z instancji, wywołuje metodę statyczną zdefiniowaną w typie czasu kompilacji.
  3. Metodę statyczną można wywołać z nullinstancji. Domyślam się, że kompilator użyje typu zmiennej do znalezienia klasy podczas kompilacji i przetłumaczy to na odpowiednie wywołanie metody statycznej.
Jai
źródło
1
Zwykły kod nie jest wyjaśnieniem, to demonstracja. W odpowiedzi na to pytanie należy przytoczyć odniesienia normatywne, a nie tylko wykazywać zachowanie jakiejś nieokreślonej implementacji.
Markiz Lorne
-2

Członkowie statyczni są członkami uniwersalnymi. Dostęp do nich można uzyskać z dowolnego miejsca.

Pavan
źródło
4
można uzyskać dostęp z dowolnego miejsca, przyjmując dosłownie, to źle: statyczny! = zasięg. możesz chcieć wyjaśnić :-)
kleopatra
Właściwie ta odpowiedź jest w porządku, jeśli wziąć ją dosłownie. Nie przychodzi mi do głowy żadne miejsce w kodzie, w którym mógłby znaleźć się kod, w którym nie można uzyskać dostępu do statycznego elementu klasy. Możesz uzyskać do nich dostęp w statycznych inicjatorach, statycznych konstruktorach, konstruktorach wystąpień, metodach, właściwościach, w różnych klasach, w dowolnym zakresie. Dopóki klasa i metoda statyczna są publiczne, można uzyskać do nich dostęp z dowolnego miejsca, przy założeniu, że nie ma cyklicznych zależności od statycznych inicjatorów. W istocie statyczne elementy członkowskie nie są dziedziczone, są po prostu metodami na poziomie klasy (tj. Uniwersalnymi), które są dostępne z dowolnego miejsca.
Triynko
@Triynko Odpowiedź jest nieprawidłowa w przypadku metod, które są prywatne lub chronione pakietem, do których dostęp jest spoza pakietu.
Markiz Lorne
@kleopatra - off topic. huśtawka java? czy ludzie faktycznie tego używają w dzisiejszych czasach?
MasterJoe 2
@Pavan spróbuj wywołać private static spoza klasy. To nie zadziała.
Rakesh Yadav
-2

Statyczne elementy członkowskie nie zostaną odziedziczone do podklasy, ponieważ dziedziczenie dotyczy tylko niestatycznych elementów członkowskich. Statyczne elementy członkowskie zostaną załadowane do puli statycznej przez program ładujący klasy. Dziedziczenie dotyczy tylko tych elementów, które są ładowane wewnątrz obiektu

Ashwini E.
źródło
Całkowicie niepoprawne. Zobacz JLS # 8.4.8 .
Markiz Lorne