Dlaczego Java nie pozwala na przesłonięcie metod statycznych?


534

Dlaczego nie można zastąpić metod statycznych?

Jeśli to możliwe, skorzystaj z przykładu.


3
Większość języków OOP na to nie pozwala.
jmucchiello

7
@jmucchiello: zobacz moją odpowiedź. Myślałem tak samo jak ty, ale potem poznałem metody klasy „Ruby / Smalltalk”, a więc istnieją inne prawdziwe języki OOP, które to robią.
Kevin Brock

5
@jmucchiello większość języków OOP nie jest prawdziwym językiem OOP (myślę o Smalltalk)
mathk


1
być może dlatego, że Java rozpoznaje wywołania metod statycznych w czasie kompilacji. Więc nawet jeśli napisałeś, Parent p = new Child()a następnie p.childOverriddenStaticMethod()kompilator rozwiąże to Parent.childOverriddenStaticMethod(), patrząc na typ odwołania.
Manoj

Odpowiedzi:


494

Przesłonięcie zależy od wystąpienia instancji klasy. Polimorfizm polega na tym, że można podklasować klasę, a obiekty implementujące te podklasy będą miały różne zachowania dla tych samych metod zdefiniowanych w nadklasie (i zastąpionych w podklasach). Metoda statyczna nie jest powiązana z żadnym wystąpieniem klasy, więc koncepcja nie ma zastosowania.

Wpłynęły na to dwie kwestie związane z projektem Javy. Jednym z nich była obawa związana z wydajnością: pojawiła się duża krytyka Smalltalk, ponieważ jest on zbyt wolny (zbieranie śmieci i wywołania polimorficzne są tego częścią), a twórcy Javy byli zdeterminowani, aby tego uniknąć. Kolejną decyzją było to, że docelowymi odbiorcami Javy byli programiści C ++. Sprawienie, by metody statyczne działały w ten sam sposób, co dla programistów C ++, a także bardzo szybkie, ponieważ nie trzeba czekać do czasu wykonania, aby ustalić, którą metodę wywołać.


18
... ale tylko „poprawne” w Javie. Na przykład odpowiednik Scali dla „klas statycznych” (które są nazywane objects) pozwala na przeładowanie metod.

32
Cel C pozwala również na przesłonięcie metod klasowych.
Richard,

11
Istnieje hierarchia typów w czasie kompilacji i hierarchia typów w czasie wykonywania. Zrozumiałe jest pytanie, dlaczego statyczne wywołanie metody nie korzysta z hierarchii typów w czasie wykonywania w tych okolicznościach, w których takie istnieją. W Javie dzieje się tak podczas wywoływania metody statycznej z obiektu ( obj.staticMethod()) - co jest dozwolone i wykorzystuje typy czasu kompilacji. Gdy wywołanie statyczne jest metodą niestatyczną klasy, obiekt „bieżący” może być typem pochodnym klasy - ale metody statyczne zdefiniowane na typach pochodnych nie są brane pod uwagę (są w typie wykonawczym hierarchia).
Steve Powell,

18
Powinienem jasno: to jest nie prawda, że pojęcie to nie dotyczy .
Steve Powell,

13
Ta odpowiedź, choć poprawna, jest bardziej zbliżona do „jaka jest”, a nie do tego, jak powinna być, a dokładniej, w jaki sposób może być, aby spełnić oczekiwania PO, a zatem i mnie i innych. Nie ma konkretnego powodu, aby nie dopuszczać przesłonięcia metod statycznych innych niż „właśnie tak”. Myślę, że to osobista wada.
RichieHH

186

Osobiście uważam, że jest to wada w projektowaniu Javy. Tak, tak, rozumiem, że metody niestatyczne są dołączone do instancji, podczas gdy metody statyczne są dołączone do klasy itp. Mimo to rozważ następujący kod:

public class RegularEmployee {
    private BigDecimal salary;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }

    public BigDecimal calculateBonus() {
        return salary.multiply(getBonusMultiplier());
    }

    /* ... presumably lots of other code ... */
}

public class SpecialEmployee extends RegularEmployee {
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

Ten kod nie będzie działać zgodnie z oczekiwaniami. Mianowicie SpecialEmployee otrzymuje 2% premii, tak jak zwykli pracownicy. Ale jeśli usuniesz „statyczne”, SpecialEmployee dostanie 3% premii.

(Trzeba przyznać, że ten przykład jest kiepskim stylem kodowania, ponieważ w rzeczywistości prawdopodobnie powinieneś chcieć, aby mnożnik premii znajdował się gdzieś w bazie danych, a nie na stałe. Ale to tylko dlatego, że nie chciałem zbytnio bagatelizować przykładu kodu nieistotnego dla sprawy).

Wydaje mi się całkiem prawdopodobne, że możesz ustawić statyczny getBonusMultiplier. Być może chcesz mieć możliwość wyświetlenia mnożnika premii dla wszystkich kategorii pracowników, bez konieczności posiadania instancji pracownika w każdej kategorii. Po co szukać takich przykładów? Co jeśli tworzymy nową kategorię pracowników i nie mamy jeszcze do niej żadnych pracowników? Jest to całkiem logiczna funkcja statyczna.

Ale to nie działa.

I tak, tak, mogę wymyślić dowolną liczbę sposobów przepisania powyższego kodu, aby działał. Nie chodzi mi o to, że stwarza to nierozwiązywalny problem, ale że tworzy pułapkę dla nieostrożnego programisty, ponieważ język nie zachowuje się tak, jak sądzę, że rozsądna osoba by się spodziewała.

Być może gdybym próbował napisać kompilator dla języka OOP, szybko zrozumiałbym, dlaczego implementacja go w celu zastąpienia funkcji statycznych byłaby trudna lub niemożliwa.

A może jest jakiś dobry powód, dla którego Java zachowuje się w ten sposób. Czy ktoś może wskazać zaletę tego zachowania, jakąś kategorię problemu, który jest przez to łatwiejszy? Mam na myśli, nie kieruj mnie tylko do specyfikacji języka Java i powiedz „patrz, to jest udokumentowane, jak się zachowuje”. Wiem to. Ale czy istnieje dobry powód, dla którego POWINIEN się tak zachowywać? (Poza oczywistym „poprawnym działaniem było zbyt trudne” ...)

Aktualizacja

@VicKirk: Jeśli masz na myśli, że jest to „zły projekt”, ponieważ nie pasuje do tego, jak Java obsługuje statykę, moja odpowiedź brzmi: „No cóż, oczywiście.” Jak powiedziałem w moim oryginalnym poście, to nie działa. Ale jeśli masz na myśli, że jest to zły projekt w tym sensie, że byłoby coś zasadniczo nie tak z językiem, w którym to działało, tj. Gdzie statyka mogłaby zostać zastąpiona tak jak funkcje wirtualne, że to w jakiś sposób wprowadziłoby dwuznaczność lub byłoby niemożliwe wydajnie wdrażać lub niektóre takie, odpowiadam: „Dlaczego? Co jest nie tak z tą koncepcją?”

Myślę, że podany przeze mnie przykład jest bardzo naturalny. Mam klasę, która ma funkcję, która nie zależy od danych instancji i którą bardzo rozsądnie chcę wywoływać niezależnie od instancji, a także chcę wywoływać z poziomu metody instancji. Dlaczego to nie powinno działać? Przez lata spotkałem się z tą sytuacją dość często. W praktyce omijam ją, tworząc funkcję wirtualną, a następnie tworząc metodę statyczną, której jedynym celem w życiu jest metoda statyczna, która przekazuje wywołanie do metody wirtualnej za pomocą fałszywej instancji. To wydaje się być bardzo prostym sposobem na dotarcie tam.


11
@Bemrose: Ale o to mi chodzi: dlaczego nie mam na to pozwolić? Być może moja intuicyjna koncepcja tego, co powinien robić „statyczny”, różni się od twojej, ale w zasadzie myślę o statycznej jako metodzie, która MOŻE być statyczna, ponieważ nie używa żadnych danych instancji i która POWINNA być statyczna, ponieważ możesz chcieć wywoływać to niezależnie od instancji. Statyczny jest wyraźnie powiązany z klasą: Oczekuję, że Integer.valueOf będzie powiązany z Integers, a Double.valueOf będzie powiązany z Doubles.
Jay

9
@ewernli & Bemrose: Tak, tak to jest. Nie dyskutuję o tym. Ponieważ kod w moim przykładzie nie działa, oczywiście nie próbowałbym go napisać. Moje pytanie brzmi: dlaczego tak jest. (Obawiam się, że przerodzi się to w jedną z tych rozmów, w których po prostu się nie komunikujemy. „Przepraszam, sprzedawca, czy mogę dostać jedną z nich na czerwono?” „Nie, to kosztuje 5 USD.” „Tak, wiem, że to kosztuje 5 USD, ale czy mogę dostać czerwony? ”„ Sir, właśnie powiedziałem, że kosztuje 5 USD. ”„ Ok, znam cenę, ale pytałem o kolor. ”„ Już powiedziałem ci cenę! ” itp.)
Jay

6
Myślę, że ostatecznie ten kod jest mylący. Zastanów się, czy instancja jest przekazywana jako parametr. Następnie mówisz, że instancja środowiska wykonawczego powinna dyktować, która metoda statyczna jest wywoływana. To w zasadzie sprawia, że ​​cała osobna hierarchia jest równoległa do istniejącej instancji. Co teraz, jeśli podklasa definiuje tę samą sygnaturę metody co niestatyczna? Myślę, że zasady skomplikowałyby sprawę. Właśnie tego rodzaju komplikacje językowe próbuje unikać Java.
Yishai,

6
@Yishai: RE „Instancja wykonawcza określa, która metoda statyczna jest nazywana”: Dokładnie. Nie rozumiem, dlaczego nie można nic zrobić statycznie, co można zrobić za pomocą wirtualnego. „Oddzielna hierarchia”: Powiedziałbym: uczyń ją częścią tej samej hierarchii. Dlaczego statyka nie jest objęta tą samą hierarchią? „Podklasa definiuje ten sam podpis, który nie jest statyczny”: Zakładam, że byłoby to nielegalne, tak jak byłoby nielegalne, powiedzmy, nadpisywanie podklasy funkcji o identycznym podpisie, ale o innym typie zwracania, lub nie odrzucanie wszystkich wyjątków, które rodzic rzuca lub ma węższy zakres.
Jay

28
Myślę, że Jay ma rację - zaskoczyło mnie również, gdy odkryłem, że statyki nie można zastąpić. Po części dlatego, że jeśli mam A z metodą, someStatic()a B rozszerza A, to B.someMethod() wiąże się z metodą w A. Jeśli następnie dodam someStatic()do B, kod wywołujący nadal wywołuje się, A.someStatic()dopóki nie skompiluję kodu wywołującego. Zaskoczyło mnie również, że bInstance.someStatic()używa zadeklarowanego typu bInstance, a nie typu środowiska wykonawczego, ponieważ wiąże się przy kompilacji, a nie z linkiem, dlatego A bInstance; ... bInstance.someStatic()wywołuje A.someStatic (), jeśli B.someStatic () istnieje.
Lawrence Dol

42

Krótka odpowiedź brzmi: jest to całkowicie możliwe, ale Java tego nie robi.

Oto kod ilustrujący obecny stan rzeczy w Javie:

Plik Base.java:

package sp.trial;
public class Base {
  static void printValue() {
    System.out.println("  Called static Base method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Base method.");
  }
  void nonLocalIndirectStatMethod() {
    System.out.println("  Non-static calls overridden(?) static:");
    System.out.print("  ");
    this.printValue();
  }
}

Plik Child.java:

package sp.trial;
public class Child extends Base {
  static void printValue() {
    System.out.println("  Called static Child method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Child method.");
  }
  void localIndirectStatMethod() {
    System.out.println("  Non-static calls own static:");
    System.out.print("  ");
    printValue();
  }
  public static void main(String[] args) {
    System.out.println("Object: static type Base; runtime type Child:");
    Base base = new Child();
    base.printValue();
    base.nonStatPrintValue();
    System.out.println("Object: static type Child; runtime type Child:");
    Child child = new Child();
    child.printValue();
    child.nonStatPrintValue();
    System.out.println("Class: Child static call:");
    Child.printValue();
    System.out.println("Class: Base static call:");
    Base.printValue();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
    child.localIndirectStatMethod();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
    child.nonLocalIndirectStatMethod();
  }
}

Jeśli uruchomisz to (zrobiłem to na komputerze Mac, z Eclipse, przy użyciu Java 1.6), otrzymasz:

Object: static type Base; runtime type Child.
  Called static Base method.
  Called non-static Child method.
Object: static type Child; runtime type Child.
  Called static Child method.
  Called non-static Child method.
Class: Child static call.
  Called static Child method.
Class: Base static call.
  Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
  Non-static calls own static.
    Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
  Non-static calls overridden(?) static.
    Called static Base method.

Tutaj jedynymi przypadkami, które mogą być niespodzianką (i których dotyczy pytanie), są pierwsze przypadki:

„Typ wykonawczy nie jest używany do określania, które metody statyczne są wywoływane, nawet jeśli są wywoływane za pomocą instancji obiektu ( obj.staticMethod()).”

i ostatni przypadek:

„Podczas wywoływania metody statycznej z metody obiektowej klasy wybrana metoda statyczna jest dostępna z samej klasy, a nie z klasy definiującej typ obiektu w czasie wykonywania.”

Wywołanie z instancją obiektu

Wywołanie statyczne jest rozwiązywane w czasie kompilacji, natomiast niestatyczne wywołanie metody jest rozwiązywane w czasie wykonywania. Zauważ, że chociaż metody statyczne są dziedziczone (od rodzica), nie są one zastępowane (przez dziecko). To może być niespodzianka, jeśli spodziewałeś się inaczej.

Wywołanie z metody obiektowej

Wywołania metod obiektowych są rozwiązywane przy użyciu typu środowiska wykonawczego, ale wywołania metod statycznych ( klasy ) są rozwiązywane przy użyciu typu deklarowanego (czas kompilacji).

Zmiana zasad

Aby zmienić te reguły, tak aby ostatnie wywołanie w podanym przykładzie wywoływało Child.printValue()wywołanie statyczne z typem w czasie wykonywania, zamiast kompilatora rozstrzygającego wywołanie w czasie kompilacji z zadeklarowaną klasą obiektu (lub kontekst). Wywołania statyczne mogłyby następnie użyć (dynamicznej) hierarchii typów do rozwiązania wywołania, podobnie jak obecnie wywoływane są metody obiektowe.

Byłoby to łatwo wykonalne (gdybyśmy zmienili Javę: -O) i wcale nie jest nieuzasadnione, ma jednak kilka interesujących względów.

Główną kwestią jest to, że musimy zdecydować, które wywołania metod statycznych powinny to zrobić.

W tej chwili Java ma to „dziwactwo” w języku, w którym obj.staticMethod()połączenia są zastępowane przez ObjectClass.staticMethod()połączenia (zwykle z ostrzeżeniem). [ Uwaga: ObjectClass jest to typ kompilacji w czasie obj.] Byliby to dobrzy kandydaci do zastąpienia w ten sposób, biorąc pod uwagę typ wykonania w czasie wykonywania obj.

Gdybyśmy to zrobili, utrudniłoby to odczytanie treści metod: wywołania statyczne w klasie nadrzędnej mogłyby potencjalnie zostać dynamicznie „przekierowane”. Aby tego uniknąć, musielibyśmy wywołać metodę statyczną z nazwą klasy - a to sprawia, że ​​wywołania są bardziej oczywiste w przypadku hierarchii typów czasu kompilacji (jak teraz).

Inne sposoby wywoływania metody statycznej są trudniejsze: this.staticMethod()powinny oznaczać to samo, co obj.staticMethod()w przypadku wykonania w czasie wykonywania this. Może to jednak powodować pewne problemy z istniejącymi programami, które wywołują (najwyraźniej lokalne) metody statyczne bez dekoracji (co prawdopodobnie jest równoważne this.method()).

A co z niechcianymi połączeniami staticMethod()? Sugeruję, aby robili to samo co dzisiaj i używali lokalnego kontekstu klasowego, aby decydować, co robić. W przeciwnym razie nastąpiłoby wielkie zamieszanie. Oczywiście oznacza to, że method()oznaczałoby to, this.method()gdyby methodbyła to metoda niestatyczna, a ThisClass.method()gdyby methodbyła to metoda statyczna. To kolejne źródło zamieszania.

Inne uwagi

Jeśli zmieniliśmy to zachowanie (i wykonane połączenia statyczne potencjalnie dynamicznie non-local), prawdopodobnie chcesz ponownie sens final, privatea protectedjako kwalifikatorów na staticmetodach klasy. Wówczas wszyscy musielibyśmy przyzwyczaić się do faktu, że metody private statici public finalnie są nadpisywane, a zatem mogą być bezpiecznie rozwiązane w czasie kompilacji i są „bezpieczne” do odczytania jako lokalne odniesienia.


„Gdybyśmy to zrobili, utrudniłoby to odczytanie treści metod: wywołania statyczne w klasie nadrzędnej mogłyby potencjalnie zostać dynamicznie„ przekierowane ”.” To prawda, ale właśnie to dzieje się teraz ze zwykłymi, niestatycznymi wywołaniami funkcji. Jest to rutynowo reklamowane jako pozytywna cecha zwykłych funkcji wirtualnych, a nie problem.
Jay

25

Właściwie się myliliśmy.
Mimo że Java domyślnie nie pozwala na przesłonięcie metod statycznych, jeśli dokładnie przejrzysz dokumentację klas Class i Method w Javie, nadal możesz znaleźć sposób na emulowanie metod statycznych zastępujących, stosując następujące obejście:

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;

class RegularEmployee {

    private BigDecimal salary = BigDecimal.ONE;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }
    public BigDecimal calculateBonus() {
        return salary.multiply(this.getBonusMultiplier());
    }
    public BigDecimal calculateOverridenBonus() {
        try {
            // System.out.println(this.getClass().getDeclaredMethod(
            // "getBonusMultiplier").toString());
            try {
                return salary.multiply((BigDecimal) this.getClass()
                    .getDeclaredMethod("getBonusMultiplier").invoke(this));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
    // ... presumably lots of other code ...
}

final class SpecialEmployee extends RegularEmployee {

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

public class StaticTestCoolMain {

    static public void main(String[] args) {
        RegularEmployee Alan = new RegularEmployee();
        System.out.println(Alan.calculateBonus());
        System.out.println(Alan.calculateOverridenBonus());
        SpecialEmployee Bob = new SpecialEmployee();
        System.out.println(Bob.calculateBonus());
        System.out.println(Bob.calculateOverridenBonus());
    }
}

Wynikowy wynik:

0.02
0.02
0.02
0.03

co próbowaliśmy osiągnąć :)

Nawet jeśli zadeklarujemy trzecią zmienną Carl jako RegularEmployee i przypiszemy do niej instancję SpecialEmployee, nadal będziemy mieli wywołanie metody RegularEmployee w pierwszym przypadku i wywołanie metody SpecialEmployee w drugim przypadku

RegularEmployee Carl = new SpecialEmployee();

System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());

wystarczy spojrzeć na konsolę wyjściową:

0.02
0.03

;)


9
Tak, odbicie jest właściwie jedyną rzeczą, którą można zrobić - ale pytanie nie jest dokładnie takie - przydatne, aby mieć ją tutaj
Mr_and_Mrs_D

1
Ta odpowiedź to największy hack, jaki widziałem do tej pory we wszystkich tematach Java. Fajnie było czytać to jeszcze :)
Andrejs

19

Metody statyczne są traktowane przez JVM jako globalne, w ogóle nie są powiązane z instancją obiektu.

Koncepcyjnie byłoby to możliwe, gdybyś mógł wywoływać metody statyczne z obiektów klasy (jak w językach takich jak Smalltalk), ale nie jest tak w Javie.

EDYTOWAĆ

Możesz przeładować metodę statyczną, w porządku. Ale nie można przesłonić metody statycznej, ponieważ klasa nie jest obiektem pierwszej klasy. Można użyć odbicia, aby uzyskać klasę obiektu w czasie wykonywania, ale otrzymany obiekt nie jest równoległy do ​​hierarchii klas.

class MyClass { ... }
class MySubClass extends MyClass { ... }

MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();

ob2 instanceof MyClass --> true

Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();

clazz2 instanceof clazz1 --> false

Możesz zastanowić się nad klasami, ale na tym się kończy. Nie wywołujesz metody statycznej za pomocą clazz1.staticMethod(), ale za pomocą MyClass.staticMethod(). Metoda statyczna nie jest związana z przedmiotem, a zatem nie ma pojęcia thisani superw metodzie statycznej. Metoda statyczna jest funkcją globalną; w konsekwencji nie ma również pojęcia polimorfizmu, a zatem zastąpienie metody nie ma sensu.

Ale byłoby to możliwe, gdyby MyClassbył obiektem w czasie wykonywania, na którym wywołujesz metodę, tak jak w Smalltalk (lub może JRuby, jak sugeruje jeden komentarz, ale nic nie wiem o JRuby).

O tak ... jeszcze jedno. Możesz wywoływać metodę statyczną przez obiekt, obj1.staticMethod()ale ten naprawdę składniowy cukier jest MyClass.staticMethod()i należy go unikać. Zwykle wywołuje ostrzeżenie we współczesnym IDE. Nie wiem, dlaczego kiedykolwiek zezwolili na ten skrót.


5
Nawet wiele współczesnych języków, takich jak Ruby, ma metody klasowe i pozwala na ich przesłonięcie.
Chandra Sekar

3
Klasy istnieją w Javie jako obiekty. Zobacz klasę „Klasa”. Mogę powiedzieć myObject.getClass (), a zwróci mi instancję odpowiedniego obiektu klasy.
Jay

5
Otrzymujesz tylko „opis” klasy - nie samą klasę. Ale różnica jest subtelna.
ewernli

Nadal masz klasę, ale jest ona ukryta w maszynie wirtualnej (w pobliżu modułu ładującego klasy), użytkownik prawie nie ma do niej dostępu.
matem

Aby używać clazz2 instanceof clazz1poprawnie, możesz zamiast tego użyć class2.isAssignableFrom(clazz1), który moim zdaniem zwróciłby prawdę w twoim przykładzie.
Simon Forsberg

14

Nadpisywanie metod jest możliwe dzięki dynamicznemu wywoływaniu , co oznacza, że ​​zadeklarowany typ obiektu nie określa jego zachowania, a raczej jego typ środowiska wykonawczego:

Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"

Nawet jeśli oboje lassiei kermitdeklarowane są jako obiekty typu Animal, ich zachowanie (metoda .speak()) zmienia się z powodu dynamicznego dyspozytorni będą tylko wiązać wywołanie metody .speak()do realizacji w czasie wykonywania - nie w czasie kompilacji.

Oto, gdzie staticsłowo kluczowe zaczyna mieć sens: słowo „statyczny” jest antonimem słowa „dynamiczny”. Dlatego powodem, dla którego nie można przesłonić metod statycznych, jest to, że nie ma dynamicznego wysyłania elementów statycznych - ponieważ statyczny oznacza dosłownie „niedynamiczny”. Gdyby wysłali dynamicznie (a więc mogliby zostać zastąpieni), staticsłowo kluczowe po prostu nie miałoby sensu.


11

Tak. Praktycznie Java pozwala na przesłonięcie metody statycznej, i teoretycznie, jeśli przesłonisz metodę statyczną w Javie, wówczas kompiluje się i działa płynnie, ale straci polimorfizm, który jest podstawową właściwością Javy. Wszędzie przeczytasz, że nie można spróbować się skompilować i uruchomić. dostaniesz swoją odpowiedź. np. Jeśli masz klasę Animal i metodę statyczną eat () i przesłonisz tę metodę statyczną w jej podklasie, możesz ją nazwać Dog. Następnie, gdziekolwiek przypisujesz obiekt Dog do Animal Reference i wywołujesz eat () zgodnie z Java Dog's eat () powinno być wywoływane, ale w statycznym Overriding Animals's () zostanie wywołane.

class Animal {
    public static void eat() {
        System.out.println("Animal Eating");
    }
}

class Dog extends Animal{
    public static void eat() {
        System.out.println("Dog Eating");
    }
}

class Test {
    public static void main(String args[]) {
       Animal obj= new Dog();//Dog object in animal
       obj.eat(); //should call dog's eat but it didn't
    }
}


Output Animal Eating

Zgodnie z zasadą polimorfizmu Java, wynik powinien być Dog Eating.
Ale wynik był inny, ponieważ do obsługi polimorfizmu Java używa późnego wiązania, co oznacza, że ​​metody są wywoływane tylko w czasie wykonywania, ale nie w przypadku metod statycznych. W metodach statycznych kompilator wywołuje metody w czasie kompilacji, a nie w czasie wykonywania, więc otrzymujemy metody zgodnie z referencją, a nie z obiektem referencją zawierającą, dlatego można powiedzieć, że praktycznie obsługuje statyczne overring, ale teoretycznie nie „t.


3
Złą praktyką jest wywoływanie metod statycznych z obiektu.
Dmitry Zagorulkin

6

przesłonięcie jest zarezerwowane dla członków, aby wspierać zachowanie polimorficzne. członkowie klasy statycznej nie należą do określonej instancji. zamiast tego elementy statyczne należą do klasy, w wyniku czego nadpisywanie nie jest obsługiwane, ponieważ podklasy dziedziczą tylko elementy instancji chronionej i publicznej, a nie elementy statyczne. Możesz zdefiniować interfejs i fabrykę badawczą i / lub wzorce projektowe strategii w celu oceny alternatywnego podejścia.


1
Czy nie przeczytaliście żadnej innej odpowiedzi, która już to obejmuje i wyjaśniając, że nie są to wystarczające powody, aby pomijać nadrzędne statyki na poziomie koncepcyjnym. Wiemy, że to nie działa.
Żądanie zastąpienia

Richard, załóżmy na chwilę, że kiedy odpowiedziałem na to pytanie 4 lata temu większość z tych odpowiedzi nie została opublikowana, więc nie bądź dupkiem! Nie trzeba twierdzić, że nie czytałem uważnie. Ponadto, czy nie przeczytaliście, że omawiamy jedynie nadpisywanie w odniesieniu do Javy. Kogo obchodzi, co jest możliwe w innych językach. To nie ma znaczenia. Idź trollować gdzie indziej. Twój komentarz nie dodaje nic wartościowego do tego wątku.
Ateny Holloway

6

W Javie (i wielu językach OOP, ale nie mogę mówić za wszystkich, a niektóre w ogóle nie mają statycznego) wszystkie metody mają stałą sygnaturę - parametry i typy. W metodzie wirtualnej sugerowany jest pierwszy parametr: odwołanie do samego obiektu, a po wywołaniu z obiektu kompilator automatycznie dodaje this.

Nie ma różnicy w przypadku metod statycznych - wciąż mają one stały podpis. Jednak deklarując metodę statyczną, wyraźnie oświadczyłeś, że kompilator nie może zawierać domyślnego parametru obiektu na początku tej sygnatury. Dlatego żaden inny kod, który to wywołuje, nie może próbować umieszczać odwołania do obiektu na stosie . Gdyby to zrobił, wówczas wykonanie metody nie działałoby, ponieważ parametry byłyby w niewłaściwym miejscu - przesunięte o jeden - na stosie.

Z powodu tej różnicy między nimi; metody wirtualne zawsze mają odniesienie do obiektu kontekstu (tj. this), więc można odwoływać się do wszystkiego w stercie, które należy do tego wystąpienia obiektu. Jednak w przypadku metod statycznych, ponieważ nie przekazano odwołania, metoda ta nie może uzyskać dostępu do żadnych zmiennych obiektowych i metod, ponieważ kontekst nie jest znany.

Jeśli chcesz, aby Java zmieniła definicję, tak aby kontekst obiektowy był przekazywany dla każdej metody, statycznej lub wirtualnej, w istocie miałbyś tylko metody wirtualne.

Jak ktoś zapytał w komentarzu do op - jaki jest powód i cel, dla którego chcesz mieć tę funkcję?

Nie znam dużo Rubiego, ponieważ wspominał o tym PO, przeprowadziłem badania. Widzę, że w klasach Ruby są naprawdę szczególnym rodzajem obiektu i można tworzyć (nawet dynamicznie) nowe metody. Klasy są obiektami pełnej klasy w Rubim, nie są w Javie. Jest to po prostu coś, co musisz zaakceptować podczas pracy z Javą (lub C #). Nie są to języki dynamiczne, chociaż C # dodaje pewne formy dynamiczne. W rzeczywistości Ruby nie ma metod „statycznych”, o ile mogłem je znaleźć - w takim przypadku są to metody obiektu klasy singleton. Następnie możesz zastąpić ten singleton nową klasą, a metody w obiekcie poprzedniej klasy wywołają metody zdefiniowane w nowej klasie (prawda?). Więc jeśli wywołałeś metodę w kontekście oryginalnej klasy, nadal wykonałaby ona tylko oryginalną statykę, ale wywołanie metody w klasie pochodnej wywołałoby metody albo z nadrzędnej, albo z podklasy. Interesujące i widzę w tym pewną wartość. To wymaga innego wzorca myślenia.

Ponieważ pracujesz w Javie, musisz dostosować się do tego sposobu działania. Dlaczego to zrobili? Prawdopodobnie w celu poprawy wydajności w tym czasie w oparciu o dostępną technologię i zrozumienie. Języki komputerowe stale się rozwijają. Wróć wystarczająco daleko i nie ma czegoś takiego jak OOP. W przyszłości pojawią się inne nowe pomysły.

EDYCJA : Jeszcze jeden komentarz. Teraz, gdy widzę różnice i jako sam programista Java / C #, rozumiem, dlaczego odpowiedzi otrzymywane od programistów Java mogą być mylące, jeśli pochodzisz z języka takiego jak Ruby. staticMetody Java nie są takie same jak classmetody Ruby . Programiści Java będą mieli trudności ze zrozumieniem tego, podobnie jak ci, którzy pracują głównie z językiem takim jak Ruby / Smalltalk. Widzę, że byłoby to również bardzo mylące, ponieważ Java używa również „metody klasowej” jako innego sposobu mówienia o metodach statycznych, ale Ruby używa tego samego terminu. Java nie ma metod klasy w stylu Ruby (przepraszam); Ruby nie ma metod statycznych w stylu Java, które są tak naprawdę tylko starymi funkcjami w stylu proceduralnym, jak w C.

Przy okazji - dziękuję za pytanie! Nauczyłem się dzisiaj czegoś nowego o metodach klasowych (styl Ruby).


1
Oczywiście nie ma powodu, dla którego Java nie mogła przekazać obiektu „Class” jako parametru ukrytego do metod statycznych. Po prostu nie został do tego stworzony.
jmucchiello

6

Cóż ... odpowiedź brzmi NIE, jeśli myślisz z perspektywy, jak powinna być zachowana metoda zastępowana w Javie. Jednak przy próbie zastąpienia metody statycznej nie pojawia się błąd kompilatora. Oznacza to, że jeśli spróbujesz przesłonić, Java nie przestanie tego robić; ale z pewnością nie uzyskuje się takiego samego efektu jak w przypadku metod niestatycznych. Przesłonięcie w Javie oznacza po prostu, że konkretna metoda zostanie wywołana na podstawie typu wykonania obiektu, a nie jego typu kompilacji (co ma miejsce w przypadku przesłoniętych metod statycznych). Okej ... jakieś domysły z tego powodu, dlaczego zachowują się dziwnie? Ponieważ są to metody klasowe, dlatego dostęp do nich jest zawsze rozwiązywany w czasie kompilacji tylko przy użyciu informacji o typie czasu kompilacji.

Przykład : spróbujmy zobaczyć, co się stanie, jeśli spróbujemy przesłonić metodę statyczną: -

class SuperClass {
// ......
public static void staticMethod() {
    System.out.println("SuperClass: inside staticMethod");
}
// ......
}

public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
    System.out.println("SubClass: inside staticMethod");
}

// ......
public static void main(String[] args) {
    // ......
    SuperClass superClassWithSuperCons = new SuperClass();
    SuperClass superClassWithSubCons = new SubClass();
    SubClass subClassWithSubCons = new SubClass();

    superClassWithSuperCons.staticMethod();
    superClassWithSubCons.staticMethod();
    subClassWithSubCons.staticMethod();
    // ...
}
}

Wyjście : -
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

Zwróć uwagę na drugi wiersz wyniku. Gdyby staticMethod zostało zastąpione, linia ta powinna być identyczna z linią trzecią, ponieważ wywołujemy funkcję „staticMethod ()” na obiekcie typu Runtime Type jako „SubClass”, a nie jako „SuperClass”. Potwierdza to, że metody statyczne są zawsze rozwiązywane przy użyciu wyłącznie informacji o typie czasu kompilacji.


5

Zasadniczo nie ma sensu zezwalanie na „zastępowanie” metod statycznych, ponieważ nie byłoby dobrego sposobu ustalenia, która z nich ma zostać wywołana w czasie wykonywania. Biorąc przykład pracownika, jeśli wywołamy RegularEmployee.getBonusMultiplier () - która metoda ma zostać wykonana?

W przypadku Javy można sobie wyobrazić definicję języka, w której można „przesłonić” metody statyczne, o ile są one wywoływane przez instancję obiektu. Jednak wystarczyłoby to ponownie wdrożyć metody klasowe, dodając nadmiarowość do języka bez żadnych dodatkowych korzyści.


2
Intuicyjnie sądzę, że powinien on działać tak jak funkcja wirtualna. Jeśli B rozszerza A, a zarówno A, jak i B mają funkcje wirtualne o nazwie doStuff, kompilator wie, że instancje A powinny używać A.doStuff, a instancje B powinny używać B.doStuff. Dlaczego nie może zrobić tego samego z funkcjami statycznymi? W końcu kompilator wie, jakiej klasy jest instancja każdego obiektu.
Jay

Eee ... Jay, metoda statyczna nie musi być (generalnie nie jest) wywoływana w instancji ...
meriton

2
@meriton, ale to jeszcze łatwiejsze, nie? Jeśli wywoływana jest metoda statyczna przy użyciu nazwy klasy, należy użyć metody odpowiedniej dla klasy.
CPerkins

Ale to, co jest nadrzędne, robi dla ciebie. Jeśli wywołasz A.doStuff (), należy użyć wersji, która została zastąpiona w „B rozszerza A” lub wersji, która została zastąpiona w „C rozszerza A”. A jeśli masz C lub B, to i tak wywołujesz te wersje ... nie ma potrzeby zastępowania.
PSpeed,

@meriton: Prawdą jest, że metoda statyczna na ogół nie jest wywoływana z instancją, ale przypuszczam, że jest tak, ponieważ takie wywołanie nie robi nic użytecznego, biorąc pod uwagę obecny projekt Java! Sugeruję, że alternatywny projekt mógłby być lepszym pomysłem. BTW, w bardzo realnym sensie funkcje statyczne są wywoływane z instancją dość rutynowo: Kiedy wywołujesz funkcję statyczną z funkcji wirtualnej. Następnie domyślnie otrzymujesz this.function (), tj. Bieżącą instancję.
Jay

5

Przez przesłonięcie możemy stworzyć naturę polimorficzną w zależności od typu obiektu. Metoda statyczna nie ma związku z przedmiotem. Dlatego Java nie może obsługiwać zastępowania metod statycznych.


5

Lubię i podwajam komentarz Jaya ( https://stackoverflow.com/a/2223803/1517187 ).
Zgadzam się, że jest to zły projekt Java.
Wiele innych języków obsługuje nadpisywanie metod statycznych, jak widzimy w poprzednich komentarzach. Czuję, że Jay również przyszedł na Javę z Delphi, tak jak ja.
Delphi (Object Pascal) był pierwszym językiem implementującym OOP.
Oczywistym jest, że wiele osób miało doświadczenie z tym językiem, ponieważ w przeszłości był to jedyny język, w którym pisano komercyjne produkty GUI. I - tak, moglibyśmy w Delphi zastąpić metody statyczne. W rzeczywistości metody statyczne w Delphi są nazywane „metodami klasowymi”, podczas gdy Delphi ma inną koncepcję „metod statycznych Delphi”, które były metodami z wczesnym wiązaniem. Aby zastąpić metody, trzeba było użyć późnego wiązania, zadeklarować dyrektywę „wirtualną”. Było to więc bardzo wygodne i intuicyjne i oczekiwałbym tego w Javie.


3

Co dobrego zrobi, aby zastąpić metody statyczne. Nie można wywoływać metod statycznych za pośrednictwem instancji.

MyClass.static1()
MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.

EDYCJA: Wygląda na to, że przez niefortunny niedopatrzenie w projektowaniu języka można wywoływać metody statyczne za pomocą instancji. Generalnie nikt tego nie robi. Mój błąd.


8
„Nie można wywoływać metod statycznych za pośrednictwem instancji” W rzeczywistości jednym z dziwactw Javy jest to, że MOŻNA wywoływać metody statyczne za pomocą instancji, nawet jeśli jest to wyjątkowo zły pomysł.
Władca

1
Rzeczywiście Java umożliwia dostęp do elementów statycznych za pośrednictwem instancji: patrz Zmienna statyczna w Javie
Richard JP Le Guen

Właściwe nowoczesne IDE wygeneruje ostrzeżenie, gdy to zrobisz, więc przynajmniej możesz je złapać, podczas gdy Oracle może zachować zgodność z poprzednimi wersjami.
Gimby

1
Nie ma nic koncepcyjnie złego w możliwości wywołania metody statycznej za pomocą instancji. To sprzeczanie się ze względu na sprzeczki. Dlaczego coś takiego jak instancja Date NIE powinna wywoływać własnych metod statycznych, przekazując dane instancji do funkcji przez interfejs wywołujący?
RichieHH

@RichieHH Nie o to się spierają. Pytanie brzmi, dlaczego wolno wywoływać variable.staticMethod()zamiast Class.staticMethod(), gdzie variablejest zmienną o zadeklarowanym typie Class. Zgadzam się, że to zły projekt językowy.
fishinear

3

Przesłonięcie w Javie oznacza po prostu, że określona metoda zostanie wywołana na podstawie typu środowiska wykonawczego obiektu, a nie na podstawie typu kompilacji (co ma miejsce w przypadku przesłoniętych metod statycznych). Ponieważ metody statyczne są metodami klasowymi, nie są to metody instancji, więc nie mają one nic wspólnego z faktem, które odniesienie wskazuje na który Obiekt lub instancję, ponieważ ze względu na naturę metody statycznej należy do konkretnej klasy. Możesz zmienić go w podklasie, ale ta podklasa nie będzie wiedziała nic o metodach statycznych klasy nadrzędnej, ponieważ, jak powiedziałem, jest specyficzna tylko dla tej klasy, w której została zadeklarowana. Dostęp do nich za pomocą odwołań do obiektów jest tylko dodatkową swobodą przyznaną przez projektantów Java i z pewnością nie powinniśmy myśleć o zaprzestaniu tej praktyki tylko wtedy, gdy ograniczają ją więcej szczegółów i przykładów http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html


3

Przez nadpisanie osiągasz dynamiczny polimorfizm. Kiedy mówisz, że zastępujesz metody statyczne, słowa, których próbujesz użyć, są sprzeczne.

Statyczny mówi - czas kompilacji, nadpisywanie jest używane do dynamicznego polimorfizmu. Oba są z natury przeciwne i dlatego nie można ich używać razem.

Dynamiczne zachowanie polimorficzne pojawia się, gdy programista używa obiektu i uzyskuje dostęp do metody instancji. JRE odwzorowuje różne metody instancji różnych klas w oparciu o rodzaj używanego obiektu.

Kiedy mówisz, że zastępujesz metody statyczne, do metod statycznych uzyskamy dostęp przy użyciu nazwy klasy, która zostanie połączona w czasie kompilacji, więc nie ma koncepcji łączenia metod w środowisku wykonawczym z metodami statycznymi. Sam termin „przesłanianie” metod statycznych nie ma więc żadnego znaczenia.

Uwaga: nawet jeśli uzyskasz dostęp do metody klasy za pomocą obiektu, nadal kompilator Java jest wystarczająco inteligentny, aby go znaleźć, i wykona statyczne łączenie.


Nie jest to prawdą w wielu przypadkach, w których w czasie wykonywania metoda statyczna jest w rzeczywistości wywoływana z instancji klasy zawierającej, a zatem możliwe jest określenie, które instancje funkcji mają zostać wywołane.
RichieHH

statyczny nie oznacza czasu kompilacji, statyczny oznacza, że ​​jest on związany z klasą, a nie z jakimkolwiek konkretnym obiektem. ma to tyle samo, jeśli nie więcej sensu niż tworzenie fabryki klas, z wyjątkiem tego, że statyczny Box.createBoxma więcej sensu BoxFactory.createBoxi jest nieuniknionym wzorcem, gdy trzeba sprawdzić błąd konstrukcji bez zgłaszania wyjątków (konstruktory nie mogą zawieść, mogą jedynie zabić proces / rzut) wyjątek), podczas gdy metoda statyczna może zwrócić wartość NULL w przypadku niepowodzenia lub nawet zaakceptować wywołania zwrotne sukcesu / błędu, aby napisać coś takiego jak hastebin.com/codajahati.java .
Dmitry

2

Odpowiedź na to pytanie jest prosta, metoda lub zmienna oznaczona jako statyczna należy tylko do klasy, więc tej metody statycznej nie można dziedziczyć w podklasie, ponieważ należą one tylko do superklasy.


1
Cześć G4uKu3_Gaurav. Dziękuję za decyzję. Jednak generalnie oczekujemy dłuższych i bardziej szczegółowych odpowiedzi niż to.
DJClayworth

@DJClayworth powinieneś skorzystać z tego linku, aby uzyskać szczegółową odpowiedź geeksforgeeks.org/…
g1ji

Dzięki za link. Właściwie jestem tutaj, aby pomóc początkującym w witrynie, aby wyjaśnić, jak działa strona dla tych, którzy nie są do niej przyzwyczajeni, nie dlatego, że potrzebowałem odpowiedzi na pytanie.
DJClayworth

1

Proste rozwiązanie: użyj instancji singleton. Pozwoli to na zastąpienia i dziedziczenie.

W moim systemie mam klasę SingletonsRegistry, która zwraca instancję dla przekazanej klasy. Jeśli instancja nie zostanie znaleziona, zostanie utworzona.

Klasa językowa Haxe:

package rflib.common.utils;
import haxe.ds.ObjectMap;



class SingletonsRegistry
{
  public static var instances:Map<Class<Dynamic>, Dynamic>;

  static function __init__()
  {
    StaticsInitializer.addCallback(SingletonsRegistry, function()
    {
      instances = null;
    });

  } 

  public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
  {
    if (instances == null) {
      instances = untyped new ObjectMap<Dynamic, Dynamic>();      
    }

    if (!instances.exists(cls)) 
    {
      if (args == null) args = [];
      instances.set(cls, Type.createInstance(cls, args));
    }

    return instances.get(cls);
  }


  public static function validate(inst:Dynamic, cls:Class<Dynamic>)
  {
    if (instances == null) return;

    var inst2 = instances[cls];
    if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it's singleton!";
  }

}

Bardzo fajnie, po raz pierwszy usłyszałem o języku programowania Haxe :)
cyc115

1
Jest to znacznie lepiej zaimplementowane w Javie jako metoda statyczna na samej klasie; Singleton.get(). Rejestr jest po prostu narzutem nad głową i wyklucza GC w klasach.
Lawrence Dol

Masz rację, to klasyczne rozwiązanie. Nie pamiętam dokładnie, dlaczego wybrałem rejestr, prawdopodobnie miałem pewne przemyślenia, które doprowadziły do ​​tego wyniku.
Raivo Fishmeister,

1

Metoda statyczna, zmienna, blokowa lub zagnieżdżona należy do całej klasy a nie do obiektu.

Metoda w Javie służy do ujawnienia zachowania obiektu / klasy. Tutaj, ponieważ metoda jest statyczna (tj. Metoda statyczna jest używana do reprezentowania zachowania tylko klasy). Zmiana / nadpisanie zachowania całej klasy naruszy zjawisko jednego z podstawowych filarów programowania obiektowego, tj. Wysoką spójność . (pamiętaj, że konstruktor jest specjalną metodą w Javie).

Wysoka spójność - jedna klasa powinna mieć tylko jedną rolę. Na przykład: klasa samochodów powinna produkować wyłącznie przedmioty samochodowe, a nie rowery, ciężarówki, samoloty itp. Ale klasa samochodów może mieć pewne cechy (zachowania), które należą tylko do siebie.

Dlatego podczas projektowania języka programowania Java. Projektanci języka pomyśleli, aby pozwolić programistom na zachowanie niektórych zachowań klasy tylko przez uczynienie metody statyczną z natury.


Poniższy kod fragmentu próbuje zastąpić metodę statyczną, ale nie napotka żadnego błędu kompilacji.

public class Vehicle {
static int VIN;

public static int getVehileNumber() {
    return VIN;
}}

class Car extends Vehicle {
static int carNumber;

public static int getVehileNumber() {
    return carNumber;
}}

Jest tak, ponieważ tutaj nie zastępujemy metody, ale po prostu ją deklarujemy . Java umożliwia ponowną deklarację metody (statyczna / niestatyczna).

Usunięcie słowa kluczowego static z metody getVehileNumber () klasy Car spowoduje błąd kompilacji, ponieważ staramy się zmienić funkcjonalność metody statycznej, która należy tylko do klasy Vehicle.

Ponadto, jeśli getVehileNumber () zostanie zadeklarowany jako końcowy, kod nie zostanie skompilowany, ponieważ ostatnie słowo kluczowe ogranicza programistę przed ponownym zadeklarowaniem metody.

public static final int getVehileNumber() {
return VIN;     }

Ogólnie rzecz biorąc, to zależy od projektantów oprogramowania, gdzie można zastosować metody statyczne. Osobiście wolę używać metod statycznych do wykonywania niektórych akcji bez tworzenia instancji klasy. Po drugie, aby ukryć zachowanie klasy przed światem zewnętrznym.


1

Oto proste wyjaśnienie. Metoda statyczna jest powiązana z klasą, podczas gdy metoda instancji jest powiązana z określonym obiektem. Przesłonięcia pozwalają na wywołanie innej implementacji przesłoniętych metod powiązanych z danym obiektem. Dlatego sprzeczne z intuicją jest zastępowanie metody statycznej, która nie jest nawet powiązana z obiektami, ale przede wszystkim z samą klasą. Tak więc metod statycznych nie można zastąpić na podstawie tego, który obiekt to wywołuje, zawsze będzie on powiązany z klasą, w której został utworzony.


W jaki sposób posiadanie public abstract IBox createBox();wewnętrznego interfejsu IBox jest sprzeczne z intuicją ? Box może zaimplementować IBox w celu zastąpienia createBox, a utworzenie obiektu spowoduje poprawny IBox, w przeciwnym razie zwróci wartość null. Konstruktorzy nie mogą zwracać wartości „null” i dlatego jesteś zmuszony (1) używać wyjątków WSZĘDZIE (co robimy teraz) lub (2) tworzyć klasy fabryczne, które robią to, co powiedziałem wcześniej, ale w sposób, który nie ma sensu dla nowicjuszy ani ekspertów Java (co również robimy teraz). Rozwiązują to statyczne niezaimplementowane metody.
Dmitry

-1

Widząc powyższe odpowiedzi, wszyscy wiedzą, że nie możemy przesłonić metod statycznych, ale nie należy źle rozumieć pojęcia dostępu do metod statycznych z podklasy .

Możemy uzyskać dostęp do metod statycznych superklasy z referencją do podklasy, jeśli ta metoda statyczna nie została ukryta przez nową metodę statyczną zdefiniowaną w podklasie.

Na przykład zobacz poniższy kod: -

public class StaticMethodsHiding {
    public static void main(String[] args) {
        SubClass.hello();
    }
}


class SuperClass {
    static void hello(){
        System.out.println("SuperClass saying Hello");
    }
}


class SubClass extends SuperClass {
    // static void hello() {
    // System.out.println("SubClass Hello");
    // }
}

Wynik:-

SuperClass saying Hello

Zobacz dokumentację Oracle Oracle i wyszukaj Co możesz zrobić w podklasie, aby uzyskać szczegółowe informacje na temat ukrywania metod statycznych w podklasie.

Dzięki


-3

Poniższy kod pokazuje, że jest to możliwe:

class OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriden Meth");   
}   

}   

public class OverrideStaticMeth extends OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriding Meth");   
}   

public static void main(String[] args) {   
OverridenStaticMeth osm = new OverrideStaticMeth();   
osm.printValue();   

System.out.println("now, from main");
printValue();

}   

} 

1
Nie, nie ma; statyczny deklarowany typ nie osmjest . OverridenStaticMethOverrideStaticMeth
Lawrence Dol

2
Ponadto starałbym się unikać używania tak dużej ilości Meth podczas programowania <big grin>;
Lawrence Dol
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.