Pourquoi la méthode principale Java est-elle statique?


505

La signature de méthode d'une méthode Java main () est:

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

Y a-t-il une raison pour que cette méthode soit statique?


1
dans ce cas, nous ne devrions pas dire la signature de la méthode , car le terme se réfère uniquement aux noms de méthode et à ses paramètres
Andrew Tobilko

Java est délibérément conçu pour sembler familier à un programmeur C. Ceci est très proche de la convention C.
Thorbjørn Ravn Andersen

Réponses:


337

La méthode est statique car sinon il y aurait ambiguïté: quel constructeur faut-il appeler? Surtout si votre classe ressemble à ceci:

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

La JVM doit-elle appeler new JavaClass(int)? Que doit-il passer x?

Sinon, la JVM doit-elle instancier JavaClasssans exécuter de méthode constructeur? Je pense que ce ne devrait pas être le cas, car cela mettra en cause votre classe entière - parfois, vous avez une instance qui n'a pas été initialisée, et vous devez la vérifier dans chaque méthode qui pourrait être appelée.

Il y a tout simplement trop de cas marginaux et d'ambiguïtés pour que la JVM ait du sens d'avoir à instancier une classe avant l'appel du point d'entrée. Voilà pourquoimain est statique.

Je n'ai aucune idée pourquoi mainest toujours marqué publiccependant.


4
L'implémentation d'une interface ne résout pas le problème d'instanciation.
Jacob Krall

26
Personnellement, j'aime cela qui public static void mainsert de marqueur d'un point d'entrée - un constructeur public sans paramètre ne crie pas "C'est probablement un point d'entrée!" de la même manière.
Jacob Krall

5
@EdwinDalorzo - Que gagnerait à forcer l'instanciation de la classe de point d'entrée? L'appel d'une méthode statique impose le moins de fardeau à la classe. Il est libre de s'instancier si cela a plus de sens pour votre conception.
David Harkness

18
"Quel constructeur faut-il appeler?" En quoi est-il même concevable un problème? Le même «problème» existe pour la décision mainà appeler. Assez étrangement (pour vous), la JVM gère très bien cela.
Konrad Rudolph

9
La méthode principale est toujours publique car elle doit être accessible par le moteur d'exécution, la JVM.
gthm

398

Ce n'est qu'une convention. En fait, même le nom main () et les arguments passés sont purement conventionnels.

Lorsque vous exécutez java.exe (ou javaw.exe sous Windows), ce qui se passe réellement, c'est quelques appels Java Native Interface (JNI). Ces appels chargent la DLL qui est vraiment la JVM (c'est vrai - java.exe n'est PAS la JVM). JNI est l'outil que nous utilisons lorsque nous devons faire le pont entre le monde des machines virtuelles et le monde du C, C ++, etc. L'inverse est également vrai - il n'est pas possible (du moins à ma connaissance) JVM fonctionnant sans utiliser JNI.

Fondamentalement, java.exe est une application C super simple qui analyse la ligne de commande, crée un nouveau tableau de chaînes dans la JVM pour contenir ces arguments, analyse le nom de classe que vous avez spécifié comme contenant main (), utilise des appels JNI pour trouver le la méthode main () elle-même, puis invoque la méthode main (), en passant le tableau de chaînes nouvellement créé en tant que paramètre. Cela ressemble beaucoup à ce que vous faites lorsque vous utilisez la réflexion à partir de Java - il utilise simplement à la place des appels de fonction natifs nommés de manière confuse.

Il serait parfaitement légal pour vous d'écrire votre propre version de java.exe (la source est distribuée avec le JDK) et de lui faire faire quelque chose de complètement différent. En fait, c'est exactement ce que nous faisons avec toutes nos applications basées sur Java.

Chacune de nos applications Java a son propre lanceur. Nous le faisons principalement pour obtenir notre propre icône et nom de processus, mais cela est utile dans d'autres situations où nous voulons faire quelque chose en plus de l'appel principal principal () pour faire avancer les choses (par exemple, dans un cas, nous faisons Interopérabilité COM, et nous passons en fait un handle COM dans main () au lieu d'un tableau de chaînes).

Donc, long et court: la raison pour laquelle il est statique est b / c qui est pratique. La raison pour laquelle on l'appelle `` principal '' est que cela devait être quelque chose, et principal () est ce qu'ils faisaient dans l'ancien temps de C (et à cette époque, le nom de la fonction était important). Je suppose que java.exe aurait pu vous permettre de simplement spécifier un nom de méthode principale complet, au lieu de simplement la classe (java com.mycompany.Foo.someSpecialMain) - mais cela rend plus difficile pour les IDE de détecter automatiquement le ' classes lancables dans un projet.


66
+1: Très fascinant (en particulier la partie sur l'écriture d'une coutume java.exe)
Adam Paynter

9
Intéressant, je ne suis pas d'accord avec la "Ceci est juste une convention". Une partie de la réponse. La principale question du PO était la raison de la statique dans la déclaration. Je ne pense pas que staticla main()déclaration ne vise que la convention. Le fait que ce soit «main ()» et pas autre chose est cependant réalisable.
Jared

2
@David C'est vrai. En fait, j'aurais préféré une réponse de l'une des personnes impliquées à l'origine - mais c'était très loin. La plupart des autres réponses sont malheureusement un exercice de raisonnement ad hoc. Celui-ci donne des détails assez intéressants, en plus d'avoir l'humilité de ne pas inventer de faux détails techniques pour écarter une cause (probablement) non technique.
Konrad Rudolph

2
@Jared - Ils auraient pu nécessiter un constructeur public sans argument et être rendus mainnon statiques et rester dans les limites du langage. Sans entendre les concepteurs, nous devrons simplement accepter d'être en désaccord. :)
David Harkness

4
@BenVoigt Vous appelez LoadLibrary () pour obtenir la DLL jvm. Ensuite, vous appelez getprocaddress ("JNI_CreateJavaVM"), puis vous appelez la fonction JNI_CreateJavaVM ( docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/… ). Une fois la machine virtuelle chargée, vous utilisez des appels JNI standard pour trouver la classe correcte, chargez la méthode principale statique et invoquez-la. Il n'y a pas beaucoup de place pour une mauvaise interprétation. JNI est absolument la façon dont vous chargez la machine virtuelle. Vous pouvez être habitué à écrire uniquement JNI côté client en utilisant le mot-clé natif, javah -jni, etc ... mais ce n'est que la moitié de JNI.
Kevin Day

188

La main()méthode dans C++, C#et Javasont statiques,
car ils peuvent ensuite être invoqués par le moteur d'exécution sans avoir à instancier aucun objet, alors le code dans le corps de main()fera le reste.


1
D'accord, mais le runtime n'a-t-il pas pu instancier un objet de la classe? Et puis appelez la méthode Main? Pourquoi?
Andrei Rînea

12
Comment la JVM saurait-elle quel constructeur appeler, si votre classe principale avait des constructeurs surchargés? Quels paramètres passeraient-ils?
Jacob Krall,

1
@ Non, quand vous dites classe parent, voulez-vous dire la classe contenant la méthode principale? Parce que si c'est le cas, le terme "classe parent" est plutôt déroutant ici, et sinon cela n'aurait aucun sens pour moi. De plus, si par convention nous utilisons public static void main..., pourquoi la convention ne pourrait-elle pas être que la classe de point d'entrée d'application devrait avoir un constructeur public par défaut?
Edwin Dalorzo

2
@Jacob Comment la JVM pourrait-elle savoir quelle surcharge static void mainappeler? Pas un problème du tout.
Konrad Rudolph

4
@Namratha: Oui, il vous manque quelque chose. Ce n'est tout simplement pas vrai que "la méthode statique ne peut pas faire référence à une méthode non statique". L'instruction correcte est: "Chaque méthode statique doit fournir un objet lors de l'utilisation d'une méthode non statique". Et regardez, des staticméthodes telles que celles mainfréquemment utilisées newpour créer un tel objet.
Ben Voigt

38

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

C'est ainsi que Java Language est conçu et Java Virtual Machine est conçu et écrit.

Spécification du langage Oracle Java

Consultez le chapitre 12 Exécution - Section 12.1.4 Invoke Test.main :

Enfin, une fois l'initialisation de la classe Test terminée (au cours de laquelle d'autres chargements, liaisons et initialisations consécutifs peuvent s'être produits), la méthode main de Test est invoquée.

La méthode main doit être déclarée publique, statique et nulle. Il doit accepter un seul argument qui est un tableau de chaînes. Cette méthode peut être déclarée comme

public static void main(String[] args)

ou

public static void main(String... args)

Spécification de la machine virtuelle Oracle Java

Consultez le Chapitre 2 Concepts du langage de programmation Java - Section 2.17 Exécution :

La machine virtuelle Java démarre l'exécution en appelant la méthode main d'une classe spécifiée et en lui passant un seul argument, qui est un tableau de chaînes. Cela entraîne le chargement de la classe spécifiée (§2.17.2), sa liaison (§2.17.3) à d'autres types qu'elle utilise et son initialisation (§2.17.4). La méthode main doit être déclarée publique, statique et nulle.

Oracle OpenJDK Source

Téléchargez et extrayez le fichier source et voyez comment JVM est écrit, consultez ../launcher/java.c, qui contient du code C natif derrière la commande 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
Le problème ici est qu'il s'agit en fait d'une très bonne réponse à la question dans sa forme originale, avec de nombreuses références (+1). Cependant, j'aimerais en savoir plus sur la justification de la décision de conception de faire d'une méthode statique le point d'entrée, plutôt que d'un constructeur ou d'une méthode d'instance.
Konrad Rudolph

1
@KonradRudolph, pour des questions concernant le langage et la conception des spécifications JVM, vous pouvez peut-être essayer de contacter la source d'origine d'Oracle et voir si vous pouvez obtenir des commentaires positifs.
yorkw

2
De manière générale, lorsqu'un calcul de résultat d'une méthode ne dépend que de ses paramètres, de sorte qu'il ne dépend pas de l'état interne de l'instance d'objet, il peut être statique. Et il est recommandé de le définir comme statique pour la maintenabilité / réutilisation du code. Si la méthode mainn'était pas statique, cela signifie que l'état de l'instance de classe doit être connu et qu'il est beaucoup plus complexe à définir, comme le constructeur à utiliser en premier.
Yves Martin

@KonradRudolph Fait intéressant, Oak (le prédécesseur de Java) avait déjà besoin de la méthode principale pour avoir un prototype similaire: public static void main(String arguments[])- Référence: Oak 0.2 Spec .
assylias

2
@Yves C'est possible . Ce n'est pas nécessaire, si un autre design a du sens. J'ai entendu quelques bons arguments dans les commentaires ici , mais je pense toujours qu'un processus est effectivement très semblable à un fil (il est ), et un fil en Java est généralement représentée comme une instance de Runnable. Représenter l'ensemble du processus de la même manière (c'est-à-dire avoir Runnable.Runcomme point d'entrée) a vraiment du sens en Java. Bien sûr, Runnablelui-même est sans doute un défaut de conception, dû au fait que Java n'a pas (encore) de méthodes anonymes. Mais comme c'est déjà là…
Konrad Rudolph

36

Imaginons simplement que static cela ne soit pas requis comme point d'entrée de l'application.

Une classe d'application ressemblerait alors à ceci:

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

La distinction entre code constructeur et mainméthode est nécessaire car en langage OO, un constructeur doit seulement s'assurer qu'une instance est correctement initialisée . Après l'initialisation, l'instance peut être utilisée pour le "service" souhaité. Mettre le code d'application complet dans le constructeur gâcherait cela.

Cette approche forcerait donc trois contrats différents lors de la demande:

  • Il doit y avoir un constructeur par défaut. Sinon, la JVM ne saurait pas quel constructeur appeler et quels paramètres doivent être fournis.
  • Il doit y avoir une mainméthode 1 . Ok, ce n'est pas surprenant.
  • La classe ne doit pas l' être abstract. Sinon, la JVM n'a pas pu l'instancier.

L' staticapproche par contre ne nécessite qu'un seul contrat:

  • Il doit y avoir une mainméthode 1 .

Ici, abstractni les constructeurs multiples n'ont d'importance.

Étant donné que Java a été conçu pour être un langage simple pour l'utilisateur, il n'est pas surprenant que le point d'entrée de l'application ait également été conçu de manière simple en utilisant un contrat et non de manière complexe en utilisant trois contrats indépendants et fragiles.

Remarque: cet argument ne concerne pas la simplicité à l'intérieur de la JVM ou à l'intérieur du JRE. Cet argument concerne la simplicité pour l' utilisateur .


1 Ici, la signature complète ne compte que pour un seul contrat.


1
En fait, les exigences sont plus complexes: il doit y avoir une mainméthode qui est public, staticet a la signature void main(String[]). Je conviens que, si la méthode était une méthode d'instance, le JRE aurait un peu plus de travail mais le type de travail serait le même et la complexité ne serait pas significativement plus élevée (voir les discussions dans les commentaires de la réponse précédente). Je ne pense pas que cette différence explique la décision de rendre le point d'entrée statique, d'autant plus que les méthodes requises pour la résolution d'une méthode d'instance existent et sont facilement utilisables.
Konrad Rudolph

3
@KonradRudolph: Mon point ne concerne pas le travail que le JRE aurait à faire. Mon point est de forcer chaque utilisateur de la langue à suivre plus de contrats si nécessaire. En ce sens, une static public main(String[])méthode est une signature et donc un contrat. Sinon, trois contrats indépendants doivent être respectés.
AH

1
Ah. Je ne suis toujours pas d'accord pour dire que cela fait une différence. Les classes de points d'entrée pourraient bien être implémentées Runnable. De toute évidence, Java s'attend à ce que les développeurs respectent ce contrat tout le temps, pourquoi devrait-il être trop pour le point d'entrée de l'application? Ça n'a aucun sens.
Konrad Rudolph

3
@KonradRudolph: Il n'y a pas de contradiction: dans un cas, le système imposerait trois contrats à l'utilisateur. Contrats douteux, non vérifiables via le compilateur et indépendants du point de vue de l'utilisateur. Dans l'habituel Threadet dans le Runnablecas où rien n'est caché à l'utilisateur, il peut clairement voir ce qui se passe et il a le changement de ne mettre en œuvre que les contrats qui lui conviennent - il a le contrôle, pas le système.
AH

2
C'est la meilleure réponse ici. Il est dommage que de nombreux utilisateurs ne lisent que les 2 ou 3 premières réponses de la page; et celui-ci est peu susceptible d'arriver bientôt. Il mentionne le point important d'un constructeur étant UNIQUEMENT pour l'initialisation - et par conséquent cela n'a aucun sens de coder dans un style où le constructeur exécute l'application entière.
Dawood ibn Kareem

14

Si ce n'était pas le cas, quel constructeur utiliser s'il y en a plus d'un?

Il y a plus d'informations sur l'initialisation et l'exécution des programmes Java disponibles dans la spécification du langage Java .


12

Avant l'appel de la méthode principale, aucun objet n'est instancié. Le fait d'avoir le mot-clé statique signifie que la méthode peut être appelée sans créer d'abord d'objets.


Faux. Ou du moins très imprécis. classe publique Main {objet objet statique = nouvel objet () {{System.out.println ("objet créé"); }}; public static void main (String [] args) {System.out.println ("in main"); }}
eljenso

Bon commentaire. Techniquement, j'aurais dû dire qu'avant d'appeler la méthode Main, la classe contenant la méthode main n'est pas instanciée.
BlackWasp

12

Car sinon, il aurait besoin d'une instance de l'objet pour être exécuté. Mais il doit être appelé à partir de zéro, sans construire l'objet au préalable, car c'est généralement la tâche de la fonction main () (bootstrap), d'analyser les arguments et de construire l'objet, généralement en utilisant ces arguments / paramètres de programme.


10

Permettez-moi d'expliquer ces choses d'une manière beaucoup plus simple:

public static void main(String args[])

Toutes les applications Java, à l'exception des applets, démarrent leur exécution à partir de main().

Le mot public- clé est un modificateur d'accès qui permet d'appeler le membre depuis l'extérieur de la classe.

staticest utilisé car il permet main()d'être appelé sans avoir à instancier une instance particulière de cette classe.

voidindique que main()ne renvoie aucune valeur.


9

Quelle est la signification de public static void main(String args[])?

  1. public est un spécificateur d'accès signifiant que n'importe qui peut y accéder / l'invoquer tel que JVM (Java Virtual Machine.
  2. staticpermet main()d'être appelé avant la création d'un objet de la classe. Ceci est nécessaire car il main()est appelé par la machine virtuelle Java avant la création d'objets. Comme il est statique, il peut être directement appelé via 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 */
        }
    }

    De même, nous utilisons parfois de la statique pour les méthodes définies par l'utilisateur afin de ne pas avoir à créer d'objets.

  3. voidindique que la main()méthode déclarée ne renvoie pas de valeur.

  4. String[] argsspécifie le seul paramètre de la main()méthode.

    args- un paramètre qui contient un tableau d'objets de type classe String.


6

Des applets, des midlets, des servlets et des haricots de divers types sont construits et font ensuite appel à des méthodes de cycle de vie. L'appel de main est tout ce qui est fait à la classe principale, il n'est donc pas nécessaire qu'un état soit conservé dans un objet appelé plusieurs fois. Il est tout à fait normal d'épingler main sur une autre classe (bien que ce ne soit pas une bonne idée), ce qui gênerait l'utilisation de la classe pour créer l'objet principal.


5

C'est juste une convention, mais probablement plus pratique que l'alternative. Avec un main statique, tout ce que vous devez savoir pour appeler un programme Java est le nom et l'emplacement d'une classe. Si elle n'était pas statique, vous devez également savoir comment instancier cette classe, ou exiger que la classe ait un constructeur vide.


Ce n'est pas une convention; cela fait partie de la spécification du langage; le runtime ne reconnaîtra pas une classe sans méthode principale statique comme point d'entrée valide.
Rob

2
La spécification linguistique elle-même suit la convention. Il n'y a aucune exigence réelle pour les concepteurs Java d'avoir choisi d'exiger un principal statique. Cependant, comme l'explique Logan, les alternatives sont plus compliquées.
David Arno

@DavidArno Il serait plus logique de dire que la convention suit la spécification du langage.
Marquis de Lorne le

5

Si la méthode principale n'est pas statique, vous devrez créer un objet de votre classe principale depuis l'extérieur du programme. Comment voudriez-vous faire ça?


5

Lorsque vous exécutez la machine virtuelle Java (JVM) avec la javacommande,

java ClassName argument1 argument2 ...

Lorsque vous exécutez votre application, vous spécifiez son nom de classe comme argument de la commande java, comme ci-dessus

la JVM tente d'appeler la méthode principale de la classe que vous spécifiez

- à ce stade, aucun objet de la classe n'a été créé.

Déclarer mainstatique allowsla JVM pour créer un invokeprincipal de la classe.withoutinstance

revenons à la commande

ClassNameest un command-line argumentà la JVM qui lui indique quelle classe exécuter. Après le nom de classe, vous pouvez également spécifier un list of Strings(séparé par des espaces) comme arguments de ligne de commande que la machine virtuelle Java transmettra à votre application. - De tels arguments peuvent être utilisés pour spécifier des options (par exemple, un nom de fichier) pour exécuter l'application - c'est pourquoi il y a un paramètre appelé String[] argsdans le main

Références: Java ™ How To Program (Early Objects), dixième édition


4

Récemment, une question similaire a été publiée sur Programmers.SE

  • Pourquoi une méthode principale statique en Java et C #, plutôt qu'un constructeur?

    À la recherche d'une réponse définitive d'une source primaire ou secondaire pour savoir pourquoi (notamment) Java et C # ont décidé d'avoir une méthode statique comme point d'entrée - plutôt que de représenter une instance d'application par une instance d'une Applicationclasse, le point d'entrée étant un constructeur approprié?

TL; DR une partie de la réponse acceptée est,

À Java, la raison en public static void main(String[] args)est que

  1. Oison voulait
  2. le code écrit par une personne expérimentée en C (pas en Java)
  3. à exécuter par une personne habituée à exécuter PostScript sur NeWS

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

 
Pour C #, le raisonnement est pour ainsi dire transitoirement similaire . Les concepteurs de langage ont gardé la syntaxe du point d'entrée du programme familière aux programmeurs venant de Java. Comme le dit l'architecte C # Anders Hejlsberg ,

... notre approche avec C # a simplement été d'offrir une alternative ... aux programmeurs Java ...

...


3

Je pense que le mot-clé 'statique' fait de la méthode principale une méthode de classe, et les méthodes de classe n'en ont qu'une copie et peuvent être partagées par tous, et aussi, il ne nécessite pas d'objet pour référence. Ainsi, lorsque la classe de pilote est compilée, la méthode principale peut être invoquée. (Je suis juste au niveau alphabétique de java, désolé si je me trompe)


Toutes les méthodes «n'en ont qu'une seule copie».
Marquis de Lorne le

3

main () est statique car; à ce stade du cycle de vie de l'application, la pile d'application est de nature procédurale car aucun objet n'est encore instancié.

C'est une table rase. Votre application est en cours d'exécution à ce stade, même sans qu'aucun objet ne soit déclaré (rappelez-vous, il existe des modèles de codage procéduraux ET OO). En tant que développeur, vous transformez l'application en une solution orientée objet en créant des instances de vos objets et en fonction du code compilé à l'intérieur.

L'orientation objet est idéale pour des millions de raisons évidentes. Cependant, le temps est révolu où la plupart des développeurs VB utilisaient régulièrement des mots clés comme "goto" dans leur code. "goto" est une commande procédurale dans VB qui est remplacée par son homologue OO: invocation de méthode.

Vous pouvez également considérer le point d'entrée statique (principal) comme de la liberté pure. Si Java avait été suffisamment différent pour instancier un objet et vous présenter uniquement cette instance lors de l'exécution, vous n'auriez pas le choix MAIS d'écrire une application procédurale. Aussi inimaginable que cela puisse paraître pour Java, il est possible qu'il existe de nombreux scénarios qui nécessitent des approches procédurales.

C'est probablement une réponse très obscure. N'oubliez pas que "classe" n'est qu'une collection de code interrelié. "Instance" est une génération autonome isolée, vivante et respirante de cette classe.


7
Ceci est une erreur. De nombreux objets sont instanciés avant d' mainêtre atteints. Et si vous incluez un constructeur statique dans la classe contenant main, cela s'exécute avant de la mainmême manière.
Konrad Rudolph

2

Ce n'est qu'une convention. La JVM aurait certainement pu traiter des méthodes principales non statiques si cela avait été la convention. Après tout, vous pouvez définir un initialiseur statique sur votre classe et instancier un zillion d'objets avant d'accéder à votre méthode main ().


2

Le protoype public static void main(String[])est une convention définie dans le JLS :

La méthode main doit être déclarée publique, statique et nulle. Il doit spécifier un paramètre formel (§8.4.1) dont le type déclaré est un tableau de String.

Dans la spécification JVM 5.2. Démarrage de la machine virtuelle, nous pouvons lire:

La machine virtuelle Java démarre en créant une classe initiale, qui est spécifiée de manière dépendante de l'implémentation, à l'aide du chargeur de classe d'amorçage (§5.3.1). La machine virtuelle Java relie ensuite la classe initiale, l'initialise et appelle la méthode de classe publique void main (String []) . L'invocation de cette méthode entraîne toute exécution ultérieure. L'exécution des instructions de machine virtuelle Java constituant la méthode principale peut entraîner la liaison (et par conséquent la création) de classes et d'interfaces supplémentaires, ainsi que l'invocation de méthodes supplémentaires.

Chose amusante, dans la spécification JVM, il n'est pas mentionné que la méthode principale doit être statique. Mais la spécification indique également que la machine virtuelle Java effectue 2 étapes avant:

L'initialisation d'une classe ou d'une interface consiste à exécuter sa méthode d'initialisation de classe ou d'interface.

Dans 2.9. Méthodes spéciales :

Une méthode d'initialisation de classe ou d'interface est définie:

Une classe ou une interface possède au plus une méthode d'initialisation de classe ou d'interface et est initialisée (§5.5) en invoquant cette méthode. La méthode d'initialisation d'une classe ou d'une interface a le nom spécial <clinit>, ne prend aucun argument et est nulle.

Et une méthode d'initialisation de classe ou d'interface est différente d'une méthode d'initialisation d'instance définie comme suit:

Au niveau de la machine virtuelle Java, chaque constructeur écrit dans le langage de programmation Java (JLS §8.8) apparaît comme une méthode d'initialisation d'instance qui porte le nom spécial <init>.

Ainsi, la JVM initialise une méthode d'initialisation de classe ou d'interface et non une méthode d'initialisation d'instance qui est en fait un constructeur. Ils n'ont donc pas besoin de mentionner que la méthode principale doit être statique dans la spécification JVM car elle est impliquée par le fait qu'aucune instance n'est créée avant d'appeler la méthode principale.


2

Le publicmot-clé est un modificateur d'accès, qui permet au programmeur de contrôler la visibilité des membres de la classe. Lorsqu'un membre de classe est précédé de public, ce membre peut être consulté par du code en dehors de la classe dans laquelle il est déclaré.

L'opposé de publicis private, qui empêche un membre d'être utilisé par du code défini en dehors de sa classe.

Dans ce cas, main()doit être déclaré comme public, car il doit être appelé par du code en dehors de sa classe au démarrage du programme.

Le mot-clé staticpermet main()d'être appelé sans avoir à instancier une instance particulière de la classe. Ceci est nécessaire car main()est appelé par l'interpréteur Java avant la création d'objets.

Le mot-clé voidindique simplement au compilateur qui main()ne renvoie pas de valeur.


1

Le véritable point d'entrée de toute application est une méthode statique. Si le langage Java supportait une méthode d'instance comme "point d'entrée", alors le runtime aurait besoin de l'implémenter en interne en tant que méthode statique qui a construit une instance de l'objet suivie par l'appel de la méthode d'instance.

Avec cela à l'écart, j'examinerai la justification du choix d'une des trois options suivantes:

  1. Un static void main()tel que nous le voyons aujourd'hui.
  2. Une méthode d'instance void main()appelée sur un objet fraîchement construit.
  3. Utiliser le constructeur d'un type comme point d'entrée (par exemple, si la classe d'entrée était appelée Program, alors l'exécution consisterait effectivement en new Program()).

Panne:

static void main()

  1. Appelle le constructeur statique de la classe englobante.
  2. Appelle la méthode statique main().

void main()

  1. Appelle le constructeur statique de la classe englobante.
  2. Construit une instance de la classe englobante en appelant efficacement new ClassName() .
  3. Appelle la méthode d'instance main().

new ClassName()

  1. Appelle le constructeur statique de la classe englobante.
  2. Construit une instance de la classe (puis ne fait rien avec elle et retourne simplement).

Raisonnement:

Je vais aller dans l'ordre inverse pour celui-ci.

Gardez à l'esprit que l'un des objectifs de conception de Java était de mettre l'accent (exiger si possible) de bonnes pratiques de programmation orientée objet. Dans ce contexte, le constructeur d'un objet initialise l'objet, mais ne doit pas être responsable du comportement de l'objet. Par conséquent, une spécification qui a donné un point d'entrée denew ClassName() perturberait la situation des nouveaux développeurs Java en forçant une exception à la conception d'un constructeur "idéal" sur chaque application.

En créant main()une méthode d'instance, le problème ci-dessus est certainement résolu. Cependant, cela crée de la complexité en exigeant que la spécification répertorie la signature du constructeur de la classe d'entrée ainsi que la signature de la main()méthode.

En résumé, spécifier un static void main()crée une spécification avec le moins de complexité tout en respectant le principe de placement du comportement dans les méthodes . Considérant à quel point il est simple d'implémenter une main()méthode qui elle-même construit une instance d'une classe et appelle une méthode d'instance, il n'y a aucun avantage réel à spécifier main()comme méthode d'instance.


1
Ceci ne fait que lancer la question. Java a de toute façon besoin d'un chargeur d'application qui fait de gros efforts avant d'appeler main. Votre raison d' mainêtre trop complexe pour les débutants semble incroyable. En fait, la statique mainest très déroutante pour les débutants, je doute qu'un constructeur le soit davantage. Vous dites qu'un «constructeur ne devrait pas être responsable du comportement de l'objet». Cela semble intéressant, mais je ne suis pas sûr d'être d'accord. Pourquoi pas? Qu'est-ce qui empêche cela?
Konrad Rudolph

1

static - Lorsque la JVM appelle la méthode principale, il n'y a aucun objet qui existe pour la classe appelée, elle doit donc avoir une méthode statique pour permettre l'invocation de la classe.


1

Je ne sais pas si la JVM appelle la méthode principale avant que les objets ne soient instanciés ... Mais il y a une raison beaucoup plus puissante pour laquelle la méthode main () est statique ... Quand JVM appelle la méthode principale de la classe (disons , La personne). il l'invoque par " Person.main () ". Vous voyez, la JVM l'invoque par le nom de la classe. C'est pourquoi la méthode main () est censée être statique et publique pour être accessible à la JVM.

J'espère que cela a aidé. Si c'est le cas, faites-le moi savoir en commentant.


0

Les méthodes statiques ne nécessitent aucun objet. Il s'exécute directement donc le principal s'exécute directement.


0

Le mot clé statique dans la méthode principale est utilisé car aucune instanciation n'a lieu dans la méthode principale. Mais l'objet est construit plutôt que l'invocation. Par conséquent, nous utilisons le mot clé statique dans la méthode principale. Dans le contexte jvm, la mémoire est créée lorsque la classe s'y charge et tous les membres statiques sont présents dans cette mémoire. si nous faisons la statique principale maintenant, elle sera en mémoire et peut être accessible à jvm (class.main (..)) afin que nous puissions appeler la méthode main sans avoir besoin de créer un tas.


0

C'est juste une convention comme nous pouvons le voir ici:

La méthode doit être déclarée publique et statique , elle ne doit renvoyer aucune valeur et elle doit accepter un tableau String comme paramètre. Par défaut, le premier argument sans option est le nom de la classe à appeler. Un nom de classe complet doit être utilisé. Si l'option -jar est spécifiée, le premier argument sans option est le nom d'une archive JAR contenant des fichiers de classe et de ressources pour l'application, la classe de démarrage étant indiquée par l'en-tête du manifeste de la classe principale.

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


Règle de la langue, tu veux dire.
Marquis de Lorne le

0

Les mots-clés public static void signifient que l'interpréteur de la machine virtuelle Java (JVM) peut appeler la méthode principale du programme pour démarrer le programme (public) sans créer d'instance de la classe (statique), et le programme ne renvoie pas de données à l'interpréteur Java VM (nul) à la fin.

Source: Essentials, Partie 1, Leçon 2: Création d'applications


0

Fondamentalement, nous rendons ces MEMBRES DE DONNÉES et FONCTIONS DE MEMBRE STATIQUES qui n'exécutent aucune tâche liée à un objet. Et dans le cas de la méthode principale, nous le faisons en tant que STATIQUE car cela n'a rien à voir avec l'objet, car la méthode principale fonctionne toujours, que nous créons ou non un objet.


0

Toute méthode déclarée comme statique en Java appartient à la classe elle-même. Encore une fois, la méthode statique d'une classe particulière n'est accessible qu'en se référant à la classe commeClass_name.method_name();

Il n'est donc pas nécessaire d'instancier une classe avant d'accéder à une méthode statique.

Ainsi, la méthode main () est déclarée comme staticétant accessible sans créer un objet de cette classe.

Puisque nous enregistrons le programme avec le nom de la classe où la méthode principale est présente (ou d'où le programme devrait commencer son exécution, applicable pour les classes sans main()méthode () (niveau avancé)). Donc, par la manière mentionnée ci-dessus:

Class_name.method_name();

la méthode principale est accessible.

En bref, lorsque le programme est compilé, il recherche la main()méthode ayant des Stringarguments comme: main(String args[])dans la classe mentionnée (c'est-à-dire par le nom du programme), et puisqu'au début il n'a pas de portée pour instancier cette classe, donc le main () est déclarée comme statique.


Cela se produit lorsque le programme est exécuté et non compilé.
Marquis de Lorne

0

De java.sun.com (il y a plus d'informations sur le site):

La méthode principale est statique pour donner à l'interpréteur Java VM un moyen de démarrer la classe sans créer d'abord une instance de la classe de contrôle. Les instances de la classe de contrôle sont créées dans la méthode principale après le démarrage du programme.

Ma compréhension a toujours été simplement que la méthode principale, comme toute méthode statique, peut être appelée sans créer d'instance de la classe associée, ce qui lui permet de s'exécuter avant toute autre chose dans le programme. S'il n'était pas statique, vous devriez instancier un objet avant de l'appeler - ce qui crée un problème de `` poulet et œuf '', car la méthode principale est généralement ce que vous utilisez pour instancier des objets au début du programme.


Mais il ne fonctionne pas «avant toute autre chose dans le programme». Tout l'argument est une erreur, et de plus, ce n'est pas la première réponse qui le mentionne, ni même la deuxième ou la troisième.
Konrad Rudolph

Je suis désolé que ma réponse répète ce que les autres ont dit; Je n'ai répondu qu'au mieux de ma compréhension et d'après ce que j'ai pu trouver en ligne. D'après les résultats que j'ai examinés, il n'y a aucune autre raison pour laquelle la méthode principale est statique; à moins qu'il n'y en ait un profondément caché quelque part, c'est peut-être la seule réponse. Ma compréhension de Java est assez basique, mais j'ai entendu la raison ci-dessus (de professeurs, manuels, etc.) et jamais aucune autre.
Jesse M

@Jesse M Votre commentaire n'a de sens que si vous n'avez même pas envisagé de lire les autres réponses en premier. Ce qui d'ailleurs n'est pas une chose farfelue à faire. Comme vous l'avez mentionné vous-même, votre compréhension est assez basique, il est donc très probable que quelqu'un d'autre ait déjà répondu à la question avec plus de compétence. Et votre commentaire semble être une rationalisation afin de rendre votre réponse plus belle. C'est une affirmation extraordinaire que vous avez des manuels et des professeurs Java qui pensent ce que vous prétendez et franchement, je ne pense pas qu'ils le fassent. (Des références?)
LeoR

1
@KonradRudolph Les meilleurs commentaires semblent assez raisonnables. main () est utilisé comme point d'entrée pour le programme et il y a plusieurs références sur le site Web Java disant qu'il est censé être similaire à la façon dont C / C ++ a une fonction main (). Parce que Java est tous les objets, il doit être statique pour éviter l'instanciation d'objet. Le rendre statique permet également de le charger et de l'exécuter dans la JVM au moment de l'exécution. Je régurgite simplement les réponses précédentes, mais je me demande ce que vous considéreriez comme une réponse satisfaisante. Je pense que le meilleur que vous obtiendrez est "C'est comme ça qu'ils le voulaient". Gardez à l'esprit la date de création de Java.
trevor-e

1
@Jesse Spot-on. Il est tout à fait possible que ce soit simplement une question de convention (bien que j'espère que non, ce serait une réponse si ennuyeuse). Mon intérêt initial pour cette question était parce que je pensais que l'utilisation d'une instance appropriée pour représenter l'objet «application en cours d'exécution» et que le point d'entrée soit une méthode (ou le constructeur) de cette classe serait une conception beaucoup plus évidente, car Java a été conçu pour être orienté objet de la get-go, et comme des objets apparemment analogues (fils, via Runnable) en Java faire utiliser cette conception. Pourquoi l'exception (apparente) ici?
Konrad Rudolph
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.