Ich suche nach einer endgültigen Antwort von einer primären oder sekundären Quelle, um herauszufinden, warum (insbesondere) Java und C # beschlossen haben, eine statische Methode als Einstiegspunkt zu verwenden, anstatt eine Anwendungsinstanz durch eine Instanz einer Application
Klasse (mit dem Einstiegspunkt) darzustellen ein geeigneter Konstruktor sein).
Hintergrund und Details meiner bisherigen Forschung
Dies wurde schon früher gefragt. Leider werfen die vorhandenen Antworten nur die Frage auf . Insbesondere die folgenden Antworten befriedigen mich nicht, da ich sie für falsch halte:
- Es würde Mehrdeutigkeit geben, wenn der Konstruktor überladen wäre. - Tatsächlich lässt C # (sowie C und C ++) unterschiedliche Signaturen zu,
Main
sodass dieselbe potenzielle Mehrdeutigkeit besteht und behandelt wird. - Eine
static
Methode bedeutet, dass keine Objekte instanziiert werden können, bevor die Reihenfolge der Initialisierung klar ist. - Dies ist nur sachlich falsch, einige Objekte werden vorher instanziiert (zB in einem statischen Konstruktor). - Sie können also von der Laufzeit aufgerufen werden, ohne dass ein übergeordnetes Objekt instanziiert werden muss. - Das ist überhaupt keine Antwort.
Nur um weiter zu begründen, warum ich dies für eine berechtigte und interessante Frage halte:
Viele Frameworks tun Klassen verwenden , um Anwendungen zu repräsentieren, und Konstrukteuren als Einstiegspunkte. Beispielsweise verwendet das VB.NET-Anwendungsframework einen dedizierten Hauptdialog (und dessen Konstruktor) als Einstiegspunkt 1 .
Weder Java noch C # benötigen technisch eine Hauptmethode. Nun, C # braucht eines zum Kompilieren, aber Java nicht einmal das. Und in keinem Fall wird es für die Ausführung benötigt. Dies scheint also keine technische Einschränkung zu sein. Und, wie ich im ersten Absatz erwähnt habe, scheint es für eine bloße Konvention seltsamerweise nicht mit dem allgemeinen Entwurfsprinzip von Java und C # vereinbar zu sein.
Um es klar zu sagen, es ist nicht besonders nachteilig , eine statische main
Methode zu haben, es ist einfach merkwürdig , weshalb ich mich fragte, ob dahinter ein technisches Grundprinzip steckt.
Ich bin an einer endgültigen Antwort aus einer primären oder sekundären Quelle interessiert, nicht an bloßen Spekulationen.
1 Obwohl es einen Callback ( Startup
) gibt, der dies abfangen kann.
quelle
Antworten:
TL; DR
In Java ist der Grund
public static void main(String[] args)
dafürFür C # ist die Argumentation sozusagen transitiv ähnlich . Die Sprachentwickler haben die Syntax des Programmeinstiegspunkts für Programmierer aus Java beibehalten . Wie der C # -Architekt Anders Hejlsberg es ausdrückt ,
Lange Version
oben erweitern und mit langweiligen Referenzen gesichert.
Java Terminator Hasta la Vista Baby!
VM Spec, 2.17.1 Start der virtuellen Maschine
... siehe auch: Anhang: Ich brauche deine Klamotten, deine Stiefel und dein Motorrad
Zielgerichtete Ausführung für die Verwendung als typische Skripte in der Befehlszeilenschnittstelle.
wichtiger Nebenschritt
... das hilft, ein paar falsche Spuren in unserer Untersuchung zu vermeiden.
VM Spec, 1.2 Die Java Virtual Machine
Ich habe oben beim Studium des vorherigen Kapitels - 1.1 Geschichte bemerkt, was ich für hilfreich hielt (aber als nutzlos herausstellte).
Ausführung wird ausschließlich durch die VM-Spezifikation geregelt, die
ausdrücklich erklärt, dass sie nichts mit der Java-Sprache zu tun hat
=> OK, um JLS und jegliche Java-Sprache überhaupt zu ignorieren
Gosling: ein Kompromiss zwischen C und Skriptsprache ...
Basierend auf den obigen Angaben habe ich begonnen, das Web nach JVM-Verlauf zu durchsuchen . Hat nicht geholfen, zu viel Müll in den Ergebnissen.
Dann erinnerte ich mich an Legenden über Gosling und beschränkte meine Suche auf die Gosling JVM-Geschichte .
Eureka! Wie die JVM-Spezifikation entstanden ist
explizite Erklärung, dass zum Zeitpunkt der Erstellung
C und Scripting als wichtigste Einflüsse betrachtet wurden.
Bereits Nicken zu Scripting in VM Spec 2.17.1, gesehen
hinreichend erklären Befehlszeilenargumente
String[] args
aber
static
undmain
sind noch nicht da, müssen weiter graben ...Beachten Sie, während Sie dies eingeben - indem Sie C, Scripting und VM Spec 1.2 mit dem Nichts von Java verbinden -, dass ich das Gefühl habe, dass etwas Vertrautes, etwas ... Objektorientiertes langsam vergeht. Nimm meine Hand und beweg dich weiter. Mach nicht langsamer, wir sind fast da
Die Keynote-Folien sind online verfügbar: 20_Gosling_keynote.pdf. Dies ist sehr praktisch, um wichtige Punkte zu kopieren.
Aha! Schauen wir uns die C-Syntax genauer an .
Kommen wir näher? Sie wetten. Es lohnt sich auch, dem "Haupt" -Link aus dem obigen Zitat zu folgen:
Um für C-Entwickler komfortabel zu sein, muss der Programmeinstiegspunkt sein
main
.Da Java erfordert, dass eine Methode in der Klasse enthalten ist,
Class.main
ist esso nah wie möglich: statischer Aufruf, nur Klassenname und Punkt,
bitte keine Konstruktoren - C weiß nichts dergleichen.
Dies gilt auch transitiv für C #, wobei
die Idee einer einfachen Migration von Java zu C # berücksichtigt wird .
Leser, die der Meinung sind, dass der Einstiegspunkt in ein vertrautes Programm keine Rolle spielt, werden gebeten, nach Stack Overflow-Fragen zu suchen und zu suchen, bei denen Jungs aus Java SE versuchen, Hello World für Java ME MIDP zu schreiben . Hinweis Der MIDP-Einstiegspunkt hat kein
main
Norstatic
.Fazit
Basierend auf oben ich sagen würde
static
,main
undString[] args
war in den Momenten von Java und C # Schaffung vernünftigste Wahl zu definieren Programmeinstiegspunkt .Anhang: Ich brauche deine Kleidung, deine Stiefel und dein Motorrad
Zugegeben , das Lesen von VM Spec 2.17.1 hat riesigen Spaß gemacht.
Symbolische Verweise von
Terminator
oh yeah.quelle
Das fühlt sich für mich nur vage beleidigend an. Ein Konstruktor wird zur Initialisierung eines Objekts verwendet: Er richtet ein Objekt ein, das dann von dem Code verwendet wird, der es erstellt hat.
Wenn Sie grundlegende Verwendungsfunktionen in den Konstruktor integrieren und dann niemals das Objekt verwenden, das der Konstruktor in externem Code erstellt, verstoßen Sie gegen die Prinzipien von OOP. Grundsätzlich macht man etwas wirklich seltsames ohne ersichtlichen Grund.
Warum würdest du das sowieso wollen?
quelle
Main
Methode eignet sich für den einfachen Fall und ist in schwierigeren Fällen kein wirkliches Problem. Warum also nicht?Für Java halte ich die Argumentation für einfach: Bei der Entwicklung von Java wussten die Entwickler, dass die meisten Leute, die die Sprache lernen, C / C ++ bereits im Voraus kennen würden.
Daher sieht Java nicht nur wie C / C ++ aus, anstatt wie Smalltalk, sondern hat auch die Idiosynchrese von C / C ++ übernommen (man denke nur an oktale Integer-Literale). Da c / c ++ beide eine Hauptmethode verwenden, machte es unter diesem Gesichtspunkt Sinn, dasselbe für Java zu tun.
Ich bin mir ziemlich sicher, dass ich mich erinnere, dass Bloch oder jemand in diesem Sinne etwas darüber gesagt hat, warum er oktale Integer-Literale hinzugefügt hat. Ich werde sehen, ob ich einige Quellen finden kann :)
quelle
:
zuextends
? Undpublic static void main(String [ ] args)
innerhalb einer Klasse ist ganz anders alsint main(int argc, char **argv)
außerhalb einer Klasse.:
zuextends
ist eine Frage der Syntax und im Wesentlichen identisch. Alles andere wird von der Sprache vorgegeben.main()
, wenn es in anderen Fällen anscheinend nicht wichtig genug war?Nun, es gibt viele Hauptfunktionen, die nur eine Endlosschleife durchlaufen. Ein Konstruktor, der auf diese Weise arbeitet (mit einem Objekt, das niemals konstruiert wird), erscheint mir seltsam.
Es gibt so viele lustige Dinge an diesem Konzept. Ihre Logik läuft auf einem ungeborenen Objekt, Objekten, die geboren wurden, um zu sterben (da sie alle ihre Arbeit im Konstruktor erledigen), ...
Würden nicht all diese Nebenwirkungen den OO-Wagen viel mehr beschädigen als eine einfache öffentliche (weil sie von einem unbekannten Benutzer aufgerufen werden muss) statische (weil wir keine Instanz benötigen, um loszulegen) Leere Haupt (weil es der Einstiegspunkt ist) )?
Damit ein einfacher, einfacher Funktionseinstiegspunkt in Java vorhanden ist, werden automatisch öffentliche und statische Funktionen benötigt. Obwohl es sich um eine statische Methode handelt , läuft sie darauf hinaus, was wir einer einfachen Funktion näher bringen können, um das zu erreichen, was gewünscht wird: einen einfachen Einstiegspunkt.
Wenn Sie keinen einfachen Funktionseinstiegspunkt als Einstiegspunkt verwenden möchten. Was kommt als nächstes, das als Konstrukteur, der nicht konstruiert werden soll, nicht seltsam erscheint?
quelle
Sie können während der Entwicklung schnell einige eigenständige Tests für eine Klasse ausführen, indem Sie ein
main()
in die Klasse einfügen, die Sie testen möchten.quelle
Du musst irgendwo anfangen. Ein statisches main ist die einfachste Ausführungsumgebung, die Sie haben können - es muss keine Instanz von irgendetwas (außerhalb der JVM und der einfachen Zeichenfolgenparameter) erstellt werden -, damit es mit einem Minimum an Aufwand (und geringer Wahrscheinlichkeit) "erstellt" werden kann eines Codierungsfehlers, der das Starten verhindert, usw.) und kann einfache Dinge ohne viele andere Einstellungen ausführen.
Grundsätzlich eine Anwendung von KISS.
[Und natürlich ist der Hauptgrund: Warum nicht?]
quelle
Nach meinem Verständnis ist der Hauptgrund einfach. Sun war ein Unix-Unternehmen, das Unix-Maschinen verkaufte, und für Unix wurde die C- Konvention "main (args)" zum Aufrufen einer Binärdatei entwickelt.
Darüber hinaus wurde Java explizit so konzipiert, dass es für C- und C ++ - Programmierer einfach zu erlernen ist. Es gab also keinen guten Grund, nicht einfach die C-Konvention aufzugreifen.
Der gewählte Ansatz, bei dem jede Klasse eine Aufrufmethode haben kann, ist sehr flexibel, insbesondere in Kombination mit der
Main-Class
Zeile in der Datei MANIFEST.MF in einem ausführbaren Jar.quelle
Es entspricht nicht der OOP-Philosophie, dass ein Programm aus Sicht des Betriebssystemprozesses ein Objekt ist, da es per Definition keine Möglichkeit gibt, mehr als eines zu haben.
Darüber hinaus ist ein Konstruktor keinesfalls ein Einstiegspunkt.
Es scheint mir die vernünftigste Wahl zu sein, main als statische Funktion zu haben, die es eigentlich am Ende des Tages ist. Angesichts der Architektur von VMs wie JVM und CLR würde jede andere Wahl diese unnötig vorantreiben.
quelle
Runnable
Objekten mit mehreren Threads.