it-swarm.com.de

Warum eine statische Hauptmethode in Java und C #) anstelle eines Konstruktors?

Ich suche nach einer endgültigen Antwort von einer primären oder sekundären Quelle, warum (insbesondere) Java und C # beschlossen, eine statische Methode als Einstiegspunkt zu verwenden, anstatt eine Anwendungsinstanz durch eine darzustellen Instanz einer Application Klasse (wobei der Einstiegspunkt ein geeigneter Konstruktor ist).


Hintergrund und Details meiner früheren Forschung

Dies wurde schon einmal gefragt. Leider sind die vorhandenen Antworten nur wirft die Frage auf . Insbesondere die folgenden Antworten befriedigen mich nicht, da ich sie für falsch halte:

  • Es wäre mehrdeutig, wenn der Konstruktor überladen wäre. - Tatsächlich erlaubt C # (sowie C und C++) unterschiedliche Signaturen für Main also besteht die gleiche potentielle Mehrdeutigkeit und wird behandelt.
  • Eine static -Methode bedeutet, dass keine Objekte vorher instanziiert werden können, sodass 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 zur Laufzeit aufgerufen werden, ohne ein übergeordnetes Objekt instanziieren zu müssen. - Dies ist überhaupt keine Antwort.

Nur um weiter zu rechtfertigen, warum ich dies für eine gültige und interessante Frage halte:

  • Viele Frameworks verwenden Klassen, um Anwendungen darzustellen, und Konstruktoren als Einstiegspunkte. Beispielsweise verwendet das VB.NET-Anwendungsframework einen dedizierten Hauptdialog (und seinen Konstruktor) als Einstiegspunkt1.

  • Weder Java noch C # technisch benötigen eine Hauptmethode. Nun, C # braucht eine 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, z eine bloße Konvention, die seltsamerweise nicht mit dem allgemeinen Entwurfsprinzip von Java und C #) übereinstimmt.

Um klar zu sein, es gibt keinen spezifischen Nachteil , eine statische main -Methode zu haben, es ist nur eindeutig ungerade , was mich fragte, ob dahinter eine technische Begründung steckte.

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 Rückruf (Startup) gibt, der dies abfangen kann.

55
Konrad Rudolph

TL; DR

In Java ist der Grund für public static void main(String[] args) der folgende

  1. Gosling gesucht
  2. der Code, der von jemandem geschrieben wurde, der Erfahrung mit C hat (nicht mit Java)
  3. von jemandem ausgeführt werden, der es gewohnt ist, PostScript on NeWS auszuführen

http://i.stack.imgur.com/qcmzP.png


Für C # ist die Argumentation sozusagen transitiv ähnlich. Sprachdesigner haben die Syntax - Programmeinstiegspunkt für Programmierer aus Java beibehalten. Wie C # Architekt Anders Hejlsberg es ausdrückt ,

... unser Ansatz mit C # war einfach, Java Programmierern eine Alternative anzubieten ...

Lange Version

oben erweitern und mit langweiligen Referenzen untermauert.

Java Terminator Hasta la Vista Baby!

VM Spec, 2.17.1 Start der virtuellen Maschine

... Die Art und Weise, in der die ursprüngliche Klasse für die virtuelle Maschine Java angegeben wird, liegt außerhalb des Bereichs dieser Spezifikation. In Hostumgebungen, in denen Befehlszeilen verwendet werden, ist dies jedoch typisch für den vollständig qualifizierten Namen der Klasse als Befehlszeilenargument anzugeben und nachfolgende Befehlszeilenargumente als Zeichenfolgen zu verwenden, die als Argument für die Methode main bereitgestellt werden sollen. Verwenden Sie beispielsweise das Befehlszeile Java 2 von Sun für Solaris

Java Terminator Hasta la Vista Baby!

startet eine virtuelle Java Maschine, indem sie die Methode main der Klasse Terminator (eine Klasse in einem unbenannten Paket) aufruft und ihr ein Array mit den vier Zeichenfolgen "Hasta", "la", "Vista" übergibt ", und Baby!"...

... siehe auch: Anhang: Ich brauche deine Kleidung, deine Stiefel und dein Motorrad

  • Meine Interpretation:
    Ausführung zur Verwendung wie typische Skripte in der Befehlszeilenschnittstelle.

wichtiger Seitenschritt

... das hilft, ein paar falsche Spuren in unserer Untersuchung zu vermeiden.

VM Spec, 1.2 Die virtuelle Maschine Java

Die virtuelle Maschine Java kennt die Programmiersprache Java nicht ...

Ich habe oben beim Studium des vorherigen Kapitels - 1.1 Geschichte bemerkt, was ich für hilfreich hielt (aber als nutzlos herausstellte).

  • Meine Interpretation:
    Die Ausführung von wird allein durch die Spezifikation VM geregelt
    erklärt ausdrücklich, dass es nichts mit der Sprache Java zu tun hat
    => OK, um [~ # ~] jls [~ # ~] und alles, was mit Java zu tun hat, zu ignorieren

Gosling: ein Kompromiss zwischen C und Skriptsprache ...

Basierend auf dem oben Gesagten begann ich im Web nach JVM-Verlauf zu suchen. Hat nicht geholfen, zu viel Müll in den Ergebnissen.

Dann erinnerte ich mich an Legenden über Gosling und beschränkte meine Suche auf Gosling JVM-Geschichte.

Eureka! Wie die JVM-Spezifikation zustande kam

In dieser Keynote des JVM Languages ​​Summit 2008 diskutiert James Gosling ... Javas Erstellung, ... einen Kompromiss zwischen C und Skriptsprache ...

  • Meine Interpretation:
    ausdrückliche Erklärung, dass zum Zeitpunkt der Schöpfung,
    C und Scripting wurden als wichtigste Einflüsse angesehen.

    Bereits gesehen, wie in VM Spec 2.17.1,
    Befehlszeilenargumente erklären ausreichend String[] args
    Aber static und main sind noch nicht da, müssen weiter graben ...

Beachten Sie, dass ich während der Eingabe - Verbinden von C, Scripting und VM Spec 1.2 mit seinem Nichts von Java - das Gefühl habe, dass etwas Vertrautes, etwas ... objektorientiert langsam vergeht . Nimm meine Hand und bewege dich nicht langsamer, wir sind jetzt fast da

Keynote-Folien sind online verfügbar: 20_Gosling_keynote.pdf , sehr praktisch zum Kopieren wichtiger Punkte.

 Seite 3 
 
 Die Vorgeschichte von Java 
 * Was mein Denken geprägt hat 
 
 Seite 9 
 
 NeWS 
 * Vernetztes erweiterbares Fenstersystem 
 * Ein auf Skripten basierendes Fenstersystem .... 
 PostScript (!!) 
 
 Seite 16 
 
 Ein großes (aber ruhiges) Ziel: 
 Wie nahe könnte ich einem 
 "Scripting" -Gefühl kommen ... 
 
 Seite 19 
 
 Das ursprüngliche Konzept 
 * Ging es darum, 
 Netzwerke von Dingen aufzubauen, 
, die durch ein Skript 
 Sprache 
 * (Unix-Shells, AppleScript, ...) 
 
 Seite 20 
 
 Ein Wolf im Schafspelz 
 * C-Syntax, um Entwicklern 
 Bequem zu machen 

Aha! Schauen wir uns C-Syntax genauer an.

Das Beispiel "Hallo Welt" ...

main()
{
    printf("hello, world\n");
}

... wird eine Funktion namens main definiert. Die Funktion main erfüllt in C-Programmen einen besonderen Zweck. Die Laufzeitumgebung ruft die Hauptfunktion auf, um mit der Programmausführung zu beginnen.

... Die Hauptfunktion hat tatsächlich zwei Argumente, int argc Und char *argv[], Mit denen Befehlszeilenargumente verarbeitet werden können ...

Kommen wir näher? Sie wetten. Es lohnt sich auch, dem "Haupt" -Link aus dem obigen Zitat zu folgen:

die Hauptfunktion ist, wo ein Programm die Ausführung startet. Es ist für die allgemeine Organisation der Programmfunktionalität verantwortlich und hat normalerweise Zugriff auf die Befehlsargumente, die dem Programm bei seiner Ausführung gegeben wurden.

  • Meine Interpretation:
    Um sich für C-Entwickler wohl zu fühlen, muss der Programmeinstiegspunkt main sein.
    Da Java erfordert, dass eine Methode in der Klasse ist, ist Class.main
    so nah wie möglich: statischer Aufruf, nur Klassenname und Punkt,
    bitte keine Konstruktoren - C weiß nichts dergleichen.

    Dies gilt auch transitiv gilt unter Berücksichtigung von C #
    die Idee einer einfachen Migration von Java dorthin.

Leser, die der Meinung sind, dass ein vertrauter Programmeinstiegspunkt keine Rolle spielt, werden gebeten, Fragen zum Stapelüberlauf zu suchen und zu überprüfen, bei denen Leute von Java SE versuchen, Hello World für Java ME MIDP. Hinweis MIDP-Einstiegspunkt hat weder main noch static.

Fazit

Basierend auf dem oben Gesagten würde ich sagen, dass static, main und String[] args In den Momenten der Java - und C # -Erstellung die vernünftigsten Entscheidungen waren, um zu definieren + Programmeinstiegspunkt .

Anhang: Ich brauche deine Kleidung, deine Stiefel und dein Motorrad

Ich muss zugeben, dass das Lesen von VM Spec 2.17.1 enormen Spaß gemacht hat.

... die Kommandozeile

Java Terminator Hasta la Vista Baby!

startet eine virtuelle Java Maschine, indem sie die Methode main der Klasse Terminator (eine Klasse in einem unbenannten Paket) aufruft und ihr ein Array mit den vier Zeichenfolgen "Hasta", "la", "Vista" übergibt ", und Baby!".

Wir skizzieren nun die Schritte, die die virtuelle Maschine ausführen kann, um Terminator auszuführen, als Beispiel für die Lade-, Verknüpfungs- und Initialisierungsprozesse, die in späteren Abschnitten näher beschrieben werden.

Der erste Versuch ... stellt fest, dass die Klasse Terminator nicht geladen ist ...

Nachdem Terminator geladen wurde, muss es initialisiert werden, bevor main aufgerufen werden kann, und ein Typ (Klasse oder Schnittstelle) muss immer verknüpft sein, bevor es initialisiert wird. Das Verknüpfen (§2.17.3) beinhaltet die Überprüfung, Vorbereitung und (optional) Auflösung ...

Die Überprüfung (§2.17.3) überprüft, ob die geladene Darstellung von Terminator gut geformt ist ...

Bei der Auflösung (§2.17.3) werden symbolische Referenzen aus der Klasse Terminator... überprüft.


Symbolische Referenzen von Terminator oh yeah.

38
gnat

Das fühlt sich für mich nur vage missbräuchlich an. Ein Konstruktor wird für die 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 das vom Konstruktor erstellte Objekt niemals in externem Code verwenden, verstoßen Sie gegen die Prinzipien von OOP. Grundsätzlich etwas wirklich Seltsames ohne ersichtlichen Grund zu tun.

Warum willst du das überhaupt tun?

16
Mason Wheeler

Für Java Ich würde denken, die Argumentation ist einfach: Bei der Entwicklung von Java wussten die Entwickler, dass die meisten Leute, die die Sprache lernen, C/C++ vorher kennen würden.

Daher Java sieht nicht nur C/C++ sehr ähnlich, anstatt Smalltalk zu sagen, sondern hat auch Idiosynchrasien von C/C++ übernommen (denken Sie nur an oktale Ganzzahlliterale). Da c/c ++ beide a verwenden Hauptmethode, dasselbe für Java zu tun, machte aus dieser Sicht Sinn.

Ich bin mir ziemlich sicher, dass ich mich an Bloch oder jemanden erinnere, der etwas in diese Richtung gesagt hat, warum er oktale Ganzzahlliterale hinzugefügt hat. Ich werde sehen, ob ich einige Quellen finden kann :)

9
Voo

Nun, es gibt viele Hauptfunktionen, die nur eine Endlosschleife ausführen. Ein Konstruktor, der auf diese Weise arbeitet (mit einem Objekt, das niemals konstruiert wird), scheint mir seltsam.

Es gibt so viele lustige Dinge an diesem Konzept. Ihre Logik läuft auf einem ungeborenen Objekt, Objekten, die zum Sterben geboren wurden (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 auf sie von einem Unbekannten zugegriffen werden muss) statische (weil keine Instanz benötigt wird, damit wir anfangen können ) void main (weil es der Einstiegspunkt ist)?

Damit ein einfacher, einfacher Funktionseinstiegspunkt in Java vorhanden ist, sind automatisch öffentliche und statische Elemente erforderlich. Obwohl es sich um eine statische Methode handelt, läuft es 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, einfachen Funktionseinstiegspunkt als Einstiegspunkt verwenden möchten. Was kommt als nächstes, das als Konstrukteur, der nicht konstruieren soll, nicht seltsam erscheint?

6
pepper_chico

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 stecken, die Sie testen möchten.

3
Graham Borland

Nach meinem Verständnis ist der Hauptgrund einfach. Sun war ein Unix-Unternehmen, das Unix-Maschinen verkaufte, und für Unix wurde das C "main (args)" Konvention zum Aufrufen einer Binärdatei entwickelt.

Zusätzlich Java wurde explizit so konzipiert, dass es für C- und C++ - Programmierer einfach zu erlernen ist, sodass es keinen guten Grund gab, nicht einfach die C-Konvention zu erlernen.

Der gewählte Ansatz, bei dem jede Klasse eine Aufrufmethode haben kann, ist sehr flexibel, insbesondere in Kombination mit dem Main-Classline in der Datei MANIFEST.MF in einem ausführbaren JAR.

0
user1249

Du musst irgendwo anfangen. Eine statische Hauptleitung 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 sie mit minimalem Aufwand (und geringer Wahrscheinlichkeit "" erstellt "werden kann eines Codierungsfehlers, der den Start verhindert usw.) und kann einfache Dinge ohne viel anderes Setup tun.

Grundsätzlich eine Anwendung von KISS.

[Und natürlich ist der Hauptgrund: Warum nicht?]

0
Daniel R Hicks