main final - Perché il metodo principale Java è statico?





15 Answers

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

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

Fondamentalmente, java.exe è un'applicazione C super semplice che analizza la riga di comando, crea un nuovo array String nella JVM per contenere quegli argomenti, analizza il nome della classe che hai specificato come contenente main (), usa le chiamate JNI per trovare il main () stesso metodo, quindi richiama il metodo main (), passando l'array di stringhe appena creato come parametro. Questo è molto, molto simile a quello che fai quando usi Reflection da Java, ma usa semplicemente chiamate di funzioni native chiamate in modo confuso.

Sarebbe perfettamente legale scrivere la tua versione di java.exe (l'origine è distribuita con JDK) e fare qualcosa di completamente diverso. In realtà, questo è esattamente ciò che facciamo con tutte le nostre app basate su Java.

Ciascuna delle nostre app Java ha il proprio launcher. Facciamo questo principalmente in modo da ottenere il nostro nome e il nome del processo, ma è utile in altre situazioni in cui vogliamo fare qualcosa oltre alla normale chiamata main () per far funzionare le cose (ad esempio, in un caso stiamo facendo Interoperabilità COM, e in realtà passiamo un handle COM in main () invece di un array di stringhe).

Quindi, lungo e corto: il motivo per cui è statico è b / c che è conveniente. Il motivo per cui è chiamato "main" è che doveva essere qualcosa, e main () è ciò che hanno fatto ai vecchi tempi di C (e in quei giorni, il nome della funzione era importante). Suppongo che java.exe ti abbia permesso di specificare solo un nome di metodo principale completo, invece della sola classe (java com.mycompany.Foo.someSpecialMain) - ma questo rende solo più difficile sugli IDE il rilevamento automatico del ' classi "lavorabili" in un progetto.

java static main

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

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

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




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

Questo è il modo in cui Java Language è progettato e Java Virtual Machine è progettato e scritto.

Oracle Java Language Specification

Consulta Capitolo 12 Esecuzione - Sezione 12.1.4 Invoca Test.main :

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

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

public static void main(String[] args)

o

public static void main(String... args)

Specifica Java Virtual Machine Oracle

Scopri Capitolo 2 Concetti sul linguaggio di programmazione Java - Sezione 2.17 Esecuzione :

La Java virtual machine avvia l'esecuzione invocando il metodo main di una determinata classe e passandogli un singolo argomento, che è una matrice di stringhe. Questo fa sì che la classe specificata venga caricata (§2.17.2), collegata (§2.17.3) ad altri tipi che usa e inizializzata (§2.17.4). Il metodo principale deve essere dichiarato pubblico, statico e vuoto.

Oracle OpenJDK Source

Scarica ed estrai il jar sorgente e vedi 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);

... ...



Se non lo fosse, quale costruttore dovrebbe essere usato se ce ne sono più di uno?

Sono disponibili ulteriori informazioni sull'inizializzazione e l'esecuzione dei programmi Java disponibili nella specifica del linguaggio Java .




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




Lascia che ti spieghi queste cose in un modo molto più semplice:

public static void main(String args[])

Tutte le applicazioni Java, eccetto 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.

static è usato perché permette a main() di essere chiamato senza dover istanziare una particolare istanza di quella classe.

void indica che main() non restituisce alcun valore.




È solo una convenzione, ma probabilmente più conveniente dell'alternativa. Con una statica principale, 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 istanziare quella classe, o richiedere che la classe abbia un costruttore vuoto.




Quando esegui Java Virtual Machine (JVM) con il comando java ,

java ClassName argument1 argument2 ...

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

la JVM tenta di richiamare il metodo principale della classe specificata

-In questo punto, non sono stati creati oggetti della classe.

La dichiarazione di main come static allows JVM di invoke main without creare instance della classe.

torniamo al comando

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

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




main () è statico perché; a quel punto nel ciclo di vita dell'applicazione, lo stack dell'applicazione è di natura procedurale poiché non vi sono oggetti ancora istanziati.

È una lavagna pulita. La tua applicazione è in esecuzione a questo punto, anche senza che vengano dichiarati oggetti (ricorda, ci sono schemi procedurali e di codifica OO). Tu, come sviluppatore, trasforma l'applicazione in una soluzione orientata agli oggetti creando istanze dei tuoi oggetti e in base al codice compilato all'interno.

Orientato agli oggetti è grande per milioni di ragioni ovvie. 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 istanziare un oggetto e presentasse solo quell'istanza durante l'esecuzione, non avresti altra scelta MA 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, "classe" è solo una raccolta di codice correlato. "Istanza" è una generazione autonoma isolata, vivente e che respira di quella classe.




Recentemente, 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 per il motivo per cui (in particolare) Java e C # decidono di avere un metodo statico come loro punto di ingresso - piuttosto che rappresentare un'istanza dell'applicazione da un'istanza di una classe Application , con il punto di ingresso un costruttore appropriato?

TL;DR parte della risposta accettata è,

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

  1. Voleva Gosling
  2. il codice scritto da qualcuno esperto in C (non in Java)
  3. da eseguire da qualcuno abituato a eseguire PostScript su NeWS


Per C #, il ragionamento è transitoriamente simile per così dire. I progettisti di linguaggi hanno mantenuto nota 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 ...

...




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

Con quello fuori mano, esaminerò la logica per la scelta di uno specifico delle seguenti tre opzioni:

  1. Un static void main() come lo vediamo oggi.
  2. Un metodo di istanza void main() chiamato su un oggetto appena costruito.
  3. Utilizzando il costruttore di un tipo come punto di ingresso (ad esempio, se la classe di voce era chiamata Program , l'esecuzione sarebbe effettivamente costituita dal new Program() ).

Abbattersi:

static void main()

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

void main()

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

new ClassName()

  1. Chiama il costruttore statico della classe che include.
  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 quello di enfatizzare (richiedono quando possibile) buone pratiche di programmazione orientata 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 forniva un entry point del new ClassName() confondeva la situazione dei nuovi sviluppatori Java forzando un'eccezione alla progettazione di un costruttore "ideale" su ogni applicazione.

Rendendo main() un metodo di istanza, il problema di cui sopra è certamente risolto. Tuttavia, crea complessità richiedendo la specifica per elencare la firma del costruttore della classe entry e la firma del metodo main() .

In sintesi, specificando un static void main() crea una specifica con la minore complessità mentre si aderisce al principio di collocare il comportamento in metodi . Considerando quanto sia semplice implementare un metodo main() che costruisce essa stessa un'istanza di una classe e chiama un metodo di istanza, non vi è alcun reale vantaggio nello specificare main() come metodo di istanza.




statico - Quando la JVM effettua una chiamata al metodo principale, non esiste alcun oggetto esistente per la classe chiamata, pertanto deve avere un metodo statico per consentire il richiamo dalla classe.




I metodi statici non richiedono alcun oggetto. Esegue direttamente le corse principali direttamente.




È 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 richiamare. Deve essere usato un nome di classe completo. Se viene specificata l'opzione -jar, il primo argomento non opzionale è il nome di un archivio JAR contenente i 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




Fondamentalmente, rendiamo quei MEMBRI DI DATI e le FUNZIONI MEMBRI come STATIC che non svolgono alcuna attività relativa ad un oggetto. E in caso di metodo principale, lo stiamo facendo come uno STATIC perché non ha nulla a che fare con l'oggetto, poiché il metodo principale viene sempre eseguito indipendentemente dal fatto che stiamo creando o meno un oggetto.




c'è una ragione semplice dietro di esso perché l'oggetto non è richiesto per chiamare il metodo statico, se fosse un metodo non statico, la macchina virtuale java crea prima l'oggetto quindi chiama il metodo main () che porterà al problema dell'allocazione extra della memoria.




Related