Warum ist es nicht möglich, statische Methoden außer Kraft zu setzen?
Wenn möglich, verwenden Sie bitte ein Beispiel.
Warum ist es nicht möglich, statische Methoden außer Kraft zu setzen?
Wenn möglich, verwenden Sie bitte ein Beispiel.
Das Überschreiben von Methoden wird ermöglicht durch dynamische Disposition Das bedeutet, dass nicht der deklarierte Typ eines Objekts sein Verhalten bestimmt, sondern sein Laufzeittyp:
Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"
Auch wenn beide lassie
y kermit
werden als Objekte des Typs Animal
und ihr Verhalten (Methode .speak()
) variiert, da die dynamische Abfertigung nur binden den Methodenaufruf .speak()
für eine Implementierung zur Laufzeit - nicht zur Kompilierzeit.
Nun, hier ist die static
beginnt, Sinn zu machen: Das Wort "statisch" ist ein Antonym für "dynamisch". Der Grund, warum Sie statische Methoden nicht überschreiben können, ist, dass es kein dynamisches Dispatching für statische Mitglieder gibt. denn statisch bedeutet wörtlich "nicht dynamisch". Wenn sie dynamisch versendet werden (und somit überschrieben werden können), wird die static
Das Schlüsselwort würde einfach keinen Sinn mehr machen.
Ich glaube nicht, dass man anhand der internen Implementierung zwischen "statisch" und "dynamisch" argumentieren sollte. Das ist das API-Schlüsselwort einer Sprache. Was erwartet der Programmierer? Statische Methoden liefern konstante Ergebnisse während der Ausführung (für eine bestimmte Klasse) => statisch. Member-Funktionen geben Ergebnisse zurück, die von den Variablen der Instanz abhängen (die sich während der Ausführung ändern können) => dynamisch.
Ja. Praktisch erlaubt Java das Überschreiben statischer Methoden, und theoretisch nicht, wenn Sie eine statische Methode in Java überschreiben, dann wird sie kompiliert und läuft reibungslos, aber sie verliert die Polymorphie, die die grundlegende Eigenschaft von Java ist. Sie werden überall lesen, dass es nicht möglich ist, selbst zu versuchen, zu kompilieren und zu laufen. Sie werden Ihre Antwort bekommen. z.B. Wenn Sie die Klasse Animal und eine statische Methode eat() haben und Sie diese statische Methode in ihrer Unterklasse überschreiben, nennen wir sie Dog. Wenn Sie dann, wo auch immer, ein Dog-Objekt einer Animal-Referenz zuweisen und eat() aufrufen, sollte laut Java Dog's eat() aufgerufen werden, aber in der statischen Überschreibung von Animals' eat() wird es 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 sein Dog Eating
.
Das Ergebnis war jedoch anders, da Java zur Unterstützung von Polymorphismus Late Binding verwendet, was bedeutet, dass Methoden nur zur Laufzeit aufgerufen werden, nicht aber im Fall von statischen Methoden. Bei statischen Methoden ruft der Compiler die Methoden zur Kompilierzeit und nicht zur Laufzeit auf, so dass wir Methoden entsprechend der Referenz und nicht entsprechend dem Objekt, das eine Referenz enthält, erhalten.
In Java (und vielen anderen OOP-Sprachen, aber ich kann nicht für alle sprechen; und einige haben überhaupt keine Statik) haben alle Methoden eine feste Signatur - die Parameter und Typen. In einer virtuellen Methode ist der erste Parameter implizit: ein Verweis auf das Objekt selbst, und wenn er aus dem Objekt heraus aufgerufen wird, fügt der Compiler automatisch this
.
Bei statischen Methoden gibt es keinen Unterschied - sie haben weiterhin eine feste Signatur. Indem Sie die Methode jedoch als statisch deklarieren, haben Sie ausdrücklich festgelegt, dass der Compiler den impliziten Objektparameter am Anfang der Signatur nicht einschließen darf. Jeder andere Code, der diese Methode aufruft, muss daher darf nicht versuchen, einen Verweis auf ein Objekt auf den Stack zu legen . Wenn dies der Fall wäre, würde die Ausführung der Methode nicht funktionieren, da die Parameter an der falschen Stelle - um eins verschoben - auf dem Stack liegen würden.
Aufgrund dieses Unterschieds zwischen den beiden haben virtuelle Methoden immer einen Verweis auf das Kontextobjekt (d.h. this
), so dass es möglich ist, auf alles im Heap zu verweisen, was zu dieser Instanz des Objekts gehört. Da bei statischen Methoden jedoch kein Verweis übergeben wird, kann diese Methode nicht auf Objektvariablen und -methoden zugreifen, da der Kontext nicht bekannt ist.
Wenn Sie wünschen, dass Java die Definition so ändert, dass für jede Methode, ob statisch oder virtuell, ein Objektkontext übergeben wird, dann hätten Sie im Wesentlichen nur virtuelle Methoden.
Wie jemand in einem Kommentar zum Beitrag fragte - was ist Ihr Grund und Zweck für den Wunsch nach dieser Funktion?
Ich weiß nicht, Ruby viel, wie dies von der OP erwähnt wurde, habe ich einige Forschung. Ich sehe, dass in Ruby Klassen wirklich eine besondere Art von Objekt sind und man kann (sogar dynamisch) neue Methoden erstellen. Klassen sind in Ruby vollständige Klassenobjekte, in Java nicht. Das ist etwas, das Sie akzeptieren müssen, wenn Sie mit Java (oder C#) arbeiten. Dies sind keine dynamischen Sprachen, obwohl C# einige Formen der Dynamik hinzufügt. Soweit ich herausfinden konnte, gibt es in Ruby keine "statischen" Methoden - in diesem Fall handelt es sich um Methoden für das Objekt der Singleton-Klasse. Sie können dann dieses Singleton mit einer neuen Klasse überschreiben und die Methoden des vorherigen Klassenobjekts rufen die in der neuen Klasse definierten auf (korrekt?). Wenn man also eine Methode im Kontext der ursprünglichen Klasse aufruft, wird nur die ursprüngliche Statik ausgeführt, aber wenn man eine Methode in der abgeleiteten Klasse aufruft, werden entweder die Methoden der Eltern- oder der Unterklasse aufgerufen. Interessant, und ich kann darin einen gewissen Nutzen erkennen. Es erfordert ein anderes Denkmuster.
Da Sie in Java arbeiten, müssen Sie sich an diese Arbeitsweise gewöhnen. Warum haben sie das getan? Nun, wahrscheinlich, um die Leistung auf der Grundlage der damals verfügbaren Technologie und des damaligen Verständnisses zu verbessern. Computersprachen entwickeln sich ständig weiter. Wenn man weit genug zurückgeht, gibt es so etwas wie OOP noch nicht. In der Zukunft wird es andere neue Ideen geben.
EDITAR : Eine weitere Bemerkung. Jetzt, da ich die Unterschiede sehe und selbst Java/C#-Entwickler bin, kann ich verstehen, warum die Antworten, die man von Java-Entwicklern erhält, verwirrend sein können, wenn man aus einer Sprache wie Ruby kommt. Java static
Methoden sind nicht dasselbe wie in Ruby class
Methoden. Java-Entwickler werden dies nur schwer verstehen können, ebenso wie umgekehrt diejenigen, die hauptsächlich mit einer Sprache wie Ruby/Smalltalk arbeiten. Ich kann mir vorstellen, dass dies auch deshalb sehr verwirrend ist, weil Java ebenfalls den Begriff "Klassenmethode" verwendet, um über statische Methoden zu sprechen, während dieser Begriff in Ruby anders verwendet wird. Java hat keine Klassenmethoden im Stil von Ruby (sorry); Ruby hat keine statischen Methoden im Stil von Java, die eigentlich nur alte prozedurale Funktionen sind, wie man sie in C findet.
Übrigens - danke für die Frage! Ich habe heute etwas Neues für mich über Klassenmethoden (Ruby-Stil) gelernt.
Nun... die Antwort ist NEIN, wenn man aus der Perspektive betrachtet, wie sich eine überschriebene Methode in Java verhalten sollte. Aber Sie erhalten keinen Compilerfehler, wenn Sie versuchen, eine statische Methode zu überschreiben. Das heißt, wenn Sie versuchen, eine statische Methode zu überschreiben, wird Java Sie nicht daran hindern, aber Sie erhalten sicherlich nicht den gleichen Effekt wie bei nicht-statischen Methoden. Überschreiben in Java bedeutet einfach, dass die betreffende Methode auf der Grundlage des Laufzeittyps des Objekts aufgerufen wird und nicht auf der Grundlage des Kompilierzeittyps (was bei überschriebenen statischen Methoden der Fall ist). Okay... haben Sie eine Vermutung, warum sich diese Methoden so seltsam verhalten? Weil es sich um Klassenmethoden handelt und daher der Zugriff auf sie während der Kompilierungszeit immer nur anhand der Kompilierungszeit-Typinformationen aufgelöst wird. Der Zugriff auf sie über Objektreferenzen ist nur eine zusätzliche Freiheit, die uns die Designer von Java gewährt haben, und wir sollten sicher nicht daran denken, diese Praxis zu unterbinden, nur weil 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 identisch mit der dritten Zeile sein müssen, da wir die 'staticMethod()' auf einem Objekt vom Laufzeittyp 'SubClass' und nicht als 'SuperClass' aufrufen. Dies bestätigt, dass die statischen Methoden immer nur anhand ihrer Kompilierzeit-Typinformationen aufgelöst werden.
Ich mag und verdopple den Kommentar von Jay ( 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 wie ich auch von Delphi zu Java gekommen ist.
Delphi (Object Pascal) war eine der Sprachen, die OOP vor Java implementierten, und eine der ersten Sprachen, die für die kommerzielle Anwendungsentwicklung verwendet wurden.
Es ist offensichtlich, dass viele Leute Erfahrung mit dieser Sprache hatten, da sie in der Vergangenheit die einzige Sprache war, um kommerzielle GUI-Produkte zu schreiben. Und - ja, wir konnten in Delphi statische Methoden überschreiben. Eigentlich werden statische Methoden in Delphi "Klassenmethoden" genannt, während Delphi das andere Konzept der "Delphi static methods" hatte, die Methoden mit früher Bindung waren. Um Methoden zu überschreiben, musste man die späte Bindung verwenden und die Direktive "virtual" deklarieren. Es war also sehr bequem und intuitiv, und ich würde dies auch in Java erwarten.
Delphi (Object Pascal) war die erste Sprache, die OOP implementierte. Simula, SmallTalk und andere unterstützten OOP und kamen alle vor Delphi.
@WJS Ich habe noch nie von Simula oder anderen Sprachen gehört, die OOP unterstützen. Ich glaube, Delphi war die erste Sprache, die OOP implementierte und in der kommerziellen Anwendungsentwicklung eingesetzt wurde und weithin bekannt war. Es sieht so aus, als müsste ich diese Aussage umformulieren
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
3 Stimmen
Die meisten OOP-Sprachen lassen dies nicht zu.
11 Stimmen
@jmucchiello: siehe meine Antwort. Ich habe dasselbe gedacht wie Sie, aber dann habe ich von den Ruby/Smalltalk-"Klassen"-Methoden erfahren, und es gibt also auch andere echte OOP-Sprachen, die das tun.
6 Stimmen
@jmucchiello die meisten OOP-Sprachen sind keine echten OOP-Sprachen (ich denke an Smalltalk)
0 Stimmen
Siehe auch stackoverflow.com/q/370962/632951
0 Stimmen
Python erlaubt das Überschreiben einer statischen Methode. stackoverflow.com/questions/893015/
2 Stimmen
Kann daran liegen, dass Java Aufrufe zu statischen Methoden zur Kompilierzeit auflöst. Selbst wenn Sie also geschrieben haben
Parent p = new Child()
und dannp.childOverriddenStaticMethod()
löst der Compiler es auf inParent.childOverriddenStaticMethod()
indem Sie sich den Referenztyp ansehen.0 Stimmen
Huzzah, wir können jetzt Dinge schreiben wie hastebin.com/codajahati.java . Mit einem solchen Muster (vorzugsweise mit weniger plumpen Code) kann Java im Wesentlichen alle Ausnahmen aus der Kernbibliothek eliminieren (kann, nicht wird), oder wir können einfach Dinge verpacken.