Dlaczego Java nie pozwala na nadpisywanie metod statycznych?

Dlaczego nie można nadpisać metod statycznych?

Jeśli to możliwe, proszę użyć przykładu.

Author: Michael Myers, 2010-02-08

22 answers

Nadpisywanie zależy od posiadania 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 superklasie (i nadpisanych w podklasach). Metoda statyczna nie jest powiązana z żadną instancją klasy, więc pojęcie to nie ma zastosowania.

Wpływ na to miały dwa czynniki wpływające na projekt Javy. Jednym z nich była troska o wydajność: było wiele krytyki Smalltalk o to, że jest zbyt wolny (Garbage collection i polymorphic calls są częścią tego) i twórcy Javy byli zdeterminowani, aby tego uniknąć. Inną była decyzja, że grupą docelową dla Javy byli Programiści C++. Tworzenie metod statycznych w taki sposób miało tę zaletę, że były dobrze znane programistom C++ i było bardzo szybkie, ponieważ nie trzeba czekać do czasu uruchomienia, aby dowiedzieć się, którą metodę wywołać.

 502
Author: Nathan Hughes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-12 13:57:38

Osobiście uważam, że jest to wada w projektowaniu Javy. Tak, Tak, rozumiem, że metody niestatyczne są dołączane do instancji, podczas gdy metody statyczne są dołączane do klasy, itd. itd. 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ł tak, jak można się spodziewać. Mianowicie, pracownicy specjalni otrzymują 2% premii, tak jak stali pracownicy. Ale jeśli usuniesz "static" s, to SpecialEmployee ' s dostać 3% bonus.

(co prawda ten przykład jest słabym stylem kodowania w że w prawdziwym życiu prawdopodobnie chciałbyś, aby mnożnik bonusowy był gdzieś w bazie danych, a nie na twardo zakodowany. Ale to dlatego, że nie chciałem pogrążyć przykład z dużą ilością kodu nieistotnego do punktu.)

Wydaje mi się całkiem prawdopodobne, że chcesz, aby getBonusMultiplier stał się statyczny. Być może chcesz mieć możliwość wyświetlania mnożnika bonusowego dla wszystkich kategorii pracowników, bez konieczności posiadania instancji pracownika w każdej kategorii. Co by było sens szukania takich przykładowych instancji? Co zrobić, jeśli tworzymy nową kategorię pracownika i nie mamy jeszcze przypisanych do niej pracowników? Jest to dość logicznie statyczna funkcja.

Ale to nie działa.

I tak, tak, mogę wymyślić wiele sposobów, aby przepisać powyższy kod, aby działał. Nie chodzi mi o to, że tworzy nierozwiązywalny problem, ale o to, że tworzy pułapkę dla nieświadomego programisty, ponieważ język nie zachowuje się tak, jak uważam za rozsądny człowiek by się spodziewał.

Być może gdybym spróbował napisać kompilator dla języka OOP, szybko zorientowałbym się, dlaczego zaimplementowanie go w celu nadpisania funkcji statycznych byłoby trudne lub niemożliwe.

A może Jest jakiś dobry powód, dla którego Java zachowuje się w ten sposób. Czy ktoś może wskazać przewagę tego zachowania, jakąś kategorię problemu, która jest przez to łatwiejsza? To znaczy, nie wskaż mi specyfikacji języka Java i nie mów "widzisz, to jest udokumentowane, jak się zachowuje". I wiedz o tym. Ale czy jest dobry powód, dla którego powinno się tak zachowywać? (Poza oczywistym "poprawienie działania było zbyt trudne"...)

Update

@VicKirk: jeśli masz na myśli, że jest to "zły projekt", ponieważ nie pasuje do tego, jak Java radzi sobie ze 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 być nadpisana tak jak funkcje wirtualne, że to w jakiś sposób wprowadzi niejednoznaczność lub nie da się efektywnie zaimplementować czy coś takiego, odpowiadam: "dlaczego? Co jest nie tak z tą koncepcją?"

Myślę, że przykład, który podaję jest bardzo naturalną rzeczą, aby chcieć zrobić. Mam klasę, która ma funkcję, która nie zależy od żadnych danych instancji, i które mogę bardzo rozsądnie chcieć wywołać niezależnie od instancji, jak również chcą wywołać z wewnątrz metoda instancji. Dlaczego miałoby to nie zadziałać? Napotkałem tę sytuację wiele razy na przestrzeni lat. W praktyce obchodzę to poprzez uczynienie funkcji wirtualną, a następnie stworzenie statycznej metody, której jedynym celem w życiu jest statyczna metoda, która przekazuje wywołanie do wirtualnej metody z fałszywą instancją. To bardzo okrężny sposób, aby się tam dostać.

 188
Author: Jay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-10 18:53:35

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

Oto jakiś kod, który ilustruje aktualny stan rzeczy w języku Java:

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 Macu, z Eclipse, używając Javy 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, tylko sprawy, które mogą być zaskoczeniem (i o które chodzi pytanie) wydają się być pierwszy case:

" Typ run-time nie jest używany do określania, które statyczne metody są wywoływane, nawet jeśli są wywoływane z instancją obiektu (obj.staticMethod())."

I ostatni przypadek:

"podczas wywoływania statycznej metody z wewnątrz metody obiektu klasy, wybrana statyczna metoda jest tą dostępną z samej klasy, A nie z klasy definiującej Typ run-time obiektu."

Wywołanie z instancją obiektu

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

Wywołanie z wewnątrz metody obiektu

wywołania metody Object są rozwiązywane przy użyciu typu run-time, ale wywołania metody static (class ) są rozwiązywane przy użyciu czasu kompilacji (zadeklarowanego) Typ.

Zmiana zasad

Aby zmienić te reguły, tak aby ostatnie wywołanie w przykładzie o nazwie Child.printValue(), wywołania statyczne musiałyby być dostarczane z typem w czasie wykonywania, a nie kompilator rozwiązujący wywołanie w czasie kompilacji z zadeklarowaną klasą obiektu (lub kontekstem). Wywołania statyczne mogą następnie użyć (dynamicznej) hierarchii typów do rozwiązania wywołania, tak jak to robią obecnie wywołania metod obiektowych.

Byłoby to łatwe do wykonania (gdybyśmy zmienili Javę: - O), a nie jest w wszystko nierozsądne, jednak ma kilka ciekawych rozważań.

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

W tej chwili Java ma taki "dziwaczny" język, w którym wywołania obj.staticMethod() są zastępowane przez wywołania ObjectClass.staticMethod() (Zwykle z ostrzeżeniem). [Uwaga: ObjectClass jest typem czasu kompilacji obj.] Byłyby to dobre kandydatury do nadpisania w ten sposób, biorąc pod uwagę typ run-time obj.

Jeśli uczyniliśmy to trudniejszym do odczytania ciałem metody: statyczne wywołania w klasie macierzystej mogłyby potencjalnie być dynamicznie "przekierowywane". Aby tego uniknąć, musielibyśmy wywołać metodę statyczną z nazwą klasy -- i to sprawia, że wywołania są bardziej rozwiązywane w hierarchii typów w czasie kompilacji (jak teraz).

Inne sposoby wywoływania statycznej metody są bardziej skomplikowane: this.staticMethod() powinno oznaczać to samo co obj.staticMethod(), biorąc Typ run-time this. Może to jednak spowodować pewne bóle głowy z istniejącymi programami, które wywołują (pozornie lokalne) statyczne metody bez dekoracji (co jest prawdopodobnie równoważne this.method()).

A co z nieodebranymi telefonami? Sugeruję, aby zrobili to samo, co dzisiaj i użyli lokalnego kontekstu klasowego, aby zdecydować, co zrobić. W przeciwnym razie nastąpiłoby wielkie zamieszanie. Oczywiście oznacza to, że method() oznaczałoby this.method() jeśli method jest metodą niestatyczną, a ThisClass.method() jeśli method jest metodą statyczną. Jest to kolejne źródło zamieszanie.

Inne względy

Gdybyśmy zmienili to zachowanie (i wykonywali statyczne wywołania potencjalnie dynamicznie nielokalne), prawdopodobnie chcielibyśmy powrócić do znaczenia final, private i protected jako kwalifikatory na static metody klasy. Wtedy wszyscy musielibyśmy przyzwyczaić się do tego, że metody private static i public final nie są nadpisywane i dlatego mogą być bezpiecznie rozwiązywane w czasie kompilacji i są "bezpieczne" do odczytu jako lokalne odniesienia.

 44
Author: Steve Powell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-25 13:05:25

Myliliśmy się.
Pomimo tego, że Java nie pozwala na nadpisywanie statycznych metod domyślnie, jeśli dokładnie przejrzysz dokumentację klas i metod w Javie, nadal możesz znaleźć sposób na emulację nadpisywania statycznych metod za pomocą następującego obejścia:

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

Wynik wyjściowy:

0.02
0.02
0.02
0.03

Co chcieliśmy osiągnąć:)

Nawet jeśli zadeklarujemy trzecią zmienną Carl jako RegularEmployee i przypiszemy do niej instancję SpecialEmployee, to i tak 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

;)

 26
Author: Patlatus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-29 19:28:13

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

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

EDIT

Możesz przeciążać metodą statyczną, to ok. Ale nie możesz nadpisać statycznej metody, ponieważ klasa nie jest obiektem pierwszej klasy. Możesz użyć reflection, 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żna zastanowić się nad klasami, ale na tym się kończy. Nie wywołujesz statycznej metody używając clazz1.staticMethod(), ale używając MyClass.staticMethod(). Metoda statyczna nie jest związana z obiektem i dlatego nie ma pojęcia this ani super w metodzie statycznej. Metoda statyczna jest funkcją globalną; w konsekwencji nie ma też pojęcia polimorfizmu, a zatem nadrzędność metody nie ma sensu.

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

O tak... jeszcze jedno. Można wywołać statyczną metodę za pomocą obiektu obj1.staticMethod(), ale to naprawdę syntaktyczny cukier dla MyClass.staticMethod() i należy go unikać. To zwykle podnosi ostrzeżenie w nowoczesnym IDE. Nie wiem, dlaczego pozwolili na ten skrót.
 19
Author: ewernli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-10 19:10:49

Nadpisywanie metod jest możliwe przez dynamiczne wysyłanie , co oznacza, że deklarowany typ obiektu nie określa jego zachowania, ale raczej jego typ runtime:

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

Mimo że zarówno lassie, jak i kermit są zadeklarowane jako obiekty typu Animal, ich zachowanie (metoda .speak()) różni się, ponieważ dynamiczne wysyłanie będzie wiązało wywołanie metody .speak() do implementacji w czasie wykonywania, a nie w czasie kompilacji.

Tutaj zaczyna się słowo kluczowe static aby mieć sens: słowo " statyczny "jest antonimem dla"dynamiczny". powodem, dla którego nie można nadpisać metod statycznych, jest brak dynamicznego wysyłania elementów statycznych - ponieważ statyczne dosłownie oznacza "nie dynamiczne". gdyby wysyłane były dynamicznie (a tym samym mogły zostać nadpisane), słowo kluczowe static nie miałoby już sensu.

 14
Author: Richard JP Le Guen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-04 09:06:07

Tak. Praktycznie Java zezwala na nadpisywanie statycznej metody i teoretycznie nie, jeśli nadpisujesz statyczną metodę w Javie, to skompiluje się i będzie działać płynnie, ale straci polimorfizm, który jest podstawową właściwością Javy. Przeczytasz wszędzie, że nie jest możliwe samodzielne kompilowanie i uruchamianie. dostaniesz swoją odpowiedź. na przykład, jeśli masz klasę Animal i statyczną metodę eat () I nadpisujesz tę statyczną metodę w jej podklasie lets nazywając ją Dog. Wtedy gdy gdziekolwiek ty Przypisanie obiektu psa do referencji zwierzęcej i wywołanie eat() zgodnie z Java Dog 's eat () powinno zostać wywołane, ale w statycznym nadrzędnym Animals' eat () 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 Javy, wyjście powinno być Dog Eating.
Wynik był jednak 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 zamiast run-time, więc otrzymujemy metody według referencji, a nie według obiektu a Referencja a zawierająca, dlatego można powiedzieć, że praktycznie obsługuje overring statyczny, ale teoretycznie nie.

 14
Author: Shubhamhackz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-26 14:03:31

Nadpisywanie jest zarezerwowane na przykład dla członków wspierających zachowanie polimorficzne. statyczne elementy klasy nie należą do konkretnej instancji. zamiast tego statyczne członkowie należą do klasy i w rezultacie nadpisywanie nie jest obsługiwane, ponieważ podklasy dziedziczą tylko chronione i publiczne członkowie instancji, a nie statyczne członkowie. Można zdefiniować inerface i fabryki badań i / lub wzorce projektowania strategii do oceny alternatywnego podejścia.

 6
Author: Athens Holloway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-04 14:03:43

W Javie (i wielu językach OOP, ale nie mogę mówić za wszystkich; a niektóre nie mają w ogóle statycznych) wszystkie metody mają ustaloną sygnaturę-parametry i typy. W metodzie wirtualnej pierwszy parametr jest implikowany: odniesienie do samego obiektu i gdy jest wywoływany z wewnątrz obiektu, kompilator automatycznie dodaje this.

Nie ma żadnej różnicy dla metod statycznych - nadal mają stałą sygnaturę. Jednak deklarując metodę statyczną wyraźnie stwierdziłeś, że kompilator nie może zawierać domyślnego parametru obiektu na początku tej sygnatury. W związku z tym, każdy inny kod wywołujący to musi nie może próbować umieścić odniesienia do obiektu na stosie . Gdyby tak się stało, to wykonanie metody nie zadziałałoby, ponieważ parametry byłyby w niewłaściwym miejscu - przesunięte o jeden-na stosie.

Z powodu tej różnicy między tymi dwoma; metody wirtualne zawsze mają odniesienie do obiektu context (tzn. this), więc jest możliwe odwoływanie się do wszystkiego wewnątrz sterty, co należy do tej instancji obiektu. Ale w przypadku metod statycznych, ponieważ nie jest przekazywane odniesienie, ta metoda nie może uzyskać dostępu do żadnych zmiennych i metod obiektu, ponieważ kontekst nie jest znany.

Jeśli chcesz, aby Java zmieniła definicję tak, aby kontekst obiektu był przekazywany dla każdej metody, statycznej lub wirtualnej, to w zasadzie będziesz mieć tylko metody wirtualne.

Jak ktoś zapytał w komentarzu do op-jaki jest Twój powód i cel, dla którego chcemy tej funkcji?

Nie znam Rubiego zbyt wiele, ponieważ o tym wspomniał OP, przeprowadziłem pewne badania. Widzę, że w Ruby klasy są tak naprawdę specjalnym rodzajem obiektów i można tworzyć (nawet dynamicznie) nowe metody. Klasy są pełnymi obiektami klas w Ruby, nie są w Javie. Jest to po prostu coś, co musisz zaakceptować podczas pracy z Javą (lub C#). Nie są to języki dynamiczne, choć C# dodaje pewne formy dynamiczne. W rzeczywistości Ruby nie ma metody "statyczne" na ile mogłem znaleźć - w takim przypadku są to metody na obiekcie klasy singleton. Możesz następnie nadpisać ten singleton nową klasą i metody w poprzednim obiekcie klasy będą wywoływać te zdefiniowane w nowej klasie (poprawne?). Więc jeśli wywołałeś metodę w kontekście oryginalnej klasy, to nadal wykonywałaby tylko oryginalną statykę, ale wywołanie metody w klasie pochodnej wywołałoby metody z rodzica lub podklasy. Ciekawe i widze jakies wartość w tym. To wymaga innego schematu myślenia.

Ponieważ pracujesz w Javie, musisz dostosować się do tego sposobu działania. Dlaczego to zrobili? Cóż, prawdopodobnie w celu poprawy wydajności w tym czasie w oparciu o technologię i zrozumienie, że był dostępny. 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.

EDIT : Jeszcze jeden komentarz. Teraz, gdy widzę różnice i jako, że sam programista Java / C# mogę zrozumieć, dlaczego odpowiedzi, które otrzymujesz od programistów Javy, mogą być mylące, jeśli pochodzisz z języka takiego jak Ruby. Metody Java static nie są takie same jak metody Ruby class. Programiści Javy będą mieli trudności ze zrozumieniem tego, podobnie jak ci, którzy pracują głównie z językiem Ruby / Smalltalk. Widzę, że byłoby to również bardzo mylące przez fakt, że Java używa również "metody klasowej" jako innego sposobu mówienia o metody statyczne, ale ten sam termin jest używany inaczej przez Ruby. Java nie posiada metod Klasy Stylu Ruby (przykro mi); Ruby nie ma metod statycznych stylu Java, które są tak naprawdę tylko starymi funkcjami proceduralnymi, jak można znaleźć w C.

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

 6
Author: Kevin Brock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-04 15:46:50

Cóż... odpowiedź brzmi NIE, jeśli myślisz z perspektywy tego, jak nadpisana metoda powinna zachowywać się w Javie. Ale nie otrzymasz żadnego błędu kompilatora, jeśli spróbujesz nadpisać statyczną metodę. Oznacza to, że jeśli spróbujesz nadpisać, Java nie powstrzyma cię od tego; ale na pewno nie uzyskasz takiego samego efektu, jak w przypadku metod niestatycznych. Nadpisywanie w języku Java oznacza po prostu, że dana metoda zostanie wywołana na podstawie typu run time obiektu, a nie na podstawie typu compile time (co ma miejsce w przypadku nadpisanych metod statycznych). Ok... jakieś przypuszczenia, dlaczego zachowują się dziwnie? Ponieważ są to metody klasowe i stąd dostęp do nich jest zawsze rozwiązywany w czasie kompilacji tylko przy użyciu informacji typu compile time. Dostęp do nich przy użyciu referencji obiektowych jest tylko dodatkową swobodą dawaną przez projektantów Javy i z pewnością nie powinniśmy myśleć o zaprzestaniu tej praktyki tylko wtedy, gdy ją ograniczą: -)

przykład: spróbujmy zobacz, co się stanie, jeśli spróbujemy nadpisać statyczną metodę: -

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 drugą linię wyjścia. Gdyby nadpisano staticMethod, ta linia powinna być identyczna z trzecią linią, ponieważ wywołujemy ' staticMethod ()' na obiekcie typu Runtime jako 'podklasa', a nie jako 'SuperClass'. Potwierdza to, że metody statyczne są zawsze rozwiązywane wyłącznie za pomocą informacji o typie czasu kompilacji.

 6
Author: Rupesh Yadav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-14 11:28:41

Ogólnie nie ma sensu zezwalać na "nadpisywanie" metod statycznych, ponieważ nie byłoby dobrego sposobu na określenie, którą z nich wywołać w czasie wykonywania. Biorąc przykład pracownika, jeśli nazywamy RegularEmployee.getBonusMultiplier () - która metoda ma być wykonana?

W przypadku Javy można sobie wyobrazić definicję języka, w której możliwe jest "nadpisanie" statycznych metod, o ile są one wywoływane przez instancję obiektu. Jednak wszystko to będzie zrobić, aby ponownie wdrożyć regularne metody klasowe, dodawanie nadmiarowości do języka bez dodawania żadnych korzyści.

 5
Author: Lars,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-08 19:19:09

Poprzez nadpisanie możemy utworzyć charakter polimorficzny w zależności od typu obiektu. Metoda statyczna nie ma związku z obiektem. Więc java nie może obsługiwać statycznych metod nadpisywania.

 5
Author: DeveloperArnab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-20 14:10:31

Lubię i podwoję komentarz Jaya ( https://stackoverflow.com/a/2223803/1517187).
Zgadzam się, że to zły projekt Javy.
Wiele innych języków obsługuje nadpisywanie metod statycznych, jak widzimy w poprzednich komentarzach. Wydaje mi się, że Jay również przybył do Javy z Delphi tak jak ja.
Delphi (Object Pascal) był jednym z języków implementujących OOP przed Javą i jednym z pierwszych języków używanych do tworzenia komercyjnych aplikacji.
Jest oczywiste, że wiele osób miało doświadczenie z tym językiem, ponieważ w przeszłości był to jedyny język do pisania komercyjnych produktów GUI. I-tak, możemy w Delphi nadpisać statyczne metody. W rzeczywistości metody statyczne w Delphi nazywane są "metodami klasowymi", podczas gdy Delphi miało inną koncepcję" metod statycznych Delphi", które były metodami z wczesnym wiązaniem. Aby nadpisać metody, które trzeba było użyć późnego wiązania, należy zadeklarować dyrektywę "wirtualną". Było to więc bardzo wygodne i intuicyjne i spodziewałbym się tego w Javie.

 5
Author: Patlatus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-07 07:13:51

Poprzez nadpisanie, można osiągnąć dynamiczny polimorfizm. Kiedy mówisz nadrzędne metody statyczne, słowa, których próbujesz użyć, są sprzeczne.

Static mówi-czas kompilacji, overriding jest używany do dynamicznego polimorfizmu. Oba są z natury przeciwne i dlatego nie mogą być używane razem.

Dynamiczne zachowanie polimorficzne pojawia się, gdy programista używa obiektu i uzyskuje dostęp do metody instancji. JRE mapuje różne metody instancji różnych klas na podstawie rodzaju obiektu bierzesz.

Kiedy mówisz nadrzędne metody statyczne, statyczne metody uzyskamy dostęp używając nazwy klasy, która będzie linkowana w czasie kompilacji, więc nie ma koncepcji łączenia metod w czasie wykonywania ze statycznymi metodami. Tak więc samo pojęcie "nadrzędnych" metod statycznych nie ma żadnego znaczenia.

Uwaga: nawet jeśli uzyskasz dostęp do metody klasy z obiektem, kompilator Javy jest wystarczająco inteligentny, aby ją znaleźć i zrobi statyczne łączenie.

 4
Author: user1923551,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-26 15:48:26

Nadpisywanie w Javie oznacza po prostu, że dana metoda zostanie wywołana na podstawie typu runtime obiektu, a nie jego typu compile-time (co ma miejsce w przypadku nadpisanych metod statycznych). Ponieważ metody statyczne są metodami klasowymi, nie są one metodami instancji, więc nie mają nic wspólnego z tym, które odniesienie wskazuje na który obiekt lub instancję, ponieważ ze względu na naturę metody statycznej należy ona do określonej klasy. Można go ponownie zgłosić w podklasie, ale to podklasa nie będzie wiedziała nic o metodach statycznych klasy macierzystej, ponieważ, jak powiedziałem, jest specyficzna tylko dla tej klasy, w której została zadeklarowana. Dostęp do nich za pomocą odniesień obiektowych jest tylko dodatkową swobodą dawaną przez projektantów Javy 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 http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html

 3
Author: faisalbhagat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-26 15:47:47

Co dobrego da zastąpienie metod statycznych. 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.

EDIT: wygląda na to, że przez niefortunne niedopatrzenie w projektowaniu języka, możesz wywołać statyczne metody za pomocą instancji. Generalnie nikt tego nie robi. Mój błąd.

 2
Author: fastcodejava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-08 18:45:36

Odpowiedź na to pytanie jest prosta, metoda lub zmienna oznaczona jako statyczna należy tylko do klasy, tak że statyczna metoda nie może być dziedziczona w podklasie, ponieważ należy tylko do klasy super.

 2
Author: g1ji,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-29 19:41:47

Łatwe rozwiązanie: użyj instancji singleton. Pozwoli to na nadpisanie i dziedziczenie.

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

Klasa języka 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!";
  }

}
 1
Author: Raivo Fishmeister,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-28 15:43:05

Statyczna metoda, zmienna, blok lub klasa zagnieżdżona należy do całej klasy, a nie do obiektu.

Metoda w Javie jest używana do ujawniania zachowania obiektu / klasy. Tutaj, ponieważ metoda jest static (tzn. metoda statyczna jest używana tylko do reprezentowania zachowania klasy.) zmiana / nadpisanie zachowanie całej klasy będzie naruszać zjawisko jednego z podstawowych filarów programowania obiektowego tj. wysokiej spójności . (pamiętaj konstruktor jest specjalnym rodzajem metody w Javie.)

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

Dlatego przy projektowaniu języka programowania java. Projektanci języka myśleli, że pozwalają programistom zachować niektóre zachowania klasy dla siebie tylko poprzez stworzenie metody statyczne w naturze.


Poniższy kod próbuje nadpisać metodę statyczną, ale nie napotkają ż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;
}}

Dzieje się tak dlatego, że tutaj nie nadpisujemy metody, ale po prostu ponownie deklarujemy ją . Java pozwala na ponowną deklarację metody (statyczna/niestatyczna).

Usunięcie statycznego słowa kluczowego z metody getVehileNumber () klasy samochodu spowoduje błąd kompilacji, ponieważ staramy się zmienić funkcjonalność metody statycznej, która należy wyłącznie do klasy pojazdu.

Ponadto, jeśli getvehilenumber() jest zadeklarowane jako final , to kod nie będzie kompilowany, ponieważ słowo kluczowe final ogranicza programistę od ponownej deklaracji metody.

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

Ogólnie rzecz biorąc, jest to upto projektanci oprogramowania, gdzie korzystać z metod statycznych. Osobiście wolę używać metod statycznych do wykonywania pewnych akcji bez tworzenia żadnej instancji klasy. Po drugie, aby ukryć zachowanie klasy ze świata zewnętrznego.

 1
Author: Rohit Gaikwad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-12 08:24:08

Oto proste wyjaśnienie. Statyczna metoda jest powiązana z klasą, podczas gdy metoda instancji jest powiązana z konkretnym obiektem. Nadpisania umożliwiają wywołanie innej implementacji nadpisanych metod powiązanych z danym obiektem. Jest więc sprzeczne z intuicją, aby nadpisać statyczną metodę, która nie jest nawet powiązana z obiektami, ale z samą klasą. Więc statyczne metody nie mogą być nadpisywane na podstawie tego, jaki obiekt je wywołuje, zawsze będzie związany z klasą, w której został utworzony.

 1
Author: Rafsan Mobasher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-26 14:05:08

Teraz widząc powyższe odpowiedzi każdy wie, że nie możemy nadpisać metod statycznych, ale nie należy źle rozumieć koncepcji dostępu do metod statycznych z podklasy .

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

Na przykład, patrz 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");
    // }
}

Wyjście:-

SuperClass saying Hello

Zobacz Java Oracle docs i szukać co można zrobić w podklasie szczegółowe informacje o ukrywaniu metod statycznych w podklasie.

Dzięki

 -1
Author: amandeep1991,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-10 13:59:21

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

}   

} 
 -3
Author: pop stack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-07 04:17:03