Perché il metodo principale Java è statico?


505

La firma del metodo di un metodo main () Java è:

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

C'è un motivo per cui questo metodo è statico?


1
in questo caso, non dovremmo dire la firma del metodo , perché il termine si riferisce solo ai nomi dei metodi e ai suoi parametri
Andrew Tobilko,

Java è progettato deliberatamente per sembrare familiare a un programmatore C. Questo è molto vicino alla convenzione C.
Thorbjørn Ravn Andersen

Risposte:


337

Il metodo è statico perché altrimenti ci sarebbe ambiguità: quale costruttore dovrebbe essere chiamato? Soprattutto se la tua classe si presenta così:

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

La JVM dovrebbe chiamare new JavaClass(int)? Per cosa dovrebbe passare x?

In caso contrario, la JVM dovrebbe creare un'istanza JavaClasssenza eseguire alcun metodo di costruzione? Penso che non dovrebbe, perché questo sarà un caso speciale per tutta la tua classe - a volte hai un'istanza che non è stata inizializzata e devi verificarla in ogni metodo che potrebbe essere chiamato.

Ci sono troppi casi limite e ambiguità perché abbia senso che la JVM debba istanziare una classe prima che venga chiamato il punto di ingresso. Ecco perché mainè statico.

Non ho idea del perché mainsia sempre segnato publicperò.


4
L'implementazione di un'interfaccia non risolve il problema di istanza.
Jacob Krall,

26
Personalmente mi piace che public static void mainserva da indicatore di un punto di ingresso - un costruttore pubblico senza parametri non urla "Questo è probabilmente un punto di ingresso!" nello stesso modo.
Jacob Krall,

5
@EdwinDalorzo - Cosa si otterrebbe forzando l'istanza della classe entry point? La chiamata a un metodo statico comporta il minor onere per la classe. È libero di creare un'istanza se questo ha più senso per il tuo design.
David Harkness,

18
"Quale costruttore dovrebbe essere chiamato?" Com'è possibile che sia un problema? Lo stesso "problema" esiste per la decisione che mainchiamare. Stranamente (per te), la JVM riesce bene.
Konrad Rudolph,

9
Il metodo principale è sempre pubblico perché deve essere accessibile dal motore di runtime, JVM.
martedì

398

Questa è solo una convenzione. In effetti, anche il nome main () e gli argomenti passati sono puramente convenzionali.

Quando si esegue java.exe (o javaw.exe su Windows), ciò che sta realmente accadendo è un paio di chiamate JNI (Java Native Interface). Queste chiamate caricano la DLL che è in realtà la JVM (giusto - java.exe NON è la JVM). JNI è lo strumento che usiamo quando dobbiamo colmare il mondo delle macchine virtuali, e il mondo di C, C ++, ecc ... Il contrario è anche vero - non è possibile (almeno per quanto ne sappia) ottenere effettivamente un JVM in esecuzione senza utilizzare JNI.

Fondamentalmente, java.exe è un'applicazione C semplicissima che analizza la riga di comando, crea un nuovo array String nella JVM per contenere tali argomenti, analizza il nome della classe specificato come contenente main (), utilizza le chiamate JNI per trovare il main () stesso metodo, quindi invoca il metodo main (), passando l'array di stringhe appena creato come parametro. Questo è molto, molto simile a quello che fai quando usi il riflesso da Java - usa invece chiamate di funzioni native con nomi confusi.

Sarebbe perfettamente legale per te scrivere la tua versione di java.exe (il sorgente è distribuito con JDK) e fare in modo che qualcosa di completamente diverso. In effetti, è esattamente quello che facciamo con tutte le nostre app basate su Java.

Ognuna delle nostre app Java ha il suo launcher. Lo facciamo principalmente in modo da ottenere la nostra icona e il nome del processo, ma è tornato utile in altre situazioni in cui vogliamo fare qualcosa oltre alla normale chiamata main () per far andare le cose (ad esempio, in un caso che stiamo facendo Interoperabilità COM e in realtà passiamo un handle COM in main () anziché in una matrice di stringhe).

Quindi, lungo e corto: il motivo per cui è statico è il b / c che è conveniente. La ragione per cui si chiama 'main' è che doveva essere qualcosa, e main () è quello che facevano ai vecchi tempi di C (e in quei giorni, il nome della funzione era importante). Suppongo che java.exe avrebbe potuto permetterti di specificare solo un nome di metodo principale completo, anziché solo la classe (java com.mycompany.Foo.someSpecialMain) - ma ciò rende più difficile agli IDE il rilevamento automatico di " classi lavabili in un progetto.


66
+1: Molto affascinante (in particolare la parte sulla scrittura di un'usanza java.exe)
Adam Paynter,

9
Interessante, non sono d'accordo con "Questa è solo una convenzione". Parte della risposta La domanda principale del PO era il motivo della staticità nella dichiarazione. Non credo che staticla main()dichiarazione sia solo per motivi di convenzione. Il fatto che sia `main () 'e non qualcos'altro è fattibile comunque.
Jared il

2
@David Così è stato. In realtà avrei preferito una risposta da una delle persone inizialmente coinvolte, ma è stata una possibilità molto lontana. La maggior parte delle altre risposte è purtroppo un esercizio di ragionamento ad hoc. Questo fornisce dettagli piuttosto interessanti, oltre ad avere l'umiltà di non inventare dettagli tecnici errati per ragionare su una causa (probabilmente) non tecnica.
Konrad Rudolph,

2
@Jared - Avrebbero potuto richiedere un costruttore no-arg pubblico e renderlo mainnon statico e comunque rientrare nei limiti del linguaggio. Senza sentire i designer, dovremo solo concordare di non essere d'accordo. :)
David Harkness,

4
@BenVoigt Chiama LoadLibrary () per ottenere la jvm dll. Quindi si chiama getprocaddress ("JNI_CreateJavaVM"), quindi si richiama la funzione JNI_CreateJavaVM ( docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/… ). Una volta caricata la VM, si utilizzano le chiamate JNI standard per trovare la classe corretta, caricare il metodo principale statico e richiamarlo. Non c'è molto spazio per interpretazioni errate lì. JNI è assolutamente il modo in cui carichi la VM. Potresti essere abituato a scrivere solo JNI lato client usando la parola chiave nativa, javah -jni, ecc ... ma questa è solo la metà di JNI.
Kevin Day

188

Il main()metodo C++, C#e Javasono statici
Poiché possono poi essere richiamati dal motore di runtime , senza dover istanziare oggetti quindi il codice nel corpo main()farà il resto.


1
Va bene ma il runtime non è in grado di creare un'istanza di un oggetto della classe? E quindi chiamare il metodo principale? Perché?
Andrei Rînea,

12
Come farebbe la JVM a sapere quale costruttore chiamare, se la tua classe principale avesse sovraccaricato i costruttori? Quali parametri passerebbe?
Jacob Krall,

1
@Noah quando dici classe genitore intendi la classe che contiene il metodo principale? Perché se è così, il termine "classe genitore" è piuttosto confuso qui, e altrimenti non avrebbe senso per me. Inoltre, se per convenzione utilizziamo public static void main..., perché la convenzione non potrebbe essere che la classe del punto di ingresso dell'applicazione dovrebbe avere un costruttore predefinito pubblico?
Edwin Dalorzo,

2
@Jacob Come potrebbe la JVM sapere quale sovraccarico static void mainchiamare? Non è affatto un problema.
Konrad Rudolph,

4
@Namratha: Sì, ti stai perdendo qualcosa. Non è vero che "il metodo statico non può fare riferimento al metodo non statico". L'istruzione corretta è: "Ogni metodo statico deve fornire un oggetto quando si utilizza un metodo non statico". E guarda, staticmetodi come mainfrequentemente usano newper creare un tale oggetto.
Ben Voigt,

38

Perché public void main main (String [] args)?

Ecco come è progettato Java Language e Java Virtual Machine è progettato e scritto.

Oracle Java Language Specification

Dai un'occhiata al capitolo 12 Esecuzione - Sezione 12.1.4 Invoke Test.main :

Alla fine, dopo il completamento dell'inizializzazione per il test di classe (durante il quale potrebbero essersi verificati altri carichi, collegamenti e inizializzazioni consequenziali), viene invocato il metodo principale di Test.

Il metodo principale deve essere dichiarato pubblico, statico e nullo. Deve accettare un singolo argomento che è una matrice di stringhe. Questo metodo può essere dichiarato come uno dei due

public static void main(String[] args)

o

public static void main(String... args)

Specifiche della macchina virtuale Oracle Oracle

Consulta il capitolo 2 Concetti relativi al linguaggio di programmazione Java - Sezione 2.17 Esecuzione :

La macchina virtuale Java avvia l'esecuzione richiamando il metodo principale di una classe specificata e passandogli un singolo argomento, che è un array di stringhe. Questo fa sì che la classe specificata venga caricata (§2.17.2), collegata (§2.17.3) ad altri tipi che utilizza e inizializzata (§2.17.4). Il metodo principale deve essere dichiarato pubblico, statico e nullo.

Oracle OpenJDK Source

Scarica ed estrai il jar di origine e guarda come viene scritta JVM, controlla ../launcher/java.c, che contiene il codice C nativo dietro il comando 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
Il problema qui è che questa è in realtà una molto buona risposta alla domanda nella sua forma originale, con abbondanza di riferimenti (+1). Tuttavia, mi piacerebbe conoscere le motivazioni alla base della decisione di progettazione di rendere un metodo statico il punto di ingresso, piuttosto che un metodo di costruzione o di istanza.
Konrad Rudolph,

1
@KonradRudolph, per domande riguardanti il ​​linguaggio e il design delle specifiche JVM, forse potresti provare a contattare la fonte originale di Oracle e vedere se riesci a ottenere un feedback positivo.
york,

2
In generale, quando il calcolo del risultato di un metodo dipende solo dai suoi parametri, quindi non dipende dallo stato interno dell'istanza dell'oggetto, può essere statico. E si consiglia di impostarlo come statico per la manutenibilità / riutilizzabilità del codice. Se il metodo mainnon era statico, significa che lo stato dell'istanza della classe deve essere noto ed è molto più complesso da definire, come quale costruttore usare per primo.
Yves Martin,

@KonradRudolph È interessante notare che Oak (il predecessore di Java) aveva già richiesto che il metodo principale avesse un prototipo simile: public static void main(String arguments[])- Riferimento: Oak 0.2 Spec .
Assylias,

2
@Yves Può essere. Non è necessario, se un altro design ha un senso. Ho sentito alcuni buoni argomenti nei commenti qui, ma penso ancora che un processo sia effettivamente molto simile a un thread (lo è ), e un thread in Java è solitamente rappresentato come un'istanza di Runnable. Rappresentare l'intero processo allo stesso modo (ovvero avere Runnable.Runcome punto di ingresso) ha sicuramente senso in Java. Naturalmente, di per Runnablesé è probabilmente un difetto di progettazione, causato dal fatto che Java non ha metodi anonimi (ancora). Ma dato che è già lì ...
Konrad Rudolph,

36

Facciamo semplicemente finta che staticnon sarebbe richiesto come punto di accesso all'applicazione.

Una classe di applicazione sarebbe quindi simile a questa:

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

La distinzione tra codice costruttore e mainmetodo è necessaria perché in OO un costruttore deve solo assicurarsi che un'istanza sia inizializzata correttamente. Dopo l'inizializzazione, l'istanza può essere utilizzata per il "servizio" previsto. Mettere l'intero codice dell'applicazione nel costruttore lo rovinerebbe.

Quindi questo approccio imporrebbe tre diversi contratti sull'applicazione:

  • Ci deve essere un costruttore predefinito. Altrimenti, la JVM non saprebbe quale costruttore chiamare e quali parametri dovrebbero essere forniti.
  • Ci deve essere un mainmetodo 1 . Ok, questo non è sorprendente.
  • La classe non deve essere abstract. Altrimenti, la JVM non potrebbe istanziarla.

L' staticapproccio invece richiede un solo contratto:

  • Ci deve essere un mainmetodo 1 .

Qui né abstractné più costruttori contano.

Poiché Java è stato progettato per essere un linguaggio semplice per l'utente , non sorprende che anche il punto di ingresso dell'applicazione sia stato progettato in modo semplice utilizzando un contratto e non in modo complesso utilizzando tre contratti indipendenti e fragili.

Nota: questo argomento non riguarda la semplicità all'interno della JVM o all'interno della JRE. Questo argomento riguarda la semplicità per l' utente .


1 Qui la firma completa conta come un solo contratto.


1
In realtà, i requisiti sono più complessi: ci deve essere un mainmetodo che è public, statice ha la firma void main(String[]). Concordo sul fatto che, se il metodo fosse un metodo di istanza, il JRE avrebbe un po ' più di lavoro ma il tipo di lavoro sarebbe lo stesso e la complessità non significativamente più alta (vedi discussioni nei commenti della risposta precedente). Non credo che questa differenza spieghi la decisione di rendere statico il punto di ingresso, in particolare poiché esistono i metodi richiesti per la risoluzione di un metodo di istanza e sono facilmente utilizzabili.
Konrad Rudolph,

3
@KonradRudolph: il mio punto non riguarda il lavoro che il JRE dovrebbe svolgere. Il mio punto è costringere ogni utente della lingua a seguire più contratti, se necessario. In questo senso un static public main(String[])metodo è una firma e quindi un contratto. Altrimenti devono essere seguiti tre contratti indipendenti .
AH,

1
Ah. Non sono ancora d'accordo sul fatto che questo faccia alcuna differenza. Le classi dei punti di ingresso potrebbero ben implementare Runnable. Chiaramente, Java si aspetta che gli sviluppatori seguano sempre quel contratto, perché dovrebbe essere troppo per il punto di ingresso dell'applicazione? Non ha senso.
Konrad Rudolph,

3
@KonradRudolph: non vi è alcuna contraddizione: in un caso il sistema imporrebbe tre contratti all'utente. Contratti che sono dubbi, che non sono verificabili tramite il compilatore e che sono, dal punto di vista dell'utente, indipendenti. Nel solito Threade nel Runnablecaso in cui nulla sia nascosto all'utente, può vedere chiaramente cosa sta succedendo e ha il cambiamento per implementare solo quei contratti che gli si adattano: ha il controllo, non il sistema.
AH,

2
Questa è la migliore risposta qui. È un peccato che molti utenti leggano solo le prime 2 o 3 risposte sulla pagina; e è improbabile che ci arrivi presto. Indica il punto importante in cui un costruttore è SOLO per l'inizializzazione - e quindi non ha senso codificare in uno stile in cui il costruttore esegue l'intera applicazione.
Dawood ibn Kareem,

14

In caso contrario, quale costruttore dovrebbe essere utilizzato se ce ne sono più di uno?

Ulteriori informazioni sull'inizializzazione e l'esecuzione dei programmi Java sono disponibili nelle specifiche del linguaggio Java .


12

Prima che venga chiamato il metodo principale, nessun oggetto viene istanziato. Avere la parola chiave statica significa che il metodo può essere chiamato senza prima creare alcun oggetto.


Sbagliato. O almeno molto impreciso. public class Main {oggetto statico oggetto = new Object () {{System.out.println ("oggetto creato"); }}; public static void main (String [] args) {System.out.println ("in main"); }}
eljenso,

Commento equo. Tecnicamente, avrei dovuto dire che prima che venga chiamato il metodo Main, la classe contenente il metodo principale non è istanziata.
BlackWasp,

12

Perché altrimenti, avrebbe bisogno di un'istanza dell'oggetto per essere eseguita. Ma deve essere chiamato da zero, senza prima costruire l'oggetto, poiché di solito è compito della funzione main () (bootstrap), analizzare gli argomenti e costruire l'oggetto, di solito usando questi argomenti / parametri del programma.


10

Lasciami spiegare queste cose in un modo molto più semplice:

public static void main(String args[])

Tutte le applicazioni Java, tranne le applet, iniziano la loro esecuzione da main().

La parola chiave publicè un modificatore di accesso che consente al membro di essere chiamato dall'esterno della classe.

staticviene utilizzato perché consente main()di essere chiamato senza dover creare un'istanza di una determinata istanza di quella classe.

voidindica che main()non restituisce alcun valore.


9

Qual è il significato di public static void main(String args[])?

  1. public è un identificatore di accesso che significa che chiunque può accedervi / invocarlo come JVM (Java Virtual Machine.
  2. staticconsente main()di essere chiamato prima della creazione di un oggetto della classe. Questo è necessario perché main()viene chiamato dalla JVM prima di creare qualsiasi oggetto. Poiché è statico, può essere richiamato direttamente tramite la classe.

    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 */
        }
    }

    Allo stesso modo, utilizziamo statico qualche volta per metodi definiti dall'utente in modo da non dover creare oggetti.

  3. voidindica che il main()metodo dichiarato non restituisce un valore.

  4. String[] argsspecifica l'unico parametro nel main()metodo

    args- un parametro che contiene una matrice di oggetti di tipo classe String.


6

Vengono costruite applet, midlet, servlet e bean di vario genere e vengono quindi chiamati metodi del ciclo di vita. Invocare main è tutto ciò che viene mai fatto alla classe principale, quindi non è necessario che uno stato venga mantenuto in un oggetto chiamato più volte. È abbastanza normale aggiungere main a un'altra classe (anche se non è una grande idea), che potrebbe ostacolare l'utilizzo della classe per creare l'oggetto principale.


5

È solo una convenzione, ma probabilmente più conveniente dell'alternativa. Con un main statico, tutto ciò che devi sapere per invocare un programma Java è il nome e la posizione di una classe. Se non fosse statico, dovresti anche sapere come creare un'istanza di quella classe o richiedere che la classe abbia un costruttore vuoto.


Non è una convenzione; fa parte delle specifiche del linguaggio; il runtime non riconoscerà una classe senza un metodo principale statico come punto di ingresso valido.
Rob,

2
Le specifiche linguistiche seguono la convenzione. Non è necessario che i progettisti Java abbiano optato per richiedere un main statico. Tuttavia, come spiega Logan, le alternative sono più complicate.
David Arno,

@DavidArno Sarebbe più sensato dire che la convenzione segue le specifiche del linguaggio.
Marchese di Lorne,

5

Se il metodo principale non fosse statico, dovrai creare un oggetto della tua classe principale dall'esterno del programma. Come vorresti farlo?


5

Quando si esegue la Java Virtual Machine (JVM) con il javacomando,

java ClassName argument1 argument2 ...

Quando si esegue l'applicazione, si specifica il nome della sua classe come argomento per il comando java, come sopra

la JVM tenta di invocare il metodo principale della classe specificata

—A questo punto, non sono stati creati oggetti della classe.

Dichiarando maincome statica allowsla JVM alla creazione invokeprincipale della classe.withoutinstance

torniamo al comando

ClassNameè un command-line argumentJVM che indica quale classe eseguire. Seguendo ClassName, è anche possibile specificare un list of Strings(separato da spazi) come argomenti della riga di comando che la JVM passerà alla propria applicazione. -Questi argomenti potrebbero essere usati per specificare le opzioni (ad es. Un nome file) per eseguire l'applicazione- questo è il motivo per cui esiste un parametro chiamato String[] argsnella

Riferimenti: Java ™ How To Program (Early Objects), decima edizione


4

Di recente, una domanda simile è stata pubblicata su Programmers.SE

  • Perché un metodo principale statico in Java e C #, piuttosto che un costruttore?

    Alla ricerca di una risposta definitiva da una fonte primaria o secondaria perché (in particolare) Java e C # hanno deciso di avere un metodo statico come punto di ingresso - piuttosto che rappresentare un'istanza dell'applicazione da un'istanza di una Applicationclasse, con il punto di ingresso come costruttore appropriato?

TL; parte DR della risposta accettata è,

In Java, la ragione public static void main(String[] args)è quella

  1. Voleva papera
  2. il codice scritto da qualcuno con esperienza in C (non in Java)
  3. per essere eseguito da qualcuno abituato a eseguire PostScript su NeWS

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

 
Per C #, il ragionamento è transitivamente simile per così dire. I progettisti linguistici hanno tenuto familiare la sintassi del punto di ingresso del programma per i programmatori provenienti da Java. Come dice l' architetto C # Anders Hejlsberg ,

... il nostro approccio con C # è stato semplicemente quello di offrire un'alternativa ... ai programmatori Java ...

...


3

Penso che la parola chiave 'statico' trasformi il metodo principale in un metodo di classe e che i metodi di classe ne abbiano una sola copia e possano essere condivisi da tutti, inoltre non richiede un oggetto come riferimento. Pertanto, quando viene compilata la classe del driver, è possibile invocare il metodo principale. (Sono solo a livello alfabetico di java, scusa se sbaglio)


Tutti i metodi "ne hanno una sola copia".
Marchese di Lorne,

3

main () è statico perché; a quel punto del ciclo di vita dell'applicazione, lo stack dell'applicazione è di natura procedurale a causa della mancanza di istanze di oggetti.

È una lavagna pulita. La tua applicazione è in esecuzione a questo punto, anche senza alcun oggetto dichiarato (ricorda, ci sono schemi di codifica procedurale E OO). Come sviluppatore, trasformi l'applicazione in una soluzione orientata agli oggetti creando istanze dei tuoi oggetti e in base al codice compilato all'interno.

Orientato agli oggetti è ottimo per milioni di ovvi motivi. Tuttavia, sono passati i giorni in cui la maggior parte degli sviluppatori di VB utilizzava regolarmente parole chiave come "goto" nel loro codice. "goto" è un comando procedurale in VB che viene sostituito dalla sua controparte OO: invocazione del metodo.

Potresti anche considerare il punto di ingresso statico (principale) come pura libertà. Se Java fosse stato abbastanza diverso da creare un'istanza di un oggetto e presentarti solo quell'istanza in esecuzione, non avresti scelta MAI scrivere un'app procedurale. Per quanto inimmaginabile possa sembrare per Java, è possibile che ci siano molti scenari che richiedono approcci procedurali.

Questa è probabilmente una risposta molto oscura. Ricorda, "class" è solo una raccolta di codice correlato. L '"istanza" è una generazione autonoma isolata, vivente e che respira di quella classe.


7
Questo non è corretto Molti oggetti vengono istanziati prima del mainraggiungimento. E se includi un costruttore statico nella classe contenente main, che viene eseguito mainanche prima .
Konrad Rudolph,

2

È solo una convenzione. La JVM potrebbe certamente trattare i metodi principali non statici se quella fosse la convenzione. Dopotutto, puoi definire un inizializzatore statico sulla tua classe e creare un'istanza di un milione di oggetti prima di arrivare al tuo metodo main ().


2

Il protoipo public static void main(String[])è una convenzione definita nel JLS :

Il metodo principale deve essere dichiarato pubblico, statico e nullo. Deve specificare un parametro formale (§8.4.1) il cui tipo dichiarato è array di String.

Nella specifica JVM 5.2. Avvio della macchina virtuale possiamo leggere:

La macchina virtuale Java si avvia creando una classe iniziale, che viene specificata in modo dipendente dall'implementazione, usando il caricatore di classi bootstrap (§5.3.1). La macchina virtuale Java collega quindi la classe iniziale, la inizializza e invoca il metodo della classe pubblica void main (String []) . L'invocazione di questo metodo guida tutte le ulteriori esecuzioni. L'esecuzione delle istruzioni della macchina virtuale Java che costituisce il metodo principale può causare il collegamento (e di conseguenza la creazione) di classi e interfacce aggiuntive, nonché l'invocazione di metodi aggiuntivi.

Cosa divertente, nelle specifiche JVM non si menziona che il metodo principale deve essere statico. Ma la specifica dice anche che la macchina virtuale Java esegue 2 passaggi prima:

L'inizializzazione di una classe o interfaccia consiste nell'eseguire il suo metodo di inizializzazione di classe o interfaccia.

In 2.9. Metodi speciali :

Viene definito un metodo di inizializzazione di classe o interfaccia :

Una classe o un'interfaccia ha al massimo una classe o un metodo di inizializzazione dell'interfaccia e viene inizializzata (§5.5) invocando quel metodo. Il metodo di inizializzazione di una classe o interfaccia ha il nome speciale <clinit>, non accetta argomenti ed è nullo.

E un metodo di inizializzazione di classe o interfaccia è diverso da un metodo di inizializzazione di istanza definito come segue:

A livello della macchina virtuale Java, ogni costruttore scritto nel linguaggio di programmazione Java (JLS §8.8) appare come un metodo di inizializzazione dell'istanza che ha il nome speciale <init>.

Quindi la JVM inizializza una classe o un metodo di inizializzazione dell'interfaccia e non un metodo di inizializzazione dell'istanza che è in realtà un costruttore. Quindi non è necessario menzionare che il metodo principale deve essere statico nelle specifiche JVM perché è implicito dal fatto che nessuna istanza viene creata prima di chiamare il metodo principale.


2

La publicparola chiave è un modificatore di accesso, che consente al programmatore di controllare la visibilità dei membri della classe. Quando un membro della classe è preceduto da public, è possibile accedere a quel membro tramite un codice esterno alla classe in cui è dichiarato.

L'opposto di publicè private, che impedisce a un membro di essere utilizzato da un codice definito al di fuori della sua classe.

In questo caso, main()deve essere dichiarato come public, poiché deve essere chiamato da un codice esterno alla sua classe all'avvio del programma.

La parola chiave staticconsente main()di essere chiamata senza dover creare un'istanza di un'istanza particolare della classe. Ciò è necessario poiché main()viene chiamato dall'interprete Java prima che vengano creati eventuali oggetti.

La parola chiave voidindica semplicemente al compilatore che main()non restituisce un valore.


1

Il vero punto di accesso a qualsiasi applicazione è un metodo statico. Se il linguaggio Java supportava un metodo di istanza come "punto di ingresso", il runtime avrebbe bisogno di implementarlo internamente come metodo statico che costruiva un'istanza dell'oggetto seguita chiamando il metodo di istanza.

Detto questo, esaminerò la logica per la scelta di una delle tre opzioni seguenti:

  1. A static void main()come lo vediamo oggi.
  2. Un metodo di istanza void main()chiamato su un oggetto appena costruito.
  3. Usando il costruttore di un tipo come punto di ingresso (ad esempio, se si chiamasse la classe di ingresso Program, l'esecuzione sarebbe effettivamente composta new Program()).

Abbattersi:

static void main()

  1. Chiama il costruttore statico della classe che lo racchiude.
  2. Chiama il metodo statico main().

void main()

  1. Chiama il costruttore statico della classe che lo racchiude.
  2. Crea un'istanza della classe che racchiude chiamando in modo efficace new ClassName().
  3. Chiama il metodo dell'istanza main().

new ClassName()

  1. Chiama il costruttore statico della classe che lo racchiude.
  2. Costruisce un'istanza della classe (quindi non fa nulla con essa e semplicemente restituisce).

Fondamento logico:

Andrò in ordine inverso per questo.

Tieni presente che uno degli obiettivi di progettazione di Java era enfatizzare (se possibile) buone pratiche di programmazione orientate agli oggetti. In questo contesto, il costruttore di un oggetto inizializza l'oggetto, ma non dovrebbe essere responsabile del comportamento dell'oggetto. Pertanto, una specifica che ha fornito un punto di ingresso new ClassName()confonderebbe la situazione per i nuovi sviluppatori Java forzando un'eccezione alla progettazione di un costruttore "ideale" su ogni applicazione.

Creando main()un metodo di istanza, il problema sopra è sicuramente risolto. Tuttavia, crea complessità richiedendo alla specifica di elencare la firma del costruttore della classe di immissione e la firma del main()metodo.

In sintesi, la specifica di a static void main()crea una specifica con la minima complessità, pur aderendo al principio di porre il comportamento nei metodi . Considerando quanto sia semplice implementare un main()metodo che costruisce a sua volta un'istanza di una classe e chiama un metodo di istanza, non vi è alcun vantaggio reale nel specificare main()come metodo di istanza.


1
Questa è solo una domanda. Java ha comunque bisogno di un caricatore di applicazioni che esegua operazioni pesanti prima di chiamare main. La tua logica di mainessere troppo complessa per i principianti sembra incredibile. In effetti, lo statico mainè molto confuso per i principianti, dubito che un costruttore lo sarebbe di più. Dici che un "costruttore non dovrebbe essere responsabile del comportamento dell'oggetto". Sembra interessante ma non sono sicuro di essere d'accordo. Perché no? Cosa impedisce questo?
Konrad Rudolph,

1

statico: quando JVM effettua una chiamata al metodo principale, non esiste alcun oggetto per la classe chiamata, pertanto deve disporre di un metodo statico per consentire l'invocazione dalla classe.


1

Non so se JVM chiama il metodo principale prima che gli oggetti vengano istanziati ... Ma c'è un motivo molto più potente per cui il metodo main () è statico ... Quando JVM chiama il metodo principale della classe (diciamo , Persona). lo invoca da " Person.main () ". Vedete, la JVM lo invoca con il nome della classe. Questo è il motivo per cui il metodo main () dovrebbe essere statico e pubblico in modo che sia accessibile dalla JVM.

Spero che abbia aiutato. In caso affermativo, fammi sapere commentando.


0

I metodi statici non richiedono alcun oggetto. Funziona direttamente, quindi il main funziona direttamente.


0

La parola chiave statica nel metodo principale viene utilizzata perché non è presente alcuna istanza nel metodo principale. Ma l'oggetto è costruito piuttosto che invocazione, di conseguenza usiamo la parola chiave statica nel metodo principale. Nel contesto jvm la memoria viene creata quando la classe viene caricata in essa e tutti i membri statici sono presenti in quella memoria. se rendiamo lo statico principale ora sarà in memoria e sarà accessibile a jvm (class.main (..)) in modo da poter chiamare il metodo principale senza la necessità di creare heap.


0

È solo una convenzione, come possiamo vedere qui:

Il metodo deve essere dichiarato pubblico e statico , non deve restituire alcun valore e deve accettare un array String come parametro. Per impostazione predefinita, il primo argomento non opzionale è il nome della classe da invocare. È necessario utilizzare un nome di classe completo. Se viene specificata l'opzione -jar, il primo argomento non-opzione è il nome di un archivio JAR contenente file di classe e di risorse per l'applicazione, con la classe di avvio indicata dall'intestazione manifest Main-Class.

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


Regola della lingua, intendi.
Marchese di Lorne,

0

Le parole chiave pubbliche statiche vuote indicano che l'interprete JVM (Java virtual machine) può chiamare il metodo principale del programma per avviare il programma (pubblico) senza creare un'istanza della classe (statico) e il programma non restituisce i dati all'interprete Java VM (vuoto) quando finisce.

Fonte: Essentials, Parte 1, Lezione 2: Creazione di applicazioni


0

Fondamentalmente facciamo quei MEMBRI DATI e FUNZIONI DEL MEMBRO come STATICI che non stanno eseguendo alcuna attività relativa ad un oggetto. E nel caso del metodo principale, lo stiamo realizzando come STATICO perché non ha nulla a che fare con l'oggetto, poiché il metodo principale viene sempre eseguito indipendentemente dal fatto che si stia creando o meno un oggetto.


0

Qualsiasi metodo dichiarato come statico in Java appartiene alla classe stessa. Anche in questo caso il metodo statico di una particolare classe è accessibile solo facendo riferimento alla classe simileClass_name.method_name();

Pertanto non è necessario creare un'istanza di una classe prima di accedere a un metodo statico.

Quindi il metodo main () viene dichiarato in staticmodo tale che sia possibile accedervi senza creare un oggetto di quella classe.

Poiché salviamo il programma con il nome della classe in cui è presente il metodo principale (o da dove il programma dovrebbe iniziare la sua esecuzione, applicabile per le classi senza main()metodo () (Livello avanzato)). Quindi nel modo sopra menzionato:

Class_name.method_name();

è possibile accedere al metodo principale.

In breve, quando il programma viene compilato, cerca il main()metodo con Stringargomenti come: main(String args[])nella classe menzionata (cioè dal nome del programma), e poiché all'inizio non ha spazio per creare un'istanza di quella classe, quindi main () il metodo è dichiarato statico.


Succede quando il programma viene eseguito, non compilato.
Marchese di Lorne,

0

Da java.sun.com (ci sono ulteriori informazioni sul sito):

Il metodo principale è statico per fornire all'interprete Java VM un modo per avviare la classe senza creare prima un'istanza della classe di controllo. Le istanze della classe di controllo vengono create nel metodo principale dopo l'avvio del programma.

La mia comprensione è sempre stata semplicemente che il metodo principale, come qualsiasi metodo statico, può essere chiamato senza creare un'istanza della classe associata, consentendone l'esecuzione prima di qualsiasi altra cosa nel programma. Se non fosse statico, dovresti creare un'istanza di un oggetto prima di chiamarlo, il che crea un problema "pollo e uovo", poiché il metodo principale è generalmente quello che usi per istanziare oggetti all'inizio del programma.


Ma non viene eseguito "prima di ogni altra cosa nel programma". L'intero argomento è un errore, e per di più, questa non è la prima risposta menzionandola, e nemmeno la seconda o la terza.
Konrad Rudolph,

Mi dispiace che la mia risposta ripeta ciò che gli altri hanno detto; Ho solo risposto al meglio della mia comprensione e da ciò che ho potuto trovare online. Dai risultati che ho visto non c'è altra ragione per cui il metodo principale sia statico; a meno che non ce ne sia uno nascosto da qualche parte, forse questa è l'unica risposta. La mia comprensione di Java è abbastanza semplice, ma ho sentito la ragione sopra (da professori, libri di testo, ecc.) E mai nessun altro.
Jesse M,

@Jesse M Il tuo commento ha senso solo se non hai nemmeno considerato di leggere prima le altre risposte. Che tra l'altro non è una cosa inverosimile da fare. Come hai detto te stesso, la tua comprensione è abbastanza semplice, quindi è molto probabile che qualcun altro abbia già risposto alla domanda in modo più competente. E il tuo commento sembra essere una razionalizzazione per rendere migliore la tua risposta. È un'affermazione straordinaria che tu abbia libri di testo e professori Java che pensano ciò che affermi e, francamente, non credo che lo facciano. (Qualche riferimento?)
LeoR,

1
@KonradRudolph I commenti principali sembrano abbastanza ragionevoli. main () viene utilizzato come punto di accesso al programma e ci sono diversi riferimenti sul sito Web Java che dicono che dovrebbe essere simile a come C / C ++ ha una funzione main (). Poiché Java è tutto oggetti, deve essere statico per evitare la creazione di istanze di oggetti. Avendolo statico, inoltre, può essere caricato ed eseguibile nella JVM in fase di esecuzione. Sto solo rigurgitando le risposte precedenti, ma mi chiedo cosa considereresti una risposta soddisfacente. Penso che il meglio che otterrai è "È così che lo volevano". Tieni presente la data di creazione di Java.
trevor-e,

1
@Jesse Spot-on. È del tutto possibile che sia semplicemente una questione di convenzioni (anche se spero che non lo sia, sarebbe una risposta così noiosa). Il mio interesse originale per questa domanda era perché pensavo che usare un'istanza appropriata per rappresentare l'oggetto "esecuzione dell'applicazione" e avere il punto di ingresso come metodo (o il costruttore) di questa classe sarebbe stato un progetto molto più ovvio, dal momento che Java è stato progettato per essere orientato agli oggetti dal get-go, e dal momento che oggetti apparentemente analoghe (fili, via Runnable) in Java farlo usare questo disegno. Perché l'eccezione (apparente) qui?
Konrad Rudolph,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.