Warum erlaubt Java nicht das Überschreiben statischer Methoden?


534

Warum ist es nicht möglich, statische Methoden zu überschreiben?

Wenn möglich, verwenden Sie bitte ein Beispiel.


3
Die meisten OOP-Sprachen erlauben dies nicht.
jmucchiello

7
@jmucchiello: siehe meine Antwort. Ich habe genauso gedacht wie Sie, aber dann etwas über Ruby / Smalltalk-Klassenmethoden gelernt, und so gibt es andere echte OOP-Sprachen, die dies tun.
Kevin Brock

5
@jmucchiello die meisten OOP-Sprache sind keine echte OOP-Sprache (ich denke an Smalltalk)
Mathk


1
Dies kann daran liegen, dass Java Aufrufe statischer Methoden zur Kompilierungszeit auflöst. Selbst wenn Sie geschrieben haben Parent p = new Child()und p.childOverriddenStaticMethod()der Compiler es dann auflöst, Parent.childOverriddenStaticMethod()indem er sich den Referenztyp ansieht.
Manoj

Antworten:


494

Das Überschreiben hängt von einer Instanz einer Klasse ab. Der Punkt des Polymorphismus besteht darin, dass Sie eine Klasse unterklassifizieren können und die Objekte, die diese Unterklassen implementieren, unterschiedliche Verhaltensweisen für dieselben Methoden aufweisen, die in der Oberklasse definiert (und in den Unterklassen überschrieben) sind. Eine statische Methode ist keiner Instanz einer Klasse zugeordnet, sodass das Konzept nicht anwendbar ist.

Es gab zwei Überlegungen, die das Design von Java beeinflussten. Eines war ein Problem mit der Leistung: Smalltalk wurde vielfach kritisiert, weil es zu langsam sei (Garbage Collection und polymorphe Aufrufe seien Teil davon), und Javas Entwickler waren entschlossen, dies zu vermeiden. Ein weiterer Grund war die Entscheidung, dass die Zielgruppe für Java C ++ - Entwickler waren. Statische Methoden so funktionieren zu lassen, wie sie es tun, war für C ++ - Programmierer von Vorteil und auch sehr schnell, da nicht bis zur Laufzeit gewartet werden muss, um herauszufinden, welche Methode aufgerufen werden soll.


18
... aber nur "richtig" in Java. Zum Beispiel ermöglicht Scalas Äquivalent zu "statischen Klassen" (die aufgerufen werden objects) das Überladen von Methoden.

32
Objective-C ermöglicht auch das Überschreiben von Klassenmethoden.
Richard

11
Es gibt eine Hierarchie vom Typ zur Kompilierungszeit und eine Hierarchie vom Typ zur Laufzeit. Es ist durchaus sinnvoll zu fragen, warum ein statischer Methodenaufruf unter den Umständen, unter denen es eine gibt, die Laufzeit-Hierarchie nicht nutzt. In Java geschieht dies, wenn eine statische Methode von einem Objekt ( obj.staticMethod()) aufgerufen wird - was zulässig ist und die Typen zur Kompilierungszeit verwendet. Wenn sich der statische Aufruf in einer nicht statischen Methode einer Klasse befindet, kann das "aktuelle" Objekt ein abgeleiteter Typ der Klasse sein. Statische Methoden, die für die abgeleiteten Typen definiert sind, werden jedoch nicht berücksichtigt (sie sind vom Laufzeittyp Hierarchie).
Steve Powell

18
Ich hätte klarstellen sollen: Es ist nicht wahr, dass das Konzept nicht anwendbar ist .
Steve Powell

13
Diese Antwort ist zwar richtig, ähnelt jedoch eher dem "wie es ist" als dem, wie es sein sollte, oder genauer dem, wie es sein könnte, um die Erwartungen des OP und damit auch von mir und anderen zu erfüllen. Es gibt keinen konkreten Grund, das Überschreiben statischer Methoden zu verbieten, außer "so ist es". Ich denke, es ist persönlich ein Fehler.
RichieHH

186

Persönlich denke ich, dass dies ein Fehler im Design von Java ist. Ja, ja, ich verstehe, dass nicht statische Methoden an eine Instanz angehängt sind, während statische Methoden an eine Klasse usw. angehängt sind. Beachten Sie dennoch den folgenden Code:

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

Dieser Code funktioniert nicht wie erwartet. SpecialEmployee's erhalten nämlich einen Bonus von 2%, genau wie reguläre Mitarbeiter. Wenn Sie jedoch die "statischen" entfernen, erhalten SpecialEmployee einen Bonus von 3%.

(Zugegeben, dieses Beispiel ist insofern ein schlechter Codierungsstil, als Sie im wirklichen Leben wahrscheinlich möchten, dass sich der Bonusmultiplikator irgendwo in einer Datenbank befindet und nicht fest codiert. Aber das liegt nur daran, dass ich das Beispiel nicht mit vielem festhalten wollte von Code für den Punkt irrelevant.)

Es scheint mir ziemlich plausibel, dass Sie getBonusMultiplier statisch machen möchten. Vielleicht möchten Sie in der Lage sein, den Bonusmultiplikator für alle Kategorien von Mitarbeitern anzuzeigen, ohne dass in jeder Kategorie eine Instanz eines Mitarbeiters erforderlich ist. Was wäre der Sinn der Suche nach solchen Beispielinstanzen? Was ist, wenn wir eine neue Kategorie von Mitarbeitern erstellen und noch keine Mitarbeiter zugewiesen haben? Dies ist logischerweise eine statische Funktion.

Aber es funktioniert nicht.

Und ja, ja, ich kann mir eine beliebige Anzahl von Möglichkeiten vorstellen, den obigen Code neu zu schreiben, damit er funktioniert. Mein Punkt ist nicht, dass es ein unlösbares Problem schafft, sondern dass es eine Falle für den unachtsamen Programmierer schafft, weil sich die Sprache nicht so verhält, wie ich es von einer vernünftigen Person erwarten würde.

Wenn ich versuchen würde, einen Compiler für eine OOP-Sprache zu schreiben, würde ich schnell erkennen, warum es schwierig oder unmöglich wäre, ihn so zu implementieren, dass statische Funktionen überschrieben werden können.

Oder vielleicht gibt es einen guten Grund, warum sich Java so verhält. Kann jemand auf einen Vorteil dieses Verhaltens hinweisen, eine Kategorie von Problemen, die dadurch erleichtert wird? Ich meine, zeige mich nicht nur auf die Java-Sprachspezifikation und sage "siehe, das ist dokumentiert, wie es sich verhält". Ich weiß das. Aber gibt es einen guten Grund, warum es sich so verhalten sollte? (Abgesehen von dem offensichtlichen "es richtig zu machen war zu schwer" ...)

Aktualisieren

@VicKirk: Wenn Sie meinen, dass dies "schlechtes Design" ist, weil es nicht dazu passt, wie Java mit Statik umgeht, lautet meine Antwort: "Nun, duh, natürlich." Wie ich in meinem ursprünglichen Beitrag sagte, funktioniert es nicht. Aber wenn Sie meinen, dass es schlechtes Design in dem Sinne ist, dass mit einer Sprache, in der dies funktioniert, etwas grundlegend falsch wäre, dh wenn die Statik genau wie virtuelle Funktionen überschrieben werden könnte, würde dies irgendwie zu einer Mehrdeutigkeit führen oder es wäre unmöglich Effizient implementieren oder so, antworte ich: "Warum? Was ist los mit dem Konzept?"

Ich denke, das Beispiel, das ich gebe, ist eine sehr natürliche Sache, die ich tun möchte. Ich habe eine Klasse mit einer Funktion, die nicht von Instanzdaten abhängt und die ich möglicherweise sehr vernünftigerweise unabhängig von einer Instanz sowie innerhalb einer Instanzmethode aufrufen möchte. Warum sollte das nicht funktionieren? Ich bin im Laufe der Jahre ziemlich oft in diese Situation geraten. In der Praxis kann ich das umgehen, indem ich die Funktion virtuell mache und dann eine statische Methode erstelle, deren einziger Lebenszweck darin besteht, eine statische Methode zu sein, die den Aufruf mit einer Dummy-Instanz an die virtuelle Methode weiterleitet. Das scheint ein sehr umständlicher Weg dorthin zu sein.


11
@Bemrose: Aber das ist mein Punkt: Warum sollte ich das nicht dürfen? Vielleicht unterscheidet sich mein intuitives Konzept, was eine "Statik" tun sollte, von Ihrer, aber im Grunde denke ich an eine Statik als eine Methode, die statisch sein kann, weil sie keine Instanzdaten verwendet, und die statisch sein SOLLTE, weil Sie möchten um es unabhängig von einer Instanz aufzurufen. Eine Statik ist eindeutig an eine Klasse gebunden: Ich erwarte, dass Integer.valueOf an Integers und Double.valueOf an Doubles gebunden sind.
Jay

9
@ewernli & Bemrose: Ja ja, so ist es. Ich diskutiere das nicht. Da der Code in meinem Beispiel nicht funktioniert, würde ich natürlich nicht versuchen, ihn zu schreiben. Meine Frage ist, warum es so ist. (Ich fürchte, dies wird zu einem dieser Gespräche, in denen wir einfach nicht kommunizieren. "Entschuldigen Sie, Herr Verkäufer, kann ich eines davon in Rot bekommen?" "Nein, es kostet 5 Dollar." "Ja, ich weiß, es kostet 5 Dollar, aber kann ich einen roten bekommen? "„ Sir, ich habe Ihnen gerade gesagt, dass er 5 Dollar kostet. "„ Okay, ich kenne den Preis, aber ich habe nach der Farbe gefragt. "„ Ich habe Ihnen bereits den Preis gesagt! " usw.)
Jay

6
Ich denke, dass dieser Code letztendlich verwirrend ist. Überlegen Sie, ob die Instanz als Parameter übergeben wird. Dann sagen Sie, dass die Laufzeitinstanz bestimmen soll, welche statische Methode aufgerufen wird. Das macht im Grunde eine ganze separate Hierarchie parallel zur vorhandenen Instanz. Was ist nun, wenn eine Unterklasse dieselbe Methodensignatur wie nicht statisch definiert? Ich denke, dass die Regeln die Dinge ziemlich kompliziert machen würden. Genau diese Art von Sprachkomplikationen versucht Java zu vermeiden.
Yishai

6
@Yishai: RE "Laufzeitinstanz bestimmt, welche statische Methode aufgerufen wird": Genau. Ich verstehe nicht, warum Sie mit einer Statik nichts machen können, was Sie mit einer virtuellen machen können. "Separate Hierarchie": Ich würde sagen, machen Sie es Teil derselben Hierarchie. Warum sind Statiken nicht in derselben Hierarchie enthalten? "Unterklasse definiert dieselbe Signatur nicht statisch": Ich nehme an, dass dies illegal wäre, genauso wie es beispielsweise illegal ist, eine Unterklasse eine Funktion mit identischer Signatur, aber einem anderen Rückgabetyp überschreiben zu lassen oder nicht alle Ausnahmen auszulösen der Elternteil wirft oder um einen engeren Umfang zu haben.
Jay

28
Ich denke, Jay hat Recht - es hat mich auch überrascht, als ich entdeckte, dass die Statik nicht überschrieben werden konnte. Zum Teil, weil, wenn ich A mit Methode habe someStatic()und B A erweitert, dann B.someMethod() an die Methode in A bindet . Wenn ich anschließend someStatic()zu B hinzufüge , wird der aufrufende Code immer noch aufgerufen, A.someStatic()bis ich den aufrufenden Code neu kompiliere. Es hat mich auch überrascht, dass bInstance.someStatic()der deklarierte Typ von bInstance verwendet wird, nicht der Laufzeittyp, da er beim Kompilieren nicht verknüpft wird. A bInstance; ... bInstance.someStatic()Daher wird A.someStatic () aufgerufen, wenn B.someStatic () vorhanden ist.
Lawrence Dol

42

Die kurze Antwort lautet: Es ist durchaus möglich, aber Java tut es nicht.

Hier ist ein Code, der den aktuellen Stand der Dinge in Java veranschaulicht :

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

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

Wenn Sie dies ausführen (ich habe es auf einem Mac von Eclipse mit Java 1.6 ausgeführt), erhalten Sie:

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.

Hier scheinen die einzigen Fälle, die eine Überraschung sein könnten (und um die es in der Frage geht), der erste Fall zu sein:

"Der Laufzeittyp wird nicht verwendet, um zu bestimmen, welche statischen Methoden aufgerufen werden, selbst wenn sie mit einer Objektinstanz ( obj.staticMethod()) aufgerufen werden ."

und der letzte Fall:

"Wenn Sie eine statische Methode aus einer Objektmethode einer Klasse aufrufen, wird die statische Methode ausgewählt, auf die von der Klasse selbst zugegriffen werden kann, und nicht von der Klasse, die den Laufzeittyp des Objekts definiert."

Aufruf mit einer Objektinstanz

Der statische Aufruf wird zur Kompilierungszeit aufgelöst, während ein nicht statischer Methodenaufruf zur Laufzeit aufgelöst wird. Beachten Sie, dass statische Methoden zwar vom Elternteil geerbt werden, aber nicht vom Kind überschrieben werden. Dies könnte eine Überraschung sein, wenn Sie etwas anderes erwartet haben.

Aufruf aus einer Objektmethode heraus

Objektmethodenaufrufe werden unter Verwendung des Laufzeittyps aufgelöst, statische ( Klassen- ) Methodenaufrufe werden jedoch unter Verwendung des Typs zur Kompilierungszeit (deklariert) aufgelöst.

Regeln ändern

Um diese Regeln so zu ändern, dass beim letzten Aufruf im aufgerufenen Beispiel Child.printValue()statische Aufrufe zur Laufzeit mit einem Typ versehen werden müssen, anstatt dass der Compiler den Aufruf zur Kompilierungszeit mit der deklarierten Klasse des Objekts (oder) auflöst Kontext). Statische Aufrufe könnten dann die (dynamische) Typhierarchie verwenden, um den Aufruf aufzulösen, so wie es Objektmethodenaufrufe heute tun.

Dies wäre leicht machbar (wenn wir Java: -O ändern würden) und ist keineswegs unvernünftig, hat jedoch einige interessante Überlegungen.

Die Hauptüberlegung ist, dass wir entscheiden müssen, welche statischen Methodenaufrufe dies tun sollen.

Im Moment hat Java diese "Eigenart" in der Sprache, in der obj.staticMethod()Anrufe durch ObjectClass.staticMethod()Anrufe ersetzt werden (normalerweise mit einer Warnung). [ Hinweis: ObjectClass ist der Typ zur Kompilierungszeit von obj.] Dies wären gute Kandidaten, um auf diese Weise den Laufzeittyp von zu überschreiben obj.

Wenn wir dies tun würden, wäre das Lesen von Methodenkörpern schwieriger: Statische Aufrufe in einer übergeordneten Klasse könnten möglicherweise dynamisch "umgeleitet" werden. Um dies zu vermeiden, müssten wir die statische Methode mit einem Klassennamen aufrufen - und dies macht die Aufrufe mit der Hierarchie des Typs zur Kompilierungszeit (wie jetzt) ​​offensichtlicher aufgelöst.

Die anderen Möglichkeiten zum Aufrufen einer statischen Methode sind schwieriger: Sie this.staticMethod()sollten dasselbe bedeuten wie obj.staticMethod()die Verwendung des Laufzeit-Typs von this. Dies kann jedoch zu Kopfschmerzen bei vorhandenen Programmen führen, die (anscheinend lokale) statische Methoden ohne Dekoration aufrufen (was wohl gleichbedeutend ist mit this.method()).

Was ist also mit schmucklosen Anrufen staticMethod()? Ich schlage vor, dass sie dasselbe tun wie heute und den lokalen Klassenkontext verwenden, um zu entscheiden, was zu tun ist. Andernfalls würde große Verwirrung entstehen. Natürlich bedeutet dies , dass method()würde bedeuten , this.method()wenn methodeine nicht-statische Methode war, und ThisClass.method()wenn methodeine statische Methode war. Dies ist eine weitere Quelle der Verwirrung.

Andere Überlegungen

Wenn wir dieses Verhalten geändert (und machte einen statischen Aufruf potenziell dynamisch nicht-lokal), würden wir wahrscheinlich wollen die Bedeutung zu überdenken final, privateund protectedals Qualifier auf staticMethoden einer Klasse. Wir müssten uns dann alle daran gewöhnen, dass private staticund public finalMethoden nicht überschrieben werden und daher zur Kompilierungszeit sicher aufgelöst werden können und als lokale Referenzen "sicher" zu lesen sind.


"Wenn wir dies tun würden, wäre das Lesen von Methodenkörpern schwieriger: Statische Aufrufe in einer übergeordneten Klasse könnten möglicherweise dynamisch" umgeleitet "werden." Stimmt, aber genau das passiert jetzt bei normalen nicht statischen Funktionsaufrufen. Dies wird routinemäßig als positives Merkmal für gewöhnliche virtuelle Funktionen angepriesen, kein Problem.
Jay

25

Eigentlich haben wir uns geirrt.
Obwohl Java das standardmäßige Überschreiben statischer Methoden nicht zulässt, können Sie bei gründlicher Durchsicht der Dokumentation von Klassen- und Methodenklassen in Java dennoch eine Möglichkeit finden, statische Methoden zu überschreiben, indem Sie die folgende Problemumgehung umgehen:

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

Resultierende Ausgabe:

0.02
0.02
0.02
0.03

was wir erreichen wollten :)

Selbst wenn wir die dritte Variable Carl als RegularEmployee deklarieren und ihr die Instanz von SpecialEmployee zuweisen, haben wir im ersten Fall den Aufruf der RegularEmployee-Methode und im zweiten Fall den Aufruf der SpecialEmployee-Methode

RegularEmployee Carl = new SpecialEmployee();

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

Schauen Sie sich einfach die Ausgabekonsole an:

0.02
0.03

;)


9
Ja, Reflexion ist so ziemlich das Einzige, was man tun kann - aber die Frage ist nicht genau das - nützlich, um sie hier zu haben
Mr_and_Mrs_D

1
Diese Antwort ist der größte Hack, den ich bisher in allen Java-Themen gesehen habe. Hat Spaß gemacht, es noch zu lesen :)
Andrejs

19

Statische Methoden werden von der JVM als global behandelt, sie sind überhaupt nicht an eine Objektinstanz gebunden.

Es könnte konzeptionell möglich sein, statische Methoden von Klassenobjekten aufzurufen (wie in Sprachen wie Smalltalk), aber dies ist in Java nicht der Fall.

BEARBEITEN

Sie können statische Methoden überladen , das ist in Ordnung. Sie können eine statische Methode jedoch nicht überschreiben , da Klassen kein erstklassiges Objekt sind. Sie können Reflection verwenden, um die Klasse eines Objekts zur Laufzeit abzurufen, aber das Objekt, das Sie erhalten, entspricht nicht der Klassenhierarchie.

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

Sie können über die Klassen nachdenken, aber es hört dort auf. Sie rufen keine statische Methode mit clazz1.staticMethod(), sondern mit auf MyClass.staticMethod(). Eine statische Methode ist nicht an ein Objekt gebunden und daher gibt es weder eine Vorstellung thisnoch supereine statische Methode. Eine statische Methode ist eine globale Funktion. Infolgedessen gibt es auch keine Vorstellung von Polymorphismus, und daher macht das Überschreiben von Methoden keinen Sinn.

Dies könnte jedoch möglich sein, wenn MyClasses sich zur Laufzeit um ein Objekt handelt, für das Sie eine Methode aufrufen, wie in Smalltalk (oder vielleicht JRuby, wie ein Kommentar andeutet, aber ich weiß nichts über JRuby).

Oh ja ... noch eine Sache. Sie können eine statische Methode über ein Objekt aufrufen, obj1.staticMethod()aber dieser wirklich syntaktische Zucker für MyClass.staticMethod()und sollte vermieden werden. In der modernen IDE wird normalerweise eine Warnung ausgegeben. Ich weiß nicht, warum sie diese Abkürzung jemals zugelassen haben.


5
Sogar viele moderne Sprachen wie Ruby haben Klassenmethoden und erlauben es, sie zu überschreiben.
Chandra Sekar

3
Klassen existieren in Java als Objekte. Siehe die Klasse "Klasse". Ich kann myObject.getClass () sagen und es wird mir eine Instanz des entsprechenden Klassenobjekts zurückgegeben.
Jay

5
Sie erhalten nur eine "Beschreibung" der Klasse - nicht die Klasse selbst. Aber der Unterschied ist subtil.
Ewernli

Sie haben noch eine Klasse, diese ist jedoch in der VM (in der Nähe des Klassenladeprogramms) versteckt. Der Benutzer hat fast keinen Zugriff darauf.
Mathk

Um clazz2 instanceof clazz1richtig zu verwenden, können Sie stattdessen verwenden class2.isAssignableFrom(clazz1), was meiner Meinung nach in Ihrem Beispiel wahr zurückgeben würde.
Simon Forsberg

14

Das Überschreiben von Methoden wird durch dynamisches Dispatching ermöglicht. Dies bedeutet, dass der deklarierte Typ eines Objekts nicht sein Verhalten bestimmt, sondern seinen Laufzeit-Typ:

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

Obwohl beide lassieund kermitals Objekte vom Typ deklariert sind, variiert Animalihr Verhalten (Methode .speak()), da das dynamische Dispatching den Methodenaufruf nur zur Laufzeit an eine Implementierung bindet.speak() - nicht zur Kompilierungszeit.

Hier staticbeginnt das Schlüsselwort Sinn zu machen: Das Wort "statisch" ist ein Antonyme für "dynamisch". Der Grund, warum Sie statische Methoden nicht überschreiben können, liegt darin, dass statische Elemente nicht dynamisch verteilt werden - weil statisch wörtlich "nicht dynamisch" bedeutet. Wenn sie dynamisch versendet würden (und somit überschrieben werden könnten), würde das staticSchlüsselwort einfach keinen Sinn mehr ergeben.


11

Ja. In der Praxis erlaubt Java das Überschreiben statischer Methoden. Wenn Sie eine statische Methode in Java überschreiben, wird sie theoretisch kompiliert und reibungslos ausgeführt, verliert jedoch den Polymorphismus, der die grundlegende Eigenschaft von Java ist. Sie werden überall lesen, dass es nicht möglich ist, sich selbst zu kompilieren und auszuführen. Sie werden Ihre Antwort bekommen. Beispiel: Wenn Sie Class Animal und eine statische Methode eat () haben und diese statische Methode in ihrer Unterklasse überschreiben, nennen wir sie Dog. Wenn dann, wo immer Sie ein Hundeobjekt einer Tierreferenz zuweisen und eat () gemäß Java Dog aufrufen, sollte eat () aufgerufen worden sein, aber in statischen Overriding Animals wird eat () aufgerufen.

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

Nach dem Polymorphismus-Prinzip von Java sollte die Ausgabe sein Dog Eating.
Das Ergebnis war jedoch anders, da Java zur Unterstützung des Polymorphismus die späte Bindung verwendet. Dies bedeutet, dass Methoden nur zur Laufzeit aufgerufen werden, bei statischen Methoden jedoch nicht. Bei statischen Methoden ruft der Compiler Methoden zur Kompilierungszeit und nicht zur Laufzeit auf, sodass wir Methoden gemäß der Referenz und nicht gemäß dem Objekt erhalten, die eine Referenz enthalten. Deshalb kann man sagen, dass er statisches Überringen praktisch unterstützt, theoretisch jedoch nicht 't.


3
Es ist eine schlechte Praxis, statische Methoden vom Objekt aufzurufen.
Dmitry Zagorulkin

6

Das Überschreiben ist beispielsweise Mitgliedern vorbehalten, um das polymorphe Verhalten zu unterstützen. statische Klassenmitglieder gehören nicht zu einer bestimmten Instanz. Stattdessen gehören statische Mitglieder zur Klasse und daher wird das Überschreiben nicht unterstützt, da Unterklassen nur geschützte und öffentliche Instanzmitglieder und keine statischen Mitglieder erben. Möglicherweise möchten Sie eine Inerface- und Research Factory- und / oder Strategiedesignmuster definieren, um einen alternativen Ansatz zu bewerten.


1
Haben Sie keine der anderen Antworten gelesen, die dies bereits behandelt haben, und klargestellt, dass dies nicht Grund genug ist, übergeordnete Statiken auf konzeptioneller Ebene zu ignorieren? Wir wissen, dass es nicht funktioniert. Es ist vollkommen "sauber, das Überschreiben statischer Methoden zu wünschen, und tatsächlich ist es in vielen anderen Sprachen möglich.
RichieHH

Richard, nehmen wir für eine Minute an, dass die meisten dieser Antworten, als ich vor 4 Jahren auf diese Frage antwortete, nicht veröffentlicht wurden, also sei kein Arsch! Es besteht keine Notwendigkeit zu behaupten, dass ich nicht sorgfältig gelesen habe. Haben Sie nicht gelesen, dass wir nur über das Überschreiben in Bezug auf Java sprechen? Wen interessiert es, was in anderen Sprachen möglich ist. Es ist irrelevant. Geh woanders trollen. Ihr Kommentar fügt diesem Thread nichts Wertvolles hinzu.
Athen Holloway

6

In Java (und vielen OOP-Sprachen, aber ich kann nicht für alle sprechen; und einige haben überhaupt keine statische Sprache) haben alle Methoden eine feste Signatur - die Parameter und Typen. In einer virtuellen Methode ist der erste Parameter impliziert: ein Verweis auf das Objekt selbst und beim Aufruf aus dem Objekt heraus fügt der Compiler automatisch hinzu this.

Bei statischen Methoden gibt es keinen Unterschied - sie haben immer noch eine feste Signatur. Indem Sie die Methode als statisch deklarieren, haben Sie ausdrücklich angegeben, dass der Compiler den implizierten Objektparameter am Anfang dieser Signatur nicht einschließen darf. Daher darf kein anderer Code, der dies aufruft, versuchen, einen Verweis auf ein Objekt auf dem Stapel zu platzieren . Wenn dies der Fall wäre, würde die Methodenausführung nicht funktionieren, da sich die Parameter an der falschen Stelle - um eins verschoben - auf dem Stapel befinden würden.

Wegen dieses Unterschieds zwischen den beiden; Virtuelle Methoden haben immer einen Verweis auf das Kontextobjekt (dh this), sodass es möglich ist, auf alles innerhalb des Heaps zu verweisen, das zu dieser Instanz des Objekts gehört. Bei statischen Methoden kann diese Methode jedoch nicht auf Objektvariablen und -methoden zugreifen, da keine Referenz übergeben wird, da der Kontext nicht bekannt ist.

Wenn Sie möchten, dass Java die Definition so ändert, dass für jede statische oder virtuelle Methode ein Objektkontext übergeben wird, haben Sie im Wesentlichen nur virtuelle Methoden.

Wie jemand in einem Kommentar zur Operation gefragt hat - was ist Ihr Grund und Zweck, diese Funktion zu wollen?

Ich kenne Ruby nicht sehr gut, da dies vom OP erwähnt wurde, habe ich einige Nachforschungen angestellt. Ich sehe, dass in Ruby Klassen wirklich eine besondere Art von Objekt sind und man (sogar dynamisch) neue Methoden erstellen kann. Klassen sind vollständige Klassenobjekte in Ruby, sie sind nicht in Java. Dies ist nur etwas, was Sie akzeptieren müssen, wenn Sie mit Java (oder C #) arbeiten. Dies sind keine dynamischen Sprachen, obwohl C # einige Formen der Dynamik hinzufügt. In Wirklichkeit hat Ruby keine "statischen" Methoden, soweit ich sie finden konnte - in diesem Fall handelt es sich um Methoden für das Singleton-Klassenobjekt. Sie können diesen Singleton dann mit einer neuen Klasse überschreiben, und die Methoden im vorherigen Klassenobjekt rufen die in der neuen Klasse definierten auf (richtig?). Wenn Sie also eine Methode im Kontext der ursprünglichen Klasse aufrufen, wird immer noch nur die ursprüngliche Statik ausgeführt. Wenn Sie jedoch eine Methode in der abgeleiteten Klasse aufrufen, werden Methoden entweder von der übergeordneten Klasse oder von der Unterklasse aufgerufen. Interessant und ich kann einen gewissen Wert darin sehen. Es braucht ein anderes Gedankenmuster.

Da Sie in Java arbeiten, müssen Sie sich an diese Vorgehensweise anpassen. Warum haben sie das getan? Nun, wahrscheinlich, um die Leistung zu diesem Zeitpunkt basierend auf der verfügbaren Technologie und dem verfügbaren Verständnis zu verbessern. Computersprachen entwickeln sich ständig weiter. Gehen Sie weit genug zurück und es gibt kein OOP. In Zukunft wird es weitere neue Ideen geben.

EDIT : Ein weiterer Kommentar. Jetzt, da ich die Unterschiede sehe und selbst Java / C # -Entwickler bin, kann ich verstehen, warum die Antworten, die Sie von Java-Entwicklern erhalten, verwirrend sein können, wenn Sie aus einer Sprache wie Ruby stammen. Java- staticMethoden sind nicht mit Ruby- classMethoden identisch . Java-Entwickler werden es schwer haben, dies zu verstehen, ebenso wie diejenigen, die hauptsächlich mit einer Sprache wie Ruby / Smalltalk arbeiten. Ich kann sehen, dass dies auch sehr verwirrend wäre, wenn Java auch "Klassenmethode" als eine andere Möglichkeit verwendet, um über statische Methoden zu sprechen, aber der gleiche Begriff wird von Ruby anders verwendet. Java verfügt nicht über Klassenmethoden im Ruby-Stil (sorry). Ruby verfügt nicht über statische Methoden im Java-Stil, die eigentlich nur alte prozedurale Stilfunktionen sind, wie in C zu finden.

Übrigens - danke für die Frage! Ich habe heute etwas Neues über Klassenmethoden (Ruby-Stil) gelernt.


1
Natürlich gibt es keinen Grund, warum Java ein "Class" -Objekt nicht als versteckten Parameter an statische Methoden übergeben konnte. Es war einfach nicht dafür ausgelegt.
jmucchiello

6

Nun ... die Antwort lautet NEIN, wenn Sie sich überlegen, wie sich eine Overriden-Methode in Java verhalten soll. Sie erhalten jedoch keinen Compilerfehler, wenn Sie versuchen, eine statische Methode zu überschreiben. Das heißt, wenn Sie versuchen zu überschreiben, hindert Java Sie nicht daran. Aber Sie erzielen sicherlich nicht den gleichen Effekt wie bei nicht statischen Methoden. Das Überschreiben in Java bedeutet einfach, dass die bestimmte Methode basierend auf dem Laufzeittyp des Objekts und nicht auf dem Kompilierungszeittyp des Objekts aufgerufen wird (was bei statischen Methoden zum Überschreiben der Fall ist). Okay ... irgendwelche Vermutungen aus dem Grund, warum sie sich seltsam verhalten? Da es sich um Klassenmethoden handelt und der Zugriff auf diese Methoden während der Kompilierungszeit immer nur unter Verwendung der Informationen zum Typ der Kompilierungszeit aufgelöst wird.

Beispiel : Versuchen wir zu sehen, was passiert, wenn wir versuchen, eine statische Methode zu überschreiben: -

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

Ausgabe : -
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

Beachten Sie die zweite Zeile der Ausgabe. Wäre die staticMethod überschrieben worden, hätte diese Zeile mit der dritten Zeile identisch sein müssen, da wir die 'staticMethod ()' für ein Objekt vom Typ Runtime als 'SubClass' und nicht als 'SuperClass' aufrufen. Dies bestätigt, dass die statischen Methoden immer nur anhand ihrer Informationen zum Kompilierungszeittyp aufgelöst werden.


5

Im Allgemeinen ist es nicht sinnvoll, statische Methoden zu überschreiben, da es keine gute Möglichkeit gibt, zu bestimmen, welche zur Laufzeit aufgerufen werden sollen. Wenn wir im Beispiel Employee RegularEmployee.getBonusMultiplier () aufrufen - welche Methode soll ausgeführt werden?

Im Fall von Java könnte man sich eine Sprachdefinition vorstellen, bei der es möglich ist, statische Methoden zu überschreiben, solange sie über eine Objektinstanz aufgerufen werden. Dies würde jedoch nur dazu führen, dass reguläre Klassenmethoden erneut implementiert werden, wodurch der Sprache Redundanz hinzugefügt wird, ohne dass dies wirklich von Vorteil ist.


2
Intuitiv würde ich denken, dass es genau wie eine virtuelle Funktion funktionieren sollte. Wenn B A erweitert und sowohl A als auch B virtuelle Funktionen mit dem Namen doStuff haben, weiß der Compiler, dass Instanzen von A A.doStuff und Instanzen von B B.doStuff verwenden sollten. Warum kann es mit statischen Funktionen nicht dasselbe tun? Schließlich weiß der Compiler, von welcher Klasse jedes Objekt eine Instanz ist.
Jay

Ähm ... Jay, eine statische Methode muss nicht (im Allgemeinen nicht) für eine Instanz aufgerufen werden ...
Meriton

2
@meriton, aber dann ist es noch einfacher, nein? Wenn eine statische Methode mit einem Klassennamen aufgerufen wird, verwenden Sie die für die Klasse geeignete Methode.
CPerkins

Aber was tut es dann für Sie? Wenn Sie A.doStuff () aufrufen, sollte es die Version verwenden, die in "B erweitert A" überschrieben wurde, oder die Version, die in "C erweitert A" überschrieben wurde. Und wenn Sie C oder B haben, rufen Sie diese Versionen trotzdem auf ... kein Überschreiben erforderlich.
PSpeed

@meriton: Es ist wahr, dass eine statische Methode im Allgemeinen nicht mit einer Instanz aufgerufen wird, aber ich nehme an, dass ein solcher Aufruf angesichts des aktuellen Java-Designs nichts Nützliches bringt! Ich schlage vor, dass ein alternatives Design eine bessere Idee gewesen sein könnte. Übrigens werden statische Funktionen im wahrsten Sinne des Wortes mit einer Instanz ziemlich routinemäßig aufgerufen: Wenn Sie die statische Funktion aus einer virtuellen Funktion heraus aufrufen. Dann erhalten Sie implizit this.function (), dh die aktuelle Instanz.
Jay

5

Durch Überschreiben können wir abhängig vom Objekttyp eine polymorphe Natur erzeugen. Die statische Methode hat keine Beziehung zum Objekt. Daher kann Java das Überschreiben statischer Methoden nicht unterstützen.


5

Ich mag und verdopple Jays Kommentar ( https://stackoverflow.com/a/2223803/1517187 ).
Ich bin damit einverstanden, dass dies das schlechte Design von Java ist.
Viele andere Sprachen unterstützen das Überschreiben statischer Methoden, wie wir in früheren Kommentaren sehen. Ich habe das Gefühl, dass Jay wie ich auch von Delphi nach Java gekommen ist.
Delphi (Object Pascal) war die erste Sprache, die OOP implementierte.
Es ist offensichtlich, dass viele Menschen Erfahrung mit dieser Sprache hatten, da sie in der Vergangenheit die einzige Sprache war, die kommerzielle GUI-Produkte schrieb. Und - ja, wir könnten in Delphi statische Methoden überschreiben. Tatsächlich werden statische Methoden in Delphi als "Klassenmethoden" bezeichnet, während Delphi das andere Konzept der "statischen Delphi-Methoden" hatte, bei denen es sich um Methoden mit früher Bindung handelte. Um Methoden zu überschreiben, für die Sie eine späte Bindung verwenden mussten, deklarieren Sie die "virtuelle" Direktive. Es war also sehr praktisch und intuitiv und ich würde dies in Java erwarten.


3

Was nützt es, statische Methoden zu überschreiben? Sie können keine statischen Methoden über eine Instanz aufrufen.

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

BEARBEITEN: Es scheint, dass Sie durch ein unglückliches Versehen im Sprachdesign statische Methoden über eine Instanz aufrufen können . Im Allgemeinen macht das niemand. Mein Fehler.


8
"Sie können statische Methoden nicht über eine Instanz aufrufen" Eine der Besonderheiten von Java besteht darin, dass Sie statische Methoden über eine Instanz aufrufen können, obwohl dies eine äußerst schlechte Idee ist.
Powerlord

1
In der Tat erlaubt Java den Zugriff auf statische Mitglieder über Instanzen: siehe Statische Variable in Java
Richard JP Le Guen

Eine ordnungsgemäße moderne IDE generiert dabei jedoch eine Warnung, sodass Sie sie zumindest abfangen können, während Oracle die Abwärtskompatibilität aufrechterhalten kann.
Gimby

1
Es ist konzeptionell nichts Falsches daran, eine statische Methode über eine Instanz aufrufen zu können. Dies ist ein Streit um des Streits willen. Warum sollte so etwas wie eine Datumsinstanz NICHT ihre eigenen statischen Methoden aufrufen, um Instanzdaten über die aufrufende Schnittstelle an die Funktion zu übergeben?
RichieHH

@RichieHH Darüber streiten sie nicht. Die Frage ist , warum ist es Anruf erlaubt variable.staticMethod(), statt Class.staticMethod(), wo variableeine Variable mit deklarierten Typ ist Class. Ich bin damit einverstanden, dass es schlechtes Sprachdesign ist.
Fisch

3

Das Überschreiben in Java bedeutet einfach, dass die bestimmte Methode basierend auf dem Laufzeit-Typ des Objekts und nicht auf dem Typ zur Kompilierungszeit des Objekts aufgerufen wird (was bei überschriebenen statischen Methoden der Fall ist). Da statische Methoden Klassenmethoden sind, handelt es sich nicht um Instanzmethoden. Sie haben also nichts damit zu tun, welche Referenz auf welches Objekt oder welche Instanz verweist, da sie aufgrund der Art der statischen Methode zu einer bestimmten Klasse gehört. Sie können es in der Unterklasse neu deklarieren, aber diese Unterklasse weiß nichts über die statischen Methoden der übergeordneten Klasse, da es, wie gesagt, nur für die Klasse spezifisch ist, in der es deklariert wurde. Der Zugriff auf sie mithilfe von Objektreferenzen ist nur eine zusätzliche Freiheit, die von den Designern von Java eingeräumt wird, und wir sollten sicherlich nicht daran denken, diese Praxis nur dann zu beenden, wenn sie mehr Details und Beispiele einschränken http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html


3

Durch Überschreiben erreichen Sie einen dynamischen Polymorphismus. Wenn Sie statische Methoden überschreiben, sind die Wörter, die Sie verwenden möchten, widersprüchlich.

Statisch sagt - Kompilierungszeit, Überschreiben wird für dynamischen Polymorphismus verwendet. Beide sind von Natur aus gegensätzlich und können daher nicht zusammen verwendet werden.

Dynamisches polymorphes Verhalten tritt auf, wenn ein Programmierer ein Objekt verwendet und auf eine Instanzmethode zugreift. JRE ordnet verschiedene Instanzmethoden verschiedener Klassen zu, je nachdem, welche Art von Objekt Sie verwenden.

Wenn Sie statische Methoden überschreiben, greifen wir auf statische Methoden zu, indem wir den Klassennamen verwenden, der zur Kompilierungszeit verknüpft wird. Daher gibt es kein Konzept, Methoden zur Laufzeit mit statischen Methoden zu verknüpfen. Der Begriff "überschreibende" statische Methoden selbst hat also keine Bedeutung.

Hinweis: Selbst wenn Sie mit einem Objekt auf eine Klassenmethode zugreifen, ist der Java-Compiler intelligent genug, um dies herauszufinden, und führt statische Verknüpfungen durch.


Dies trifft in vielen Fällen nicht zu, in denen die statische Methode zur Laufzeit tatsächlich von einer Instanz der enthaltenden Klasse aufgerufen wird und daher durchaus möglich ist, zu bestimmen, welche Instanzen der Funktion aufgerufen werden sollen.
RichieHH

statisch bedeutet nicht Kompilierungszeit, statisch bedeutet, dass es eher an die Klasse als an ein bestimmtes Objekt gebunden ist. Es ist genauso sinnvoll, wenn nicht sogar sinnvoller als das Erstellen einer Klassenfactory, außer dass statisch Box.createBoxsinnvoller ist als BoxFactory.createBoxund ein unvermeidbares Muster ist, wenn die Konstruktion ohne Ausnahmen einer Fehlerprüfung unterzogen werden muss (Konstruktoren können nicht fehlschlagen, sie können nur den Prozess / Wurf beenden Ausnahme), während eine statische Methode bei einem Fehler null zurückgeben oder sogar Erfolgs- / Fehlerrückrufe akzeptieren kann, um so etwas wie hastebin.com/codajahati.java zu schreiben .
Dmitry

2

Die Antwort auf diese Frage ist einfach: Die als statisch gekennzeichnete Methode oder Variable gehört nur zur Klasse. Daher kann diese statische Methode nicht in die Unterklasse vererbt werden, da sie nur zur Superklasse gehört.


1
Hallo G4uKu3_Gaurav. Vielen Dank für Ihre Entscheidung, einen Beitrag zu leisten. Im Allgemeinen erwarten wir jedoch längere und detailliertere Antworten.
DJClayworth

@ DJClayworth Sie sollten diesem Link für detaillierte Antwort folgen geeksforgeeks.org/…
g1ji

Danke für den Link. Eigentlich bin ich hier, um Neulingen auf der Website zu helfen und zu erklären, wie die Website für diejenigen funktioniert, die nicht daran gewöhnt sind, nicht weil ich eine Antwort auf die Frage brauchte.
DJClayworth

1

Einfache Lösung: Verwenden Sie eine Singleton-Instanz. Es ermöglicht Überschreibungen und Vererbung.

In meinem System habe ich die SingletonsRegistry-Klasse, die die Instanz für die übergebene Klasse zurückgibt. Wenn die Instanz nicht gefunden wird, wird sie erstellt.

Haxe Sprachkurs:

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!";
  }

}

Sehr cool, es ist das erste Mal, dass ich von der Programmiersprache Haxe gehört habe :)
cyc115

1
Dies ist in Java viel besser als statische Methode für die Klasse selbst implementiert. Singleton.get(). Die Registrierung ist nur ein Boilerplate-Overhead und schließt GC für die Klassen aus.
Lawrence Dol

Sie haben Recht, es ist eine klassische Lösung. Ich erinnere mich nicht genau, warum ich mich für die Registrierung entschieden habe, hatte wahrscheinlich einen Denkrahmen, der zu diesem Ergebnis führte.
Raivo Fishmeister

1

Eine statische Methode, Variable, Block oder verschachtelte Klasse gehört eher zur gesamten Klasse als zu einem Objekt.

Eine Methode in Java wird verwendet, um das Verhalten eines Objekts / einer Klasse verfügbar zu machen. Da die Methode statisch ist (dh die statische Methode wird nur zur Darstellung des Verhaltens einer Klasse verwendet), wird das Ändern / Überschreiben des Verhaltens der gesamten Klasse das Phänomen einer der Grundpfeiler der objektorientierten Programmierung, dh der hohen Kohäsion, verletzen . (Denken Sie daran, dass ein Konstruktor eine spezielle Methode in Java ist.)

Hoher Zusammenhalt - Eine Klasse sollte nur eine Rolle spielen. Zum Beispiel: Eine Fahrzeugklasse sollte nur Fahrzeugobjekte produzieren und keine Fahrräder, Lastwagen, Flugzeuge usw. Die Fahrzeugklasse kann jedoch einige Merkmale (Verhalten) aufweisen, die nur sich selbst gehören.

Daher beim Entwerfen der Java-Programmiersprache. Die Sprachdesigner dachten, Entwicklern zu erlauben, einige Verhaltensweisen einer Klasse für sich zu behalten, indem sie eine Methode statischer Natur machen.


Die unten Stück Code versucht , die statische Methode außer Kraft zu setzen, aber nicht alle Übersetzungsfehler auftreten.

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

Dies liegt daran, dass wir hier eine Methode nicht überschreiben, sondern sie nur neu deklarieren . Java ermöglicht die erneute Deklaration einer Methode (statisch / nicht statisch).

Das Entfernen des statischen Schlüsselworts aus der getVehileNumber () -Methode der Car-Klasse führt zu einem Kompilierungsfehler. Da wir versuchen, die Funktionalität der statischen Methode zu ändern, die nur zur Vehicle-Klasse gehört.

Wenn getVehileNumber () als final deklariert wird, wird der Code nicht kompiliert, da das Schlüsselwort final den Programmierer daran hindert , die Methode erneut zu deklarieren.

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

Insgesamt liegt es an den Software-Designern, wo die statischen Methoden angewendet werden sollen. Ich persönlich bevorzuge statische Methoden, um einige Aktionen auszuführen, ohne eine Instanz einer Klasse zu erstellen. Zweitens, um das Verhalten einer Klasse vor der Außenwelt zu verbergen.


1

Hier ist eine einfache Erklärung. Eine statische Methode ist einer Klasse zugeordnet, während eine Instanzmethode einem bestimmten Objekt zugeordnet ist. Überschreibungen ermöglichen das Aufrufen der unterschiedlichen Implementierung der überschriebenen Methoden, die dem jeweiligen Objekt zugeordnet sind. Es ist daher nicht intuitiv, statische Methoden zu überschreiben, die nicht einmal Objekten zugeordnet sind, sondern in erster Linie der Klasse selbst. Daher können statische Methoden nicht basierend auf dem aufrufenden Objekt überschrieben werden. Sie werden immer der Klasse zugeordnet, in der sie erstellt wurden.


Wie ist es nicht intuitiv, eine public abstract IBox createBox();interne IBox-Oberfläche zu haben? Box kann IBox implementieren, um createBox zu überschreiben, und die Erstellung eines Objekts führt zu einer gültigen IBox, andernfalls wird eine Null zurückgegeben. Konstruktoren können nicht "null" zurückgeben, und daher sind Sie gezwungen, (1) ÜBERALL Ausnahmen zu verwenden (was wir jetzt tun) oder (2) Factory-Klassen zu erstellen, die das tun, was ich zuvor gesagt habe, aber für Anfänger oder Experten keinen Sinn ergeben von Java (was wir jetzt auch tun). Statische nicht implementierte Methoden lösen dies.
Dmitry

-1

Wenn man nun die obigen Antworten sieht, weiß jeder, dass wir statische Methoden nicht überschreiben können, aber man sollte das Konzept des Zugriffs auf statische Methoden aus der Unterklasse nicht missverstehen .

Wir können auf statische Methoden der Superklasse mit Unterklassenreferenz zugreifen, wenn diese statische Methode nicht durch eine neue statische Methode ausgeblendet wurde, die in der Unterklasse definiert ist.

Zum Beispiel siehe folgenden Code: -

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");
    // }
}

Ausgabe:-

SuperClass saying Hello

Weitere Informationen zum Ausblenden statischer Methoden in der Unterklasse finden Sie in den Java Oracle-Dokumenten. Suchen Sie nach Funktionen in einer Unterklasse .

Vielen Dank


-3

Der folgende Code zeigt, dass es möglich ist:

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
Nein, tut es nicht; Der statisch deklarierte Typ von osmist OverridenStaticMethnicht OverrideStaticMeth.
Lawrence Dol

2
Außerdem würde ich versuchen, zu vermeiden, dass beim Programmieren von <Big Grin> so viel Meth verwendet wird.
Lawrence Dol
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.