Warum ist die Java-Hauptmethode statisch?


505

Die Methodensignatur einer Java main () -Methode lautet:

public static void main(String[] args){
    ...
}

Gibt es einen Grund dafür, dass diese Methode statisch ist?


1
In diesem Fall sollten wir die Methodensignatur nicht sagen , da sich der Begriff nur auf Methodennamen und deren Parameter bezieht
Andrew Tobilko

Java wurde bewusst so konzipiert, dass es einem C-Programmierer bekannt vorkommt. Dies kommt der C-Konvention sehr nahe.
Thorbjørn Ravn Andersen

Antworten:


337

Die Methode ist statisch, da sonst Unklarheiten bestehen würden: Welcher Konstruktor sollte aufgerufen werden? Besonders wenn deine Klasse so aussieht:

public class JavaClass{
  protected JavaClass(int x){}
  public void main(String[] args){
  }
}

Sollte die JVM anrufen new JavaClass(int)? Was soll es passieren x?

Wenn nicht, sollte die JVM instanziiert werden, JavaClassohne eine Konstruktormethode auszuführen? Ich denke, das sollte nicht der Fall sein, da dies Ihre gesamte Klasse in einem Sonderfall behandelt. Manchmal haben Sie eine Instanz, die nicht initialisiert wurde, und Sie müssen bei jeder Methode, die aufgerufen werden kann, danach suchen.

Es gibt einfach zu viele Randfälle und Mehrdeutigkeiten, als dass es für die JVM sinnvoll wäre, eine Klasse instanziieren zu müssen, bevor der Einstiegspunkt aufgerufen wird. Deshalb mainist statisch.

Ich habe keine Ahnung warum mainimmer markiert ist public.


4
Das Implementieren einer Schnittstelle löst das Instanziierungsproblem nicht.
Jacob Krall

26
Ich persönlich mag es, dass dies public static void mainals Markierung für einen Einstiegspunkt dient - ein öffentlicher parameterloser Konstruktor schreit nicht "Dies ist wahrscheinlich ein Einstiegspunkt!" auf die gleiche Weise.
Jacob Krall

5
@EdwinDalorzo - Was würde man gewinnen, wenn die Einstiegspunktklasse instanziiert würde? Das Aufrufen einer statischen Methode belastet die Klasse am wenigsten. Es ist kostenlos, sich selbst zu instanziieren, wenn dies für Ihr Design sinnvoller ist.
David Harkness

18
"Welcher Konstruktor soll aufgerufen werden?" Wie ist das überhaupt denkbar ein Problem? Das gleiche "Problem" besteht für die Entscheidung, welche mainangerufen werden soll. Seltsamerweise (für Sie) schafft die JVM das ganz gut.
Konrad Rudolph

9
Die Hauptmethode ist immer öffentlich, da die Laufzeit-Engine, die JVM, auf sie zugreifen muss.
gthm

398

Dies ist nur eine Konvention. Tatsächlich sind sogar der Name main () und die übergebenen Argumente reine Konventionen.

Wenn Sie java.exe (oder javaw.exe unter Windows) ausführen, passieren tatsächlich einige Java Native Interface (JNI) -Aufrufe. Diese Aufrufe laden die DLL, die wirklich die JVM ist (das ist richtig - java.exe ist NICHT die JVM). JNI ist das Tool, das wir verwenden, wenn wir die Welt der virtuellen Maschinen und die Welt von C, C ++ usw. überbrücken müssen. Das Gegenteil ist auch der Fall - es ist (zumindest meines Wissens) nicht möglich, tatsächlich eine zu erhalten JVM läuft ohne JNI.

Grundsätzlich ist java.exe eine supereinfache C-Anwendung, die die Befehlszeile analysiert, ein neues String-Array in der JVM erstellt, um diese Argumente zu speichern, den Klassennamen analysiert, den Sie als main () angegeben haben, und JNI-Aufrufe verwendet, um die zu finden Die main () -Methode selbst ruft dann die main () -Methode auf und übergibt das neu erstellte String-Array als Parameter. Dies ist sehr, sehr ähnlich zu dem, was Sie tun, wenn Sie die Reflexion von Java verwenden - es werden stattdessen nur verwirrend benannte native Funktionsaufrufe verwendet.

Es wäre völlig legal für Sie, eine eigene Version von java.exe zu schreiben (die Quelle wird mit dem JDK verteilt) und etwas ganz anderes tun zu lassen. Genau das machen wir mit all unseren Java-basierten Apps.

Jede unserer Java-Apps verfügt über einen eigenen Launcher. Wir tun dies in erster Linie, um unser eigenes Symbol und unseren eigenen Prozessnamen zu erhalten. In anderen Situationen, in denen wir neben dem regulären main () -Aufruf etwas tun möchten, um die Dinge in Gang zu bringen, hat sich dies jedoch als nützlich erwiesen (in einem Fall tun wir dies beispielsweise COM-Interoperabilität, und wir übergeben tatsächlich ein COM-Handle an main () anstelle eines String-Arrays).

Also, lang und kurz: Der Grund, warum es statisch ist, ist b / c, was praktisch ist. Der Grund ist es ‚main‘ genannt wird, ist , dass es etwas sein musste, und main () ist das, was sie in den alten Tagen von C hat (und in diesen Tagen, der Name der Funktion war wichtig). Ich nehme an, dass Sie mit java.exe möglicherweise nur einen vollständig qualifizierten Hauptmethodennamen anstelle der Klasse (java com.mycompany.Foo.someSpecialMain) angeben konnten. Dies erschwert es IDEs jedoch nur, die 'automatisch zu erkennen. startbare Klassen in einem Projekt.


66
+1: Sehr faszinierend (besonders der Teil über das Schreiben eines Brauchs java.exe)
Adam Paynter

9
Interessanterweise bin ich mit der "Dies ist nur Konvention" nicht einverstanden. Ein Teil der Antwort. Die Hauptfrage des OP war der Grund für die statische Aufladung in der Erklärung. Ich denke nicht, dass staticdie main()Erklärung nur der Konvention dient. Die Tatsache, dass es "main ()" und nicht etwas anderes ist, ist jedoch machbar.
Jared

2
@ David So war es auch. Eigentlich hätte ich eine Antwort von einer der ursprünglich beteiligten Personen vorgezogen - aber das war ein sehr weiter Schuss. Die meisten anderen Antworten sind leider eine Übung im Ad-hoc-Denken. Dieser gibt ziemlich interessante Details, abgesehen von der Demut, keine falschen technischen Details zu erfinden, um eine (wahrscheinlich) nicht-technische Ursache zu begründen.
Konrad Rudolph

2
@Jared - Sie hätten einen öffentlichen No-Arg-Konstruktor benötigen und mainnicht statisch machen können und trotzdem in die Grenzen der Sprache passen. Ohne von den Designern zu hören, müssen wir nur zustimmen, nicht zuzustimmen. :)
David Harkness

4
@BenVoigt Sie rufen LoadLibrary () auf, um die jvm-DLL abzurufen. Dann rufen Sie getprocaddress ("JNI_CreateJavaVM") auf und rufen dann die Funktion JNI_CreateJavaVM auf ( docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/… ). Sobald die VM geladen ist, verwenden Sie Standard-JNI-Aufrufe, um die richtige Klasse zu finden, laden Sie die statische Hauptmethode und rufen Sie sie auf. Es gibt dort nicht viel Raum für Fehlinterpretationen. Mit JNI laden Sie die VM auf jeden Fall. Sie sind möglicherweise daran gewöhnt, nur clientseitige JNI mit dem nativen Schlüsselwort javah -jni usw. zu schreiben, aber das ist nur die Hälfte von JNI.
Kevin Day

188

Das main() Verfahren in C++, C#und Javaist statisch
Weil sie können dann von den Runtime - Engine aufgerufen werden , ohne dem Code in dem Körper alle Objekte dann instanziiert mit der main()der Arbeit tun.


1
In Ordnung, aber konnte die Laufzeit nicht ein Objekt der Klasse instanziieren? Und dann die Main-Methode aufrufen? Warum?
Andrei Rînea

12
Wie würde die JVM wissen, welchen Konstruktor sie aufrufen soll, wenn Ihre Hauptklasse Konstruktoren überladen hätte? Welche Parameter würde es passieren?
Jacob Krall

1
@Noah Wenn Sie Elternklasse sagen, meinen Sie damit die Klasse, die die Hauptmethode enthält? Denn wenn ja, ist der Begriff "Elternklasse" hier ziemlich verwirrend, und sonst würde er für mich keinen Sinn ergeben. Wenn wir eine Konvention verwenden public static void main..., warum könnte die Konvention dann nicht sein, dass die Anwendungseinstiegspunktklasse einen öffentlichen Standardkonstruktor haben sollte?
Edwin Dalorzo

2
@ Jacob Wie würde die JVM wissen, welche überlastet static void mainanzurufen ist? Überhaupt kein Problem.
Konrad Rudolph

4
@Namratha: Ja, dir fehlt etwas. Es ist einfach nicht wahr, dass "statische Methode nicht auf nicht statische Methode verweisen kann". Die richtige Aussage lautet: "Jede statische Methode muss ein Objekt bereitstellen, wenn eine nicht statische Methode verwendet wird." Und schauen Sie, staticMethoden, wie sie mainhäufig verwendet werden new, um ein solches Objekt zu erstellen.
Ben Voigt

38

Warum public static void main (String [] args)?

So wird Java Language entworfen und Java Virtual Machine wird entworfen und geschrieben.

Oracle Java-Sprachspezifikation

Lesen Sie Kapitel 12 Ausführung - Abschnitt 12.1.4. Rufen Sie Test.main auf :

Schließlich wird nach Abschluss der Initialisierung für den Klassentest (während der möglicherweise andere nachfolgende Ladevorgänge, Verknüpfungen und Initialisierungen aufgetreten sind) die Methode main of Test aufgerufen.

Die Methode main muss als öffentlich, statisch und nichtig deklariert werden. Es muss ein einzelnes Argument akzeptieren, das ein Array von Zeichenfolgen ist. Diese Methode kann entweder deklariert werden

public static void main(String[] args)

oder

public static void main(String... args)

Oracle Java Virtual Machine-Spezifikation

Lesen Sie Kapitel 2 Konzepte der Java-Programmiersprache - Abschnitt 2.17 Ausführung :

Die virtuelle Java-Maschine startet die Ausführung, indem sie die Methode main einer bestimmten Klasse aufruft und ihr ein einzelnes Argument übergibt, bei dem es sich um ein Array von Zeichenfolgen handelt. Dadurch wird die angegebene Klasse geladen (§2.17.2), mit anderen verwendeten Typen verknüpft (§2.17.3) und initialisiert (§2.17.4). Die Methode main muss als öffentlich, statisch und nichtig deklariert werden.

Oracle OpenJDK-Quelle

Laden Sie das Quell-JAR herunter, extrahieren Sie es und sehen Sie, wie JVM geschrieben ist. Schauen Sie sich das an ../launcher/java.c, das nativen C-Code hinter dem Befehl enthält java [-options] class [args...]:

/*
 * Get the application's main class.
 * ... ...
 */
if (jarfile != 0) {
    mainClassName = GetMainClassName(env, jarfile);

... ...

    mainClass = LoadClass(env, classname);
    if(mainClass == NULL) { /* exception occured */

... ...

/* Get the application's main method */
mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
                                   "([Ljava/lang/String;)V");

... ...

{    /* Make sure the main method is public */
    jint mods;
    jmethodID mid;
    jobject obj = (*env)->ToReflectedMethod(env, mainClass,
                                            mainID, JNI_TRUE);

... ...

/* Build argument array */
mainArgs = NewPlatformStringArray(env, argv, argc);
if (mainArgs == NULL) {
    ReportExceptionDescription(env);
    goto leave;
}

/* Invoke main method. */
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

... ...

4
Das Problem hierbei ist, dass dies tatsächlich eine sehr gute Antwort auf die Frage in ihrer ursprünglichen Form mit vielen Referenzen (+1) ist. Ich würde jedoch gerne etwas über die Gründe für die Entwurfsentscheidung erfahren , eine statische Methode als Einstiegspunkt und nicht als Konstruktor- oder Instanzmethode festzulegen.
Konrad Rudolph

1
@KonradRudolph, bei Fragen zum Sprach- und JVM-Spezifikationsdesign können Sie sich an die Originalquelle von Oracle wenden und prüfen, ob Sie positives Feedback erhalten.
Yorkw

2
Wenn eine Methodenergebnisberechnung nur von ihren Parametern abhängt, sodass sie nicht vom internen Status der Objektinstanz abhängt, kann sie im Allgemeinen statisch sein. Es wird empfohlen, es für die Wartbarkeit / Wiederverwendbarkeit von Code als statisch festzulegen. Wenn die Methode mainnicht statisch war, bedeutet dies, dass der Status der Klasseninstanz bekannt sein muss und die Definition viel komplexer ist, z. B. welcher Konstruktor zuerst verwendet werden soll.
Yves Martin

@KonradRudolph Interessanterweise benötigte Oak (der Vorgänger von Java) bereits die Hauptmethode, um einen ähnlichen Prototyp zu haben: public static void main(String arguments[])- Referenz: Oak 0.2 Spec .
Assylias

2
@ Yves Es kann sein. Es muss nicht, wenn ein anderes Design Sinn macht. Ich habe in den Kommentaren hier einige gute Argumente gehört, aber ich denke immer noch, dass ein Prozess einem Thread sehr ähnlich ist (es ist ), und ein Thread in Java wird normalerweise als Instanz von dargestellt Runnable. Runnable.RunIn Java ist es auf jeden Fall sinnvoll, den gesamten Prozess auf die gleiche Weise darzustellen (dh als Einstiegspunkt zu haben). Natürlich ist es Runnableselbst wohl ein Designfehler, der dadurch verursacht wird, dass Java (noch) keine anonymen Methoden hat. Aber da es schon da ist ...
Konrad Rudolph

36

staticStellen wir uns einfach vor, dies wäre nicht als Einstiegspunkt für die Anwendung erforderlich.

Eine Anwendungsklasse würde dann folgendermaßen aussehen:

class MyApplication {
    public MyApplication(){
        // Some init code here
    }
    public void main(String[] args){
        // real application code here
    }
}

Die Unterscheidung zwischen Konstruktorcode und mainMethode ist notwendig, da ein Konstruktor in OO speak nur sicherstellen muss, dass eine Instanz ordnungsgemäß initialisiert wird. Nach der Initialisierung kann die Instanz für den beabsichtigten "Dienst" verwendet werden. Das Einfügen des vollständigen Anwendungscodes in den Konstruktor würde dies beeinträchtigen.

Dieser Ansatz würde dem Antrag also drei verschiedene Verträge aufzwingen:

  • Es muss einen Standardkonstruktor geben. Andernfalls würde die JVM nicht wissen, welcher Konstruktor aufgerufen werden soll und welche Parameter bereitgestellt werden sollen.
  • Es muss eine mainMethode 1 geben . Ok, das ist nicht überraschend.
  • Die Klasse darf nicht sein abstract. Andernfalls konnte die JVM dies nicht instanziieren.

Der staticAnsatz erfordert dagegen nur einen Vertrag:

  • Es muss eine mainMethode 1 geben .

Hier sind weder abstractnoch mehrere Konstruktoren von Bedeutung.

Da Java als einfache Sprache für den Benutzer konzipiert wurde , ist es nicht verwunderlich, dass auch der Anwendungseinstiegspunkt auf einfache Weise unter Verwendung eines Vertrags und nicht auf komplexe Weise unter Verwendung von drei unabhängigen und spröden Verträgen entworfen wurde.

Bitte beachten Sie: Bei diesem Argument geht es nicht um Einfachheit innerhalb der JVM oder innerhalb der JRE. Bei diesem Argument geht es um Einfachheit für den Benutzer .


1 Hier gilt die vollständige Unterschrift als nur ein Vertrag.


1
Tatsächlich sind die Anforderungen komplexer: es muss ein sein mainVerfahren , das ist public, staticund hat die Unterschrift void main(String[]). Ich bin damit einverstanden, dass die JRE, wenn die Methode eine Instanzmethode wäre, etwas mehr Arbeit hätte, aber die Art der Arbeit dieselbe wäre und die Komplexität nicht wesentlich höher wäre (siehe Diskussionen in den Kommentaren der vorherigen Antwort). Ich glaube nicht, dass dieser Unterschied für die Entscheidung verantwortlich ist, den Einstiegspunkt statisch zu machen, insbesondere da die erforderlichen Methoden zur Auflösung einer Instanzmethode existieren und leicht verwendbar sind.
Konrad Rudolph

3
@KonradRudolph: Mein Punkt ist nicht die Arbeit, die die JRE leisten müsste. Es geht mir darum, jeden Benutzer der Sprache zu zwingen, bei Bedarf weitere Verträge einzuhalten. In diesem Sinne ist eine static public main(String[])Methode eine Unterschrift und damit ein Vertrag. Andernfalls müssen drei unabhängige Verträge eingehalten werden.
AH

1
Ah. Ich bin immer noch nicht der Meinung, dass dies einen Unterschied macht. Einstiegspunktklassen könnten gut implementiert werden Runnable. Java erwartet natürlich, dass Entwickler diesen Vertrag ständig einhalten. Warum sollte er für den Einstiegspunkt der Anwendung zu viel sein? Das macht keinen Sinn.
Konrad Rudolph

3
@KonradRudolph: Es gibt keinen Widerspruch: In einem Fall würde das System dem Benutzer drei Verträge aufzwingen. Zweifelhafte Verträge, die über den Compiler nicht überprüfbar sind und die aus Anwendersicht unabhängig sind. Im Normalfall Threadund Runnablewenn dem Benutzer nichts verborgen ist, kann er klar sehen, was los ist, und er hat die Änderung, nur die Verträge umzusetzen, die zu ihm passen - er hat die Kontrolle, nicht das System.
AH

2
Dies ist die beste Antwort hier. Es ist eine Schande, dass viele Benutzer nur die Top 2 oder 3 Antworten auf der Seite lesen. und es ist unwahrscheinlich, dass dieser bald dort ankommt. Es wird erwähnt, dass der wichtige Punkt eines Konstruktors NUR für die Initialisierung ist - und daher macht es keinen Sinn, in einem Stil zu codieren, in dem der Konstruktor die gesamte Anwendung ausführt.
Dawood ibn Kareem

14

Wenn nicht, welcher Konstruktor sollte verwendet werden, wenn es mehr als einen gibt?

Weitere Informationen zur Initialisierung und Ausführung von Java-Programmen finden Sie in der Java-Sprachspezifikation .


12

Bevor die Hauptmethode aufgerufen wird, werden keine Objekte instanziiert. Mit dem statischen Schlüsselwort kann die Methode aufgerufen werden, ohne zuvor Objekte zu erstellen.


Falsch. Oder zumindest sehr ungenau. öffentliche Klasse Main {statisches Objekt object = new Object () {{System.out.println ("Objekt erstellt"); }}; public static void main (String [] args) {System.out.println ("in main"); }}
Eljenso

Fairer Kommentar. Technisch hätte ich sagen sollen, dass vor dem Aufruf der Main-Methode die Klasse, die die main-Methode enthält, nicht instanziiert wird.
BlackWasp

12

Andernfalls muss eine Instanz des Objekts ausgeführt werden. Es muss jedoch von Grund auf aufgerufen werden, ohne das Objekt zuerst zu erstellen, da es normalerweise Aufgabe der main () - Funktion (Bootstrap) ist, die Argumente zu analysieren und das Objekt zu erstellen, normalerweise unter Verwendung dieser Argumente / Programmparameter.


10

Lassen Sie mich diese Dinge viel einfacher erklären:

public static void main(String args[])

Alle Java-Anwendungen mit Ausnahme von Applets starten ihre Ausführung ab main().

Das Schlüsselwort publicist ein Zugriffsmodifikator, mit dem das Mitglied von außerhalb der Klasse aufgerufen werden kann.

staticwird verwendet, weil es ermöglicht main(), aufgerufen zu werden, ohne eine bestimmte Instanz dieser Klasse instanziieren zu müssen.

voidgibt an, dass main()kein Wert zurückgegeben wird.


9

Was bedeutet das public static void main(String args[])?

  1. public ist ein Zugriffsspezifizierer, der bedeutet, dass jeder darauf zugreifen / ihn aufrufen kann, z. B. JVM (Java Virtual Machine).
  2. staticErmöglicht main()den Aufruf, bevor ein Objekt der Klasse erstellt wurde. Dies ist erforderlich, da main()es von der JVM aufgerufen wird, bevor Objekte erstellt werden. Da es statisch ist, kann es direkt über die Klasse aufgerufen werden.

    class demo {    
        private int length;
        private static int breadth;
        void output(){
            length=5;
            System.out.println(length);
        }
    
        static void staticOutput(){
            breadth=10; 
            System.out.println(breadth);
        }
    
        public static  void main(String args[]){
            demo d1=new demo();
            d1.output(); // Note here output() function is not static so here
            // we need to create object
            staticOutput(); // Note here staticOutput() function is  static so here
            // we needn't to create object Similar is the case with main
            /* Although:
            demo.staticOutput();  Works fine
            d1.staticOutput();  Works fine */
        }
    }

    In ähnlicher Weise verwenden wir manchmal statisch für benutzerdefinierte Methoden, damit wir keine Objekte erstellen müssen.

  3. voidgibt an, dass die main()deklarierte Methode keinen Wert zurückgibt.

  4. String[] argsGibt den einzigen Parameter in der main()Methode an.

    args- Ein Parameter, der ein Array von Objekten vom Klassentyp enthält String.


6

Applets, Midlets, Servlets und Beans verschiedener Art werden konstruiert und dann mit Lebenszyklusmethoden aufgerufen. Das Aufrufen von main ist alles, was jemals an der Hauptklasse ausgeführt wird. Es ist also nicht erforderlich, dass ein Status in einem Objekt gespeichert wird, das mehrmals aufgerufen wird. Es ist ganz normal, main einer anderen Klasse zuzuordnen (obwohl dies keine gute Idee ist), was die Verwendung der Klasse zum Erstellen des Hauptobjekts behindern würde.


5

Es ist nur eine Konvention, aber wahrscheinlich bequemer als die Alternative. Bei einer statischen Hauptleitung müssen Sie lediglich den Namen und den Speicherort einer Klasse kennen, um ein Java-Programm aufzurufen. Wenn es nicht statisch wäre, müssten Sie auch wissen, wie diese Klasse instanziiert wird, oder Sie müssen verlangen, dass die Klasse einen leeren Konstruktor hat.


Es ist keine Konvention; es ist Teil der Sprachspezifikation; Die Laufzeit erkennt eine Klasse ohne statische Hauptmethode nicht als gültigen Einstiegspunkt.
Rob

2
Die Sprachspezifikation selbst folgt der Konvention. Es gibt keine tatsächliche Anforderung, dass sich die Java-Designer für die Anforderung einer statischen Hauptleitung entschieden haben. Wie Logan erklärt, sind die Alternativen jedoch komplizierter.
David Arno

@DavidArno Es wäre sinnvoller zu sagen, dass die Konvention der Sprachspezifikation folgt.
Marquis von Lorne

5

Wenn die Hauptmethode nicht statisch wäre, müssten Sie ein Objekt Ihrer Hauptklasse von außerhalb des Programms erstellen. Wie möchten Sie das machen?


5

Wenn Sie die Java Virtual Machine (JVM) mit dem javaBefehl ausführen ,

java ClassName argument1 argument2 ...

Wenn Sie Ihre Anwendung ausführen, geben Sie den Klassennamen wie oben beschrieben als Argument für den Java-Befehl an

Die JVM versucht, die Hauptmethode der von Ihnen angegebenen Klasse aufzurufen

- Zu diesem Zeitpunkt wurden keine Objekte der Klasse erstellt.

mainAls statisch deklarierenallows die JVM invokeHaupt withouteines Erstellen instanceder Klasse.

Kehren wir zum Befehl zurück

ClassName ist ein command-line argument JVM, die angibt, welche Klasse ausgeführt werden soll. Nach dem Klassennamen können Sie auch ein list of Strings(durch Leerzeichen getrenntes) als Befehlszeilenargument angeben , das die JVM an Ihre Anwendung weitergibt . - Solche Argumente können verwendet werden, um Optionen (z. B. einen Dateinamen) zum Ausführen der Anwendung anzugeben. Aus diesem Grund wird String[] argsim Hauptfenster ein Parameter aufgerufen

Referenzen: Java ™ Programmieranleitung (frühe Objekte), 10. Ausgabe


4

Kürzlich wurde eine ähnliche Frage bei Programmers.SE veröffentlicht

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

    Auf der Suche nach einer endgültigen Antwort von einer primären oder sekundären Quelle, warum (insbesondere) Java und C # beschlossen haben, eine statische Methode als Einstiegspunkt zu verwenden, anstatt eine Anwendungsinstanz durch eine Instanz einer ApplicationKlasse darzustellen , wobei der Einstiegspunkt eine ist geeigneter Konstruktor?

TL; DR Teil der akzeptierten Antwort ist:

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

  1. Gänschen wollte
  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 unter NeWS auszuführen

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

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

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

...


3

Ich denke, das Schlüsselwort 'static' macht die Hauptmethode zu einer Klassenmethode, und Klassenmethoden haben nur eine Kopie davon und können von allen gemeinsam genutzt werden. Außerdem ist kein Objekt als Referenz erforderlich. Wenn die Treiberklasse kompiliert wird, kann die Hauptmethode aufgerufen werden. (Ich bin nur in der Alphabet-Ebene von Java, sorry, wenn ich falsch liege)


Alle Methoden haben nur eine Kopie davon.
Marquis von Lorne

3

main () ist statisch, weil; Zu diesem Zeitpunkt im Lebenszyklus der Anwendung ist der Anwendungsstapel prozeduraler Natur, da noch keine Objekte instanziiert wurden.

Es ist eine saubere Tafel. Ihre Anwendung wird zu diesem Zeitpunkt ausgeführt, auch ohne dass Objekte deklariert wurden (denken Sie daran, dass es prozedurale UND OO-Codierungsmuster gibt). Als Entwickler verwandeln Sie die Anwendung in eine objektorientierte Lösung, indem Sie Instanzen Ihrer Objekte erstellen und von dem darin kompilierten Code abhängen.

Objektorientiert ist aus Millionen von offensichtlichen Gründen großartig. Vorbei sind jedoch die Zeiten, in denen die meisten VB-Entwickler regelmäßig Schlüsselwörter wie "goto" in ihrem Code verwendeten. "goto" ist ein prozeduraler Befehl in VB, der durch sein OO-Gegenstück ersetzt wird: Methodenaufruf.

Sie können den statischen Einstiegspunkt (main) auch als reine Freiheit betrachten. Wäre Java anders genug gewesen, um ein Objekt zu instanziieren und Ihnen beim Ausführen nur diese Instanz zu präsentieren, hätten Sie keine andere Wahl, ABER eine prozedurale App zu schreiben. So unvorstellbar es für Java auch klingen mag, es gibt viele Szenarien, die prozedurale Ansätze erfordern.

Dies ist wahrscheinlich eine sehr dunkle Antwort. Denken Sie daran, dass "Klasse" nur eine Sammlung von miteinander verbundenem Code ist. "Instanz" ist eine isolierte, lebende und atmende autonome Generation dieser Klasse.


7
Das ist falsch. Viele Objekte werden instanziiert, bevor sie mainerreicht werden. Und wenn Sie einen statischen Konstruktor in die Klasse aufnehmen, die main enthält, wird dieser mainebenfalls zuvor ausgeführt .
Konrad Rudolph

2

Es ist nur eine Konvention. Die JVM könnte sich sicherlich mit nicht statischen Hauptmethoden befassen, wenn dies die Konvention gewesen wäre. Schließlich können Sie einen statischen Initialisierer für Ihre Klasse definieren und zig Objekte instanziieren, bevor Sie jemals zu Ihrer main () -Methode gelangen.


2

Der Prototyp public static void main(String[])ist eine im JLS definierte Konvention :

Die Methode main muss als öffentlich, statisch und nichtig deklariert werden. Es muss einen formalen Parameter (§8.4.1) angeben, dessen deklarierter Typ ein Array von String ist.

In der JVM-Spezifikation 5.2. Start der virtuellen Maschine können wir lesen:

Die Java Virtual Machine startet mit dem Erstellen einer anfänglichen Klasse, die implementierungsabhängig angegeben wird, mithilfe des Bootstrap-Klassenladeprogramms (§5.3.1). Die virtuelle Java-Maschine verknüpft dann die ursprüngliche Klasse, initialisiert sie und ruft die öffentliche Klassenmethode void main (String []) auf . Der Aufruf dieser Methode steuert die weitere Ausführung. Die Ausführung der Java Virtual Machine-Anweisungen, die die Hauptmethode bilden, kann das Verknüpfen (und folglich das Erstellen) zusätzlicher Klassen und Schnittstellen sowie den Aufruf zusätzlicher Methoden verursachen.

Lustige Sache, in der JVM-Spezifikation wird nicht erwähnt, dass die Hauptmethode statisch sein muss. Die Spezifikation besagt jedoch auch, dass die Java Virtual Machine zuvor zwei Schritte ausgeführt hat:

Die Initialisierung einer Klasse oder Schnittstelle besteht aus der Ausführung ihrer Klassen- oder Schnittstelleninitialisierungsmethode.

In 2.9. Spezielle Methoden :

Eine Klassen- oder Schnittstelleninitialisierungsmethode ist definiert:

Eine Klasse oder Schnittstelle hat höchstens eine Klassen- oder Schnittstelleninitialisierungsmethode und wird durch Aufrufen dieser Methode initialisiert (§5.5). Die Initialisierungsmethode einer Klasse oder Schnittstelle hat den speziellen Namen <clinit>, akzeptiert keine Argumente und ist ungültig.

Eine Klassen- oder Schnittstelleninitialisierungsmethode unterscheidet sich von einer Instanzinitialisierungsmethode, die wie folgt definiert ist:

Auf der Ebene der virtuellen Java-Maschine wird jeder in der Java-Programmiersprache (JLS §8.8) geschriebene Konstruktor als Instanzinitialisierungsmethode mit dem speziellen Namen angezeigt <init>.

Die JVM initialisiert also eine Klassen- oder Schnittstelleninitialisierungsmethode und keine Instanzinitialisierungsmethode, die tatsächlich ein Konstruktor ist. Sie müssen also nicht erwähnen, dass die Hauptmethode in der JVM-Spezifikation statisch sein muss, da dies durch die Tatsache impliziert wird, dass vor dem Aufruf der Hauptmethode keine Instanz erstellt wird.


2

Das publicSchlüsselwort ist ein Zugriffsmodifikator, mit dem der Programmierer die Sichtbarkeit von Klassenmitgliedern steuern kann. Wenn einem Klassenmitglied vorangestellt wirdpublic , kann auf dieses Mitglied durch Code außerhalb der Klasse zugegriffen werden, in der es deklariert ist.

Das Gegenteil von publicistprivate verhindert, dass ein Mitglied von Code verwendet wird, der außerhalb seiner Klasse definiert ist.

In diesem Fall main()muss als deklariert werdenpublic , da es beim Starten des Programms durch Code außerhalb seiner Klasse aufgerufen werden muss.

Mit dem Schlüsselwort statickann main()aufgerufen werden, ohne dass eine bestimmte Instanz der Klasse instanziiert werden muss. Dies ist da notwendigmain() es vom Java-Interpreter aufgerufen wird, bevor Objekte erstellt werden.

Das Schlüsselwort voidteilt dem Compiler einfach mit, dass main()kein Wert zurückgegeben wird.


1

Der wahre Einstiegspunkt für jede Anwendung ist eine statische Methode. Wenn die Java-Sprache eine Instanzmethode als "Einstiegspunkt" unterstützt, müsste die Laufzeit diese intern als statische Methode implementieren, die eine Instanz des Objekts erstellt und anschließend die Instanzmethode aufruft.

Nachdem dies nicht möglich ist, werde ich die Gründe für die Auswahl einer bestimmten der folgenden drei Optionen untersuchen:

  1. A static void main()wie wir es heute sehen.
  2. Eine Instanzmethode, void main()die für ein frisch erstelltes Objekt aufgerufen wird.
  3. Verwenden des Konstruktors eines Typs als Einstiegspunkt (z. B. wenn die Eingabeklasse aufgerufen wurde Program, würde die Ausführung effektiv aus bestehen new Program()).

Nervenzusammenbruch:

static void main()

  1. Ruft den statischen Konstruktor der einschließenden Klasse auf.
  2. Ruft die statische Methode auf main().

void main()

  1. Ruft den statischen Konstruktor der einschließenden Klasse auf.
  2. Erstellt eine Instanz der einschließenden Klasse durch effektiven Aufruf new ClassName() .
  3. Ruft die Instanzmethode auf main().

new ClassName()

  1. Ruft den statischen Konstruktor der einschließenden Klasse auf.
  2. Konstruiert eine Instanz der Klasse (macht dann nichts damit und kehrt einfach zurück).

Begründung:

Ich werde in umgekehrter Reihenfolge für diesen gehen.

Beachten Sie, dass eines der Entwurfsziele von Java darin bestand, gute objektorientierte Programmierpraktiken hervorzuheben (wenn möglich zu erfordern). In diesem Zusammenhang initialisiert der Konstruktor eines Objekts das Objekt, sollte jedoch nicht für das Verhalten des Objekts verantwortlich sein. Daher eine Spezifikation, die einen Einstiegspunkt vonnew ClassName() angibt, die Situation für neue Java-Entwickler verwirren, indem für jede Anwendung eine Ausnahme vom Entwurf eines "idealen" Konstruktors erzwungen wird.

Durch das Erstellen main()einer Instanzmethode wird das obige Problem sicherlich gelöst. Dies führt jedoch zu Komplexität, da die Spezifikation die Signatur des Konstruktors der Eintragsklasse sowie die Signatur der main()Methode auflisten muss.

Zusammenfassend lässt sich sagen, dass durch die Angabe von a static void main()eine Spezifikation mit der geringsten Komplexität erstellt wird, während das Prinzip der Platzierung von Verhalten in Methoden eingehalten wird . Wenn man bedenkt, wie einfach es ist, eine main()Methode zu implementieren , die selbst eine Instanz einer Klasse erstellt und eine Instanzmethode aufruft, hat die Angabe main()als Instanzmethode keinen wirklichen Vorteil .


1
Dies wirft nur die Frage auf. Java benötigt ohnehin einen Application Loader, der vor dem Aufruf viel Arbeit leistet main. Ihre Begründung main, für Anfänger zu komplex zu sein, scheint unglaublich. In der Tat, die statischen mainist sehr verwirrend für Anfänger, bezweifle ich , ein Konstruktor mehr so sein würde. Sie sagen, ein Konstruktor sollte nicht für das Verhalten des Objekts verantwortlich sein. Das klingt interessant, aber ich bin mir nicht sicher, ob ich dem zustimmen würde. Warum nicht? Was verhindert das?
Konrad Rudolph

1

statisch - Wenn die JVM die Hauptmethode aufruft, ist für die aufgerufene Klasse kein Objekt vorhanden. Daher muss eine statische Methode vorhanden sein, um den Aufruf von der Klasse zu ermöglichen.


1

Ich weiß nicht, ob die JVM die Hauptmethode aufruft, bevor die Objekte instanziiert werden ... Aber es gibt einen weitaus stärkeren Grund, warum die main () -Methode statisch ist ... Wenn die JVM die Hauptmethode der Klasse aufruft (z , Person). es ruft es von " Person.main () " auf. Sie sehen, die JVM ruft es unter dem Klassennamen auf. Aus diesem Grund sollte die main () -Methode statisch und öffentlich sein, damit die JVM darauf zugreifen kann.

Hoffe es hat geholfen. Wenn ja, lassen Sie es mich durch einen Kommentar wissen.


0

Statische Methoden erfordern kein Objekt. Es läuft direkt, also läuft main direkt.


0

Das statische Schlüsselwort in der Hauptmethode wird verwendet, da in der Hauptmethode keine Instanziierung stattfindet. Da das Objekt jedoch eher konstruiert als aufgerufen wird, verwenden wir in der Hauptmethode das statische Schlüsselwort. Im JVM-Kontext wird ein Speicher erstellt, wenn eine Klasse in ihn geladen wird. Und alle statischen Elemente sind in diesem Speicher vorhanden. Wenn wir die Hauptmethode jetzt statisch machen, befindet sie sich im Speicher und kann von jvm (class.main (..)) aufgerufen werden, sodass wir die Hauptmethode aufrufen können, ohne dass ein Heap erstellt werden muss.


0

Es ist nur eine Konvention, wie wir hier sehen können:

Die Methode muss als öffentlich und statisch deklariert sein , darf keinen Wert zurückgeben und muss ein String-Array als Parameter akzeptieren. Standardmäßig ist das erste Argument ohne Option der Name der Klasse, die aufgerufen werden soll. Es sollte ein vollständig qualifizierter Klassenname verwendet werden. Wenn die Option -jar angegeben ist, ist das erste Argument ohne Option der Name eines JAR-Archivs, das Klassen- und Ressourcendateien für die Anwendung enthält, wobei die Startklasse im Manifest-Header der Hauptklasse angegeben ist.

http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/java.html#description


Regel der Sprache, meinst du.
Marquis von Lorne

0

Die Schlüsselwörter public static void bedeuten, dass der Java Virtual Machine (JVM) -Interpreter die Hauptmethode des Programms aufrufen kann, um das Programm (public) zu starten, ohne eine Instanz der Klasse (static) zu erstellen, und das Programm keine Daten an den Java VM-Interpreter zurückgibt (nichtig) wenn es endet.

Quelle: Essentials, Teil 1, Lektion 2: Erstellen von Anwendungen


0

Grundsätzlich machen wir die DATENMITGLIEDER und MITGLIEDSFUNKTIONEN als STATISCH, die keine objektbezogene Aufgabe ausführen. Und im Fall der Hauptmethode machen wir es als STATIC, weil es nichts mit Objekt zu tun hat, da die Hauptmethode immer ausgeführt wird, ob wir ein Objekt erstellen oder nicht.


0

Jede in Java als statisch deklarierte Methode gehört zur Klasse selbst. Wiederum kann auf die statische Methode einer bestimmten Klasse nur unter Bezugnahme auf die Klasse like zugegriffen werdenClass_name.method_name();

Eine Klasse muss also nicht instanziiert werden, bevor auf eine statische Methode zugegriffen werden kann.

Daher wird die main () -Methode so deklariert static, dass auf sie zugegriffen werden kann, ohne ein Objekt dieser Klasse zu erstellen.

Da wir das Programm mit dem Namen der Klasse speichern, in der die Hauptmethode vorhanden ist (oder von wo aus das Programm mit der Ausführung beginnen soll, gilt dies für Klassen ohne main()Methode () (Advanced Level)). Also auf die oben erwähnte Weise:

Class_name.method_name();

Auf die Hauptmethode kann zugegriffen werden.

Kurz gesagt, wenn das Programm kompiliert wird, sucht es nach der main()Methode mit StringArgumenten wie: main(String args[])in der genannten Klasse (dh mit dem Namen des Programms), und da es zu Beginn keinen Spielraum hat, diese Klasse zu instanziieren, so ist main () Methode wird als statisch deklariert.


Es passiert, wenn das Programm ausgeführt und nicht kompiliert wird.
Marquis von Lorne

0

Von java.sun.com (es gibt weitere Informationen auf der Website):

Die Hauptmethode ist statisch, um dem Java VM-Interpreter eine Möglichkeit zu geben, die Klasse zu starten, ohne zuerst eine Instanz der Steuerungsklasse zu erstellen. Instanzen der Steuerklasse werden nach dem Start des Programms in der Hauptmethode erstellt.

Mein Verständnis war immer einfach, dass die Hauptmethode wie jede statische Methode aufgerufen werden kann, ohne eine Instanz der zugeordneten Klasse zu erstellen, sodass sie vor allen anderen Elementen im Programm ausgeführt werden kann. Wenn es nicht statisch wäre, müssten Sie ein Objekt instanziieren, bevor Sie es aufrufen. Dies führt zu einem Problem mit Hühnchen und Eiern, da die Hauptmethode im Allgemeinen die Instanziierung von Objekten zu Beginn des Programms ist.


Es wird jedoch nicht "vor allem anderen im Programm" ausgeführt. Das ganze Argument ist ein Irrtum, und außerdem ist dies nicht die erste Antwort, die es erwähnt, noch die zweite oder dritte.
Konrad Rudolph

Es tut mir leid, dass meine Antwort wiederholt, was andere gesagt haben. Ich antwortete nur nach bestem Wissen und nach dem, was ich online finden konnte. Aus den Ergebnissen, die ich mir angesehen habe, geht kein anderer Grund hervor, warum die Hauptmethode statisch ist. es sei denn, irgendwo ist einer tief verborgen, vielleicht ist das die einzige Antwort, die es gibt. Mein Verständnis von Java ist ziemlich grundlegend, aber ich habe den oben genannten Grund (von Professoren, Lehrbüchern usw.) gehört und nie einen anderen.
Jesse M

@Jesse M Dein Kommentar ist nur dann sinnvoll, wenn du nicht einmal daran gedacht hast, die anderen Antworten zuerst zu lesen. Was übrigens nicht weit hergeholt ist. Wie Sie selbst erwähnt haben, ist Ihr Verständnis ziemlich grundlegend, so dass es sehr wahrscheinlich ist, dass jemand anderes die Frage bereits kompetenter beantwortet hat. Und Ihr Kommentar scheint eine Rationalisierung zu sein, damit Ihre Antwort besser aussieht. Es ist eine außergewöhnliche Behauptung, dass Sie Java-Lehrbücher und Professoren haben, die denken, was Sie behaupten, und ehrlich gesagt glaube ich nicht, dass sie es tun. (Irgendwelche Referenzen?)
LeoR

1
@KonradRudolph Die Top-Kommentare scheinen ziemlich vernünftig. main () wird als Einstiegspunkt in das Programm verwendet, und es gibt mehrere Verweise auf der Java-Website, die besagen, dass es ähnlich sein soll, wie C / C ++ eine main () -Funktion hat. Da Java nur Objekte sind, muss es statisch sein, um eine Objektinstanziierung zu vermeiden. Wenn es statisch ist, kann es auch zur Laufzeit in die JVM geladen und ausgeführt werden. Ich spucke nur frühere Antworten aus, aber ich frage mich, was Sie als zufriedenstellende Antwort betrachten würden. Ich denke, das Beste, was Sie bekommen werden, ist "So wollten sie es". Beachten Sie das Datum, an dem Java erstellt wurde.
Trevor-E

1
@ Jesse Spot-on. Es ist durchaus möglich, dass es sich nur um eine Frage der Konvention handelt (obwohl ich hoffe, dass dies nicht der Fall ist, wäre dies eine so langweilige Antwort). Mein ursprüngliches Interesse an dieser Frage bestand darin, dass ich dachte, dass die Verwendung einer geeigneten Instanz zur Darstellung des Objekts „laufende Anwendung“ und der Einstiegspunkt als Methode (oder Konstruktor) dieser Klasse ein viel offensichtlicheres Design wäre, da Java wurde entwickelt von dem get-go orientierte Objekt zu sein, und scheinbar analoge Objekte (Fäden, über da Runnable) in Java zu tun , diesen Entwurf verwenden. Warum die (offensichtliche) Ausnahme hier?
Konrad Rudolph
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.