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




(25)

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

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

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


Answers

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. static consente a main() di essere chiamato prima che un oggetto della classe sia stato creato. Questo è necessario perché main() viene chiamato dalla JVM prima che vengano creati tutti gli oggetti. 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, usiamo statico qualche volta per i metodi definiti dall'utente, così non abbiamo bisogno di creare oggetti.

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

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

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


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 .


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.


Facciamo semplicemente finta, che static non sarebbe richiesta come il punto di ingresso dell'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 metodo main è 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 il codice completo dell'applicazione nel costruttore lo rovinerebbe.

Quindi questo approccio costringerebbe tre diversi contratti sull'applicazione:

  • Ci deve essere un costruttore predefinito. In caso contrario, la JVM non saprebbe quale costruttore chiamare e quali parametri dovrebbero essere forniti.
  • Ci deve essere un metodo main 1 . Ok, questo non è sorprendente.
  • La classe non deve essere abstract . In caso contrario, la JVM non è stata in grado di creare un'istanza.

L'approccio static invece richiede solo un contratto:

  • Ci deve essere un metodo main 1 .

Qui non contano né i costruttori abstract né quelli multipli.

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 di JRE. Questo argomento riguarda la semplicità per l' utente .

1 Qui la firma completa conta come un solo contratto.


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.


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

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

Nella specifica JVM 5.2. Start-up della macchina virtuale possiamo leggere:

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

Cosa buffa, nelle specifiche JVM non è detto che il metodo principale debba essere statico. Ma le specifiche dicono anche che la macchina virtuale Java esegue 2 passaggi prima:

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

Nel 2.9. Metodi speciali :

Viene definito un metodo di inizializzazione di classe o interfaccia :

Una classe o un'interfaccia ha al massimo un metodo di inizializzazione di classe o interfaccia ed è inizializzato (§5.5) invocando quel metodo. Il metodo di inizializzazione di una classe o di un'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 dell'istanza definito come segue:

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

Quindi la JVM inizializza un metodo di inizializzazione di classe o interfaccia e non un metodo di inizializzazione dell'istanza che è in realtà un costruttore. Quindi non c'è bisogno di 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.


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 ...

...


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

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


Se il metodo principale non fosse statico, avresti bisogno di creare un oggetto della tua classe principale al di fuori del programma. Come vorresti farlo?


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.


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.


Applet, midlet, servlet e bean di vario tipo vengono costruiti e quindi richiamati dai metodi del ciclo di vita. Invocare main è tutto ciò che viene fatto alla classe principale, quindi non c'è bisogno di tenere uno stato in un oggetto chiamato più volte. È abbastanza normale pin principale su un'altra classe (anche se non è una grande idea), che potrebbe intralciare l'uso della classe per creare l'oggetto principale.


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.


Penso che la parola chiave 'static' renda il metodo principale un metodo di classe, ei metodi di classe ne abbiano solo una copia e possano essere condivisi da tutti, e inoltre, non richiede un oggetto di riferimento. Pertanto, quando viene compilata la classe del driver, è possibile richiamare il metodo principale. (Sono solo al livello di alfabeto di java, scusa se ho torto)


Perché altrimenti, avrebbe bisogno di un'istanza dell'oggetto da eseguire. Ma deve essere richiamato da zero, senza prima costruire l'oggetto, dato che di solito è l'attività della funzione main () (bootstrap), per analizzare gli argomenti e costruire l'oggetto, solitamente usando questi parametri argomento / programma.


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.


La parola chiave statica nel metodo principale viene utilizzata perché non esiste alcuna istanziazione che si verifica nel metodo principale. Ma l'oggetto è costruito piuttosto che l'invocazione, come risultato usiamo la parola chiave statica nel metodo principale. Nel contesto jvm, la memoria viene creata quando la classe viene caricata in esso. Tutti i membri statici sono presenti in quella memoria. se facciamo la statica principale ora sarà in memoria e può essere accessibile a jvm (class.main (..)) in modo che possiamo chiamare il metodo principale senza necessità di creare un heap.


È 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


Il metodo è statico perché altrimenti ci sarebbe ambiguità: quale costruttore dovrebbe essere chiamato? Soprattutto se la tua classe ha questo aspetto:

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

La JVM dovrebbe chiamare la new JavaClass(int) ? Cosa dovrebbe passare per x ?

In caso contrario, la JVM dovrebbe istanziare JavaClass senza eseguire alcun metodo di costruzione? Penso che non dovrebbe, perché sarà il caso speciale dell'intera classe - a volte hai un'istanza che non è stata inizializzata, e devi controllarla in tutti i metodi che potrebbero essere chiamati.

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

Non ho idea del perché il main sia sempre contrassegnato come public .


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, a quel membro può accedere il codice al di fuori della classe in cui è dichiarato.

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

In questo caso, main()deve essere dichiarato come public, dal momento che deve essere richiamato dal codice al di fuori della sua classe all'avvio del programma.

La parola chiave staticpermette main()di essere chiamata senza dover istanziare una particolare istanza della classe. Questo è necessario poiché main()viene chiamato dall'interprete Java prima che vengano creati tutti gli oggetti.

La parola chiave voiddice semplicemente al compilatore che main()non restituisce un 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.


Il metodo main () in C ++, C # e Java sono statici perché possono essere richiamati dal motore di runtime senza dover istanziare un'istanza della classe genitore.


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.


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


Dichiarare un metodo staticsignifica che possiamo chiamare quel metodo con il suo nome di classe e se anche quella classe è abstractcosì, non ha senso chiamarla in quanto non contiene alcun corpo, e quindi non possiamo dichiarare un metodo sia come statice abstract.





java static main