it-swarm.com.de

Warum erlaubt Java kein Überschreiben statischer Methoden?

Warum können statische Methoden nicht überschrieben werden?

Verwenden Sie nach Möglichkeit ein Beispiel.

502
sgokhales

Das Überschreiben hängt davon ab, ob eine Instanz einer Klasse vorhanden ist. Der Punkt des Polymorphismus besteht darin, dass Sie eine Klasse in eine Unterklasse unterteilen können und die Objekte, die diese Unterklassen implementieren, ein unterschiedliches Verhalten 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. Ein Grund zur Sorge war die Performance: Smalltalk wurde vielfach kritisiert, dass es zu langsam sei (Garbage Collection und polymorphe Aufrufe gehörten dazu), und Javas Schöpfer waren entschlossen, dies zu vermeiden. Eine andere war die Entscheidung, dass die Zielgruppe für Java C++ - Entwickler waren. Statische Methoden so zu erstellen, wie sie funktionieren, war für C++ - Programmierer vertraut und auch sehr schnell, da nicht bis zur Laufzeit gewartet werden muss, um herauszufinden, welche Methode aufgerufen werden soll.

473
Nathan Hughes

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 werden, während statische Methoden an eine Klasse usw. usw. angehängt werden. 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 normale Angestellte. Wenn Sie jedoch die "statischen" entfernen, erhalten SpecialEmployees einen Bonus von 3%.

(Zugegeben, dieses Beispiel ist insofern ein schlechter Codierungsstil, als Sie im wirklichen Leben wahrscheinlich möchten, dass der Bonusmultiplikator nicht hartcodiert, sondern in einer Datenbank gespeichert wird. Aber das liegt nur daran, dass ich das Beispiel nicht mit viel Aufwand belasten wollte von Code auf den Punkt irrelevant.)

Es erscheint mir durchaus plausibel, dass Sie getBonusMultiplier statisch machen möchten. Möglicherweise möchten Sie den Bonusmultiplikator für alle Kategorien von Mitarbeitern anzeigen können, ohne dass in jeder Kategorie eine Instanz eines Mitarbeiters vorhanden sein muss. Was wäre der Sinn, nach solchen Beispielinstanzen zu suchen? Was ist, wenn wir eine neue Kategorie von Mitarbeitern erstellen und noch keine Mitarbeiter zugewiesen haben? Dies ist logischerweise eine statische Funktion.

Aber es geht nicht.

Und ja, ja, ich kann mir eine beliebige Anzahl von Möglichkeiten vorstellen, um 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 erwartet hätte.

Wenn ich versuchen würde, einen Compiler für eine OOP Sprache zu schreiben, würde ich schnell verstehen, warum die Implementierung dieser Sprache, damit statische Funktionen überschrieben werden können, schwierig oder unmöglich wäre.

Oder vielleicht gibt es einen guten Grund, warum sich Java so verhält. Kann jemand auf einen Vorteil für dieses Verhalten hinweisen, eine Kategorie von Problemen, die dadurch erleichtert werden? Ich meine, zeige mich nicht einfach auf die Sprachspezifikation Java 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? (Neben dem offensichtlichen "es richtig zu machen war zu schwer" ...)

pdate

@VicKirk: Wenn Sie meinen, dass dies "schlechtes Design" ist, weil es nicht 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, es ist schlechtes Design in dem Sinne, dass mit einer Sprache, in der dies funktionierte, etwas grundsätzlich nicht stimmt, dh wenn Statik wie virtuelle Funktionen außer Kraft gesetzt werden könnte, würde dies eine Mehrdeutigkeit hervorrufen, oder es wäre unmöglich, dies zu tun 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 unabhängig von einer Instanz aufrufen möchte und die ich auch 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 umgehe ich das, indem ich die Funktion virtuell mache und dann eine statische Methode erstelle, deren einziger Zweck im Leben 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 zu sein, um dorthin zu gelangen.

175
Jay

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 getan), 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 dienurFälle, die eine Überraschung sein könnten (und von denen die Frage handelt), dieerstezu sein/Fall:

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

und derlastFall:

"Wenn eine statische Methode aus einer Objektmethode einer Klasse aufgerufen wird, wird die statische Methode ausgewählt, auf die von der Klasse selbst undnotvon der Klasse zugegriffen werden kann, die den Lauf definiert. Zeittyp des Objekts. "

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 zwargeerbt(vom übergeordneten Element) sind, jedoch nichtüberschrieben(vom untergeordneten Element). Dies könnte eine Überraschung sein, wenn Sie etwas anderes erwarten.

Aufruf aus einer Objektmethode

ObjectMethodenaufrufe werden mit dem Laufzeittyp aufgelöst, statische (class) Methodenaufrufe werden mit aufgelöst Der (deklarierte) Typ für die Kompilierungszeit.

Regeln ändern

Um diese Regeln so zu ändern, dass der letzte Aufruf im Beispiel Child.printValue() heißt, müssten statische Aufrufe zur Laufzeit mit einem Typ versehen werden, anstatt dass der Compiler den Aufruf zur Kompilierungszeit mit der deklarierten Klasse des Objekts auflöst ( oder 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 zu bewerkstelligen (wenn wir Java: -O ändern würden) und ist keineswegs unvernünftig, hat jedoch einige interessante Überlegungen.

Die wichtigste Überlegung ist, dass wirentscheiden müssen, welchestatischen Methodenaufrufe dies tun sollen.

Momentan hat Java diese "Eigenart" in der Sprache, in der obj.staticMethod()-Aufrufe durch ObjectClass.staticMethod()-Aufrufe ersetzt werden (normalerweise mit einer Warnung). [Hinweis:ObjectClass ist der Typ für die Kompilierung von obj.] Dies sind gute Kandidaten für das Überschreiben auf diese Weise, wobei der Laufzeit-Typ von obj verwendet wird.

Wenn wir dies tun würden, würde das Lesen von Methodenkörpern erschwert: statische Aufrufe in einer übergeordneten Klasse könnten möglicherweisedynamisch"umgeleitet" werden. Um dies zu vermeiden, müssten wir die statische Methode mit einem Klassennamen aufrufen. Dadurch werden die Aufrufe mit der Typhierarchie zur Kompilierungszeit (wie jetzt) ​​offensichtlicher aufgelöst.

Die anderen Methoden zum Aufrufen einer statischen Methode sind schwieriger: this.staticMethod() sollte das Gleiche bedeuten wie obj.staticMethod(), wobei der Laufzeit-Typ this verwendet wird. Dies kann jedoch zu Kopfschmerzen bei vorhandenen Programmen führen, bei denen (anscheinend lokale) statische Methoden ohne Dekoration aufgerufen werden (was wahrscheinlich einer this.method() äquivalent ist).

Was ist mit schmucklosen Anrufen staticMethod()? Ich schlage vor, dass sie dasselbe tun wie heute und den Kontext der lokalen Klasse verwenden, um zu entscheiden, was zu tun ist. Andernfalls würde es zu großer Verwirrung kommen. Natürlich bedeutet dies, dass method()this.method() bedeuten würde, wenn method eine nicht statische Methode und ThisClass.method(), wenn method eine statische Methode wäre. Dies ist eine weitere Quelle der Verwirrung.

Andere Überlegungen

Wenn wir dieses Verhalten ändern (und statische Aufrufe möglicherweise nicht lokal dynamisch ausführen), möchten wir wahrscheinlich die Bedeutung von final, private und protected als Qualifikationsmerkmale für static-Methoden einer Klasse überprüfen. Wir müssten uns dann alle daran gewöhnen, dass die Methoden private static und public final nicht überschrieben werden und daher beim Kompilieren sicher aufgelöst werden können und als lokale Referenzen "sicher" zu lesen sind.

38
Steve Powell

Eigentlich haben wir uns geirrt.
Obwohl Sie mit Java standardmäßig keine statischen Methoden überschreiben können, können Sie bei einer gründlichen Durchsicht der Dokumentation der Klassen und Methodenklassen in Java dennoch eine Möglichkeit finden, das Überschreiben statischer Methoden zu emulieren durch folgende Problemumgehung:

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 :)

Auch wenn wir die dritte Variable Carl als RegularEmployee deklarieren und ihr eine Instanz von SpecialEmployee zuweisen, haben wir im ersten Fall immer noch 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

;)

23
Patlatus

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

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

EDIT

Sie können statische Methoden überladen , das ist in Ordnung. Sie können jedoch keine statische Methode überschreiben , da Klassen keine erstklassigen Objekte sind. Sie können Reflection verwenden, um die Klasse eines Objekts zur Laufzeit abzurufen. Das abgerufene Objekt entspricht jedoch 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 eine statische Methode nicht mit clazz1.staticMethod() auf, sondern mit MyClass.staticMethod(). Eine statische Methode ist nicht an ein Objekt gebunden und daher gibt es in einer statischen Methode keine Vorstellung von this oder super. 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 MyClass zur Laufzeit ein Objekt war, für das Sie eine Methode aufrufen, wie in Smalltalk (oder vielleicht JRuby, wie ein Kommentar vermuten lässt, aber ich weiß nichts über JRuby).

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

17
ewernli

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

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

Obwohl sowohl lassie als auch Kermit als Objekte des Typs Animal deklariert sind, variiert ihr Verhalten (Methode .speak()), da das dynamische Dispatching nur bind Der Methodenaufruf .speak() für eine Implementierung zur Laufzeit - nicht zur Kompilierungszeit.

Hier beginnt nun das Schlüsselwort static Sinn zu machen: Das Wort "statisch" ist ein Antonyme für "dynamisch". Also der Grund Sie können statische Methoden nicht überschreiben, da statische Member nicht dynamisch verteilt werden - , da statisch wörtlich "nicht dynamisch" bedeutet. Wenn sie dynamisch verteilt werden (und könnte daher überschrieben werden) Das Schlüsselwort static würde einfach keinen Sinn mehr ergeben.

13

Ja. Praktisch Java ermöglicht das Überschreiben von statischen Methoden. Wenn Sie theoretisch eine statische Methode in Java überschreiben, wird sie kompiliert und problemlos ausgeführt, verliert jedoch den Polymorphismus, der die grundlegende Eigenschaft von Java darstellt. Sie werden überall lesen, dass es nicht möglich ist, sich selbst zu kompilieren und auszuführen. Du wirst deine Antwort bekommen. z.B. Wenn Sie Class Animal und eine statische Methode eat () haben und diese statische Methode in ihrer Unterklasse überschreiben, wird sie Dog genannt. Wann immer Sie einem Animal Reference ein Dog-Objekt zuweisen und eat () gemäß Javaaufrufen, _ sollte Dog's eat () aufgerufen worden sein, aber in statischem Overriding Animals 'eat () wird 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

Gemäß dem Polymorphismus-Prinzip von Java sollte die Ausgabe Dog Eating sein.
Das Ergebnis war jedoch anders, da zur Unterstützung von Polymorphismus Java Late Binding verwendet wird. Dies bedeutet, dass Methoden nur zur Laufzeit aufgerufen werden, nicht jedoch bei statischen Methoden. In statischen Methoden ruft der Compiler Methoden eher zur Kompilierungszeit als zur Laufzeit auf, daher erhalten wir Methoden gemäß der Referenz und nicht gemäß dem Objekt. Eine Referenz, die enthält. Deshalb können Sie sagen nicht.

9
Shubham Soni

Nun ... die Antwort lautet NEIN, wenn Sie sich überlegen, wie sich eine Überschreibungsmethode in Java verhalten soll. Sie erhalten jedoch keinen Compilerfehler, wenn Sie versuchen, eine statische Methode zu überschreiben. Das heißt, wenn Sie versuchen, dies zu überschreiben, wird Java Sie nicht davon abhalten, dies zu tun. Aber Sie erzielen mit Sicherheit nicht den gleichen Effekt wie bei nicht statischen Methoden. Überschreiben in Java bedeutet einfach, dass die bestimmte Methode basierend auf dem Laufzeit-Typ des Objekts und nicht auf dessen Kompilierzeit-Typ aufgerufen wird (was bei überschriebenen statischen Methoden der Fall ist). Okay ... Vermutungen, warum sie sich seltsam verhalten? Da es sich um Klassenmethoden handelt, wird der Zugriff auf diese Methoden während der Kompilierungszeit immer nur mithilfe der Typinformationen für die Kompilierungszeit aufgelöst. Der Zugriff über Objektreferenzen ist nur eine zusätzliche Freiheit, die die Designer von Java gewähren, und wir sollten auf keinen Fall daran denken, diese Praxis nur dann zu beenden, wenn sie sie einschränken :-)

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. Hierdurch wird bestätigt, dass die statischen Methoden immer nur anhand ihrer Informationen zum Kompilierungstyp aufgelöst werden.

5
Rupesh Yadav

In Java (und vielen OOP Sprachen, aber ich kann nicht für alle sprechen; und einige haben überhaupt keine statische) 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 wenn er innerhalb des Objekts aufgerufen wird, fügt der Compiler automatisch this hinzu.

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

Wegen dieses Unterschieds zwischen den beiden; Virtuelle Methoden haben immer einen Verweis auf das Kontextobjekt (d. h. this), so dass es möglich ist, auf alles innerhalb des Heaps zu verweisen, das zu dieser Instanz des Objekts gehört. Da bei statischen Methoden keine Referenz übergeben wird, kann diese Methode nicht auf Objektvariablen und Methoden zugreifen, 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, stehen im Wesentlichen nur virtuelle Methoden zur Verfügung.

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

Ich weiß nicht viel Ruby, da dies vom OP erwähnt wurde, habe ich einige Nachforschungen angestellt. Ich sehe, dass in Ruby Klassen wirklich eine spezielle Art von Objekt sind und man neue Methoden (sogar dynamisch) erstellen kann. Klassen sind in Ruby vollständige Klassenobjekte und nicht in Java. Dies müssen Sie nur akzeptieren, wenn Sie mit Java (oder C #) arbeiten. Dies sind keine dynamischen Sprachen, obwohl C # einige Formen von Dynamik hinzufügt. In Wirklichkeit verfügt Ruby nicht über "statische" Methoden, soweit ich das beurteilen kann. 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, führt sie immer noch nur die ursprüngliche Statik aus. 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 der Zeit zu verbessern, basierend auf der Technologie und dem Verständnis, das verfügbar war. Die 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. Die Methoden Java static sind nicht mit den Methoden Ruby class identisch. Java -Entwickler werden Schwierigkeiten 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 dieser Begriff wird von Ruby unterschiedlich verwendet. Java hat keine Klassenmethoden im Ruby - Stil (sorry); Ruby verfügt nicht über statische Methoden im Java - Stil, die eigentlich nur alte prozedurale Stilfunktionen sind, wie sie in C zu finden sind.

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

5
Kevin Brock

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

4
DeveloperArnab

Im Allgemeinen ist es nicht sinnvoll, das Überschreiben statischer Methoden zuzulassen, da es keine gute Möglichkeit gibt, zu bestimmen, welche Methode zur Laufzeit aufgerufen werden soll. Nehmen wir das Employee-Beispiel, wenn wir 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 und die Sprache redundant wird, ohne dass dies wirklich von Vorteil ist.

4
Lars

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

4
Patlatus

das Überschreiben ist beispielsweise Mitgliedern vorbehalten, um polymorphes Verhalten zu unterstützen. statische Klassenmitglieder gehören nicht zu einer bestimmten Instanz. Stattdessen gehören statische Member zur Klasse. Daher wird das Überschreiben nicht unterstützt, da Unterklassen nur geschützte und öffentliche Instanzmember und keine statischen Member erben. Möglicherweise möchten Sie eine Schnittstellen- und Forschungsfabrik und/oder Strategieentwurfsmuster definieren, um einen alternativen Ansatz zu bewerten.

4
Athens Holloway

Überschreiben in Java bedeutet einfach, dass die bestimmte Methode basierend auf dem Laufzeittyp des Objekts aufgerufen wird und nicht basierend auf dessen Typ zur Kompilierungszeit (was bei überschriebenen statischen Methoden der Fall ist). Da statische Methoden Klassenmethoden sind, handelt es sich nicht um Instanzmethoden, sodass sie nichts mit der Tatsache zu tun haben, welche Referenz auf welches Objekt oder auf 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 sie, wie gesagt, nur für die Klasse spezifisch ist, in der sie deklariert wurde. Der Zugriff über Objektreferenzen ist nur eine zusätzliche Freiheit, die die Designer von Java gewähren, und wir sollten nicht daran denken, diese Praxis nur dann zu beenden, wenn sie mehr Details und Beispiele enthält http: // faisalbhagat .blogspot.com/2014/09/method-overriding-and-method-hiding.html

2
faisalbhagat

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

Statisch sagt - Kompilierzeit, Ü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 Sie 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: Auch wenn Sie mit einem Objekt auf eine Klassenmethode zugreifen, ist der Compiler Java intelligent genug, um dies herauszufinden, und führt eine statische Verknüpfung durch.

2
user1923551

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

2
G4uKu3_Gaurav

Eine statische Methode, Variable, Block oder verschachtelte Klasse gehört zur gesamten Klasse anstelle eines Objekts.

Eine Methode in Java wird verwendet, um das Verhalten eines Objekts/einer Klasse offen zu legen. Da die Methode statisch ist (dh die statische Methode wird nur zur Darstellung des Verhaltens einer Klasse verwendet.) Ändern/Überschreiben verstößt das Verhalten der gesamten Klasse gegen das Phänomen einer der Grundpfeiler der objektorientierten Programmierung, dh hohe Kohäsion. (Denken Sie daran, dass ein Konstruktor eine spezielle Methode in Java ist.)

Hohe Kohäsion - Eine Klasse sollte nur eine Rolle haben. Zum Beispiel: Eine Autoklasse sollte nur Autoobjekte produzieren und keine Fahrräder, Lastwagen, Flugzeuge usw. Die Autoklasse kann jedoch einige Merkmale (Verhalten) aufweisen, die nur für sich selbst gelten.

Daher beim Entwerfen der Programmiersprache Java. Die Sprachentwickler wollten es Entwicklern ermöglichen, einige Verhaltensweisen einer Klasse für sich zu behalten, indem sie eine Methode statisch machten.


Der folgende Teilcode versucht, die statische Methode zu überschreiben, aber nicht tritt ein Kompilierungsfehler auf.

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 keine Methode überschreiben, sondern nur erneut deklarieren. Java ermöglicht die Neudeklaration einer Methode (statisch/nicht statisch).

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

Wenn getVehileNumber () als final deklariert ist, 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 sie die statischen Methoden anwenden. 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
Rohit Gaikwad

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 können statische Methoden über eine Instanz aufrufen. Im Allgemeinen macht das niemand. Mein Fehler.

1
fastcodejava

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 den Aufruf der unterschiedlichen Implementierung der überschriebenen Methoden, die dem jeweiligen Objekt zugeordnet sind. Daher ist es nicht intuitiv, statische Methoden zu überschreiben, die nicht einmal mit Objekten, sondern in erster Linie mit der Klasse selbst verknüpft sind. Damit statische Methoden nicht aufgrund des aufgerufenen Objekts überschrieben werden können, wird sie immer der Klasse zugeordnet, in der sie erstellt wurden.

1
Rafsan Mobasher

Einfache Lösung: Verwenden Sie eine Singleton-Instanz. Überschreibungen und Vererbung sind möglich.

In meinem System gibt es 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!";
  }

}
1