web-dev-qa-db-fra.com

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

Je cherche 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 un instance d'une classe Application (le point d'entrée étant un constructeur approprié).


Contexte et détails de mes recherches antérieures

Cela a déjà été demandé. Malheureusement, les réponses existantes sont simplement en posant la question . En particulier, les réponses suivantes ne me satisfont pas, car je les juge incorrectes:

  • Il y aurait ambiguïté si le constructeur était surchargé. - En fait, C # (ainsi que C et C++) autorise différentes signatures pour Main donc la même ambiguïté potentielle existe et est traitée.
  • Une méthode static signifie qu'aucun objet ne peut être instancié avant donc l'ordre d'initialisation est clair. - Ceci est juste faux en fait, certains objets sont instanciés avant (par exemple dans un constructeur statique).
  • Ils peuvent donc être invoqués par le runtime sans avoir à instancier un objet parent. - Ce n'est pas du tout une réponse.

Juste pour justifier davantage pourquoi je pense que c'est une question valable et intéressante:

  • De nombreux frameworks utilisent des classes pour représenter les applications et les constructeurs comme points d'entrée. Par exemple, le framework d'application VB.NET utilise une boîte de dialogue principale dédiée (et son constructeur) comme point d'entrée1.

  • Ni Java ni C # techniquement n'ont besoin d'une méthode principale. Eh bien, C # en a besoin d'une pour compiler, mais Java même pas cela. Et dans aucun cas, il n'est nécessaire pour l'exécution. Donc, cela ne semble pas être une restriction technique. Et, comme je l'ai mentionné dans le premier paragraphe, pour une simple convention, il semble étrangement inapproprié avec le principe de conception général de Java et C #.

Pour être clair, il n'y a pas d'inconvénient spécifique à avoir une méthode statique main, c'est juste distinctement impair , ce qui m'a fait me demander s'il y avait une justification technique derrière cela.

Je suis intéressé par une réponse définitive d'une source primaire ou secondaire, pas de simples spéculations.


1 Bien qu'il y ait un rappel (Startup) qui peut l'intercepter.

55
Konrad Rudolph

TL; DR

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

  1. Gosling voulu
  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 on NeWS

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


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

... notre approche avec C # a simplement consisté à offrir une alternative ... aux programmeurs Java ...

Version longue

étendre au-dessus et soutenu par des références ennuyeuses.

Java Terminator Hasta la Vista Baby!

VM Spec, 2.17.1 Démarrage de la machine virtuelle

... La manière dont la classe initiale est spécifiée pour la machine virtuelle Java dépasse le cadre de cette spécification, mais il est typique, dans les environnements hôtes utilisant des lignes de commande, pour le nom complet de la classe à spécifier en tant qu'argument de ligne de commande et les arguments de ligne de commande suivants à utiliser comme chaînes à fournir comme argument de la méthode main. Par exemple, en utilisant le SDK Java 2 de Sun pour Solaris, la ligne de commande

Java Terminator Hasta la Vista Baby!

va démarrer une machine virtuelle Java en appelant la méthode main de la classe Terminator (une classe dans un package sans nom) et en lui passant un tableau contenant les quatre chaînes "Hasta", "la", "Vista" et "Baby!" ...

... voir aussi: Annexe: J'ai besoin de tes vêtements, de tes bottes et de ta moto

  • Mon interprétation:
    exécution destinée à être utilisée comme des scripts typiques dans l'interface de ligne de commande.

pas important

... qui permet d'éviter quelques fausses traces dans notre enquête.

Spécifications VM, 1.2 La machine virtuelle Java

La machine virtuelle Java ne sait rien du langage de programmation Java ...

J'ai remarqué ci-dessus en étudiant le chapitre précédent - 1.1 Histoire que je pensais être utile (mais qui s'est avéré inutile).

  • Mon interprétation:
    L'exécution de est régie par la spécification VM seule, qui
    déclare explicitement que cela n'a rien à voir avec la langue Java
    => OK pour ignorer JLS et tout ce qui concerne la langue Java du tout

Gosling: un compromis entre C et langage de script ...

Sur la base de ce qui précède, j'ai commencé à rechercher sur le Web Historique JVM. N'a pas aidé, trop de déchets dans les résultats.

Ensuite, je me suis souvenu des légendes sur Gosling et j'ai restreint ma recherche à Historique de la JVM de Gosling.

Eureka! Comment les spécifications JVM sont apparues

Dans cette keynote du JVM Languages ​​Summit 2008, James Gosling discute ... de la création de Java, ... d'un compromis entre le langage C et le langage de script ...

  • Mon interprétation:
    déclaration explicite qu'au moment de la création,
    C et les scripts ont été considérés comme les influences les plus importantes.

    Déjà vu clin d'œil aux scripts dans VM Spec 2.17.1,
    Les arguments de la ligne de commande expliquent suffisamment String[] args
    mais static et main ne sont pas encore là, il faut creuser plus loin ...

Remarquez en tapant ceci - connexion C, script et VM Spec 1.2 avec son rien de Java - je me sens comme quelque chose de familier, quelque chose ... orienté objet est lentement décès. Prends ma main et continue de bouger Ne ralentis pas, nous y sommes presque maintenant

Les diapositives des notes d'identification sont disponibles en ligne: 20_Gosling_keynote.pdf , très pratique pour copier des points clés.

 page 3 
 
 La préhistoire de Java 
 * Ce qui a façonné ma pensée 
 
 page 9 
 
 NeWS 
 * Système de fenêtres extensibles en réseau 
 * Un système de fenêtres basé sur des scripts .... 
 PostScript (!!) 
 
 page 16 
 
 Un grand objectif (mais silencieux): 
 Dans quelle mesure pourrais-je me rapprocher d'une sensation de 
 "scripting" ... 
 
 page 19 
 
 Le concept original 
 * Il s'agissait de construire 
 des réseaux de choses, 
 orchestrés par un script 
 langage 
 * (Coques Unix, AppleScript, ...) 
 
 page 20 
 
 Un loup en tenue de mouton 
 * Syntaxe C pour rendre les développeurs 
 Confortables 

A-ha! Regardons de plus près syntaxe C.

L'exemple "bonjour le monde" ...

main()
{
    printf("hello, world\n");
}

... une fonction nommée main est en cours de définition. La fonction main a une fonction particulière dans les programmes C; l'environnement d'exécution appelle la fonction principale pour commencer l'exécution du programme.

... La fonction principale a en fait deux arguments, int argc Et char *argv[], Respectivement, qui peuvent être utilisés pour gérer les arguments de la ligne de commande ...

Sommes-nous en train de nous rapprocher? tu paries. Il vaut également la peine de suivre le lien "principal" de la citation ci-dessus:

la fonction principale est l'endroit où un programme commence son exécution. Il est responsable de l'organisation de haut niveau des fonctionnalités du programme et a généralement accès aux arguments de commande donnés au programme lors de son exécution.

  • Mon interprétation:
    Pour être à l'aise avec le développeur C, le point d'entrée du programme doit être main.
    De plus, comme Java requiert que toute méthode soit en classe, Class.main Est
    le plus près possible: invocation statique, juste le nom de la classe et le point,
    aucun constructeur s'il vous plaît - C ne sait rien de tel.

    Cela vaut également transitoirement s'applique à C #, en tenant compte
    l'idée d'une migration facile vers Java.

Les lecteurs pensant que le point d'entrée de programme familier n'a pas d'importance sont aimablement invités à rechercher et vérifier les questions de débordement de pile où les gars venant de Java SE essaient d'écrire Bonjour tout le monde pour Java ME MIDP. Remarque point d'entrée MIDP n'a ni main ni static.

Conclusion

Sur la base de ce qui précède, je dirais que static, main et String[] args Étaient aux moments de la création de [Java et C # les choix les plus raisonnables pour définir point d'entrée du programme .

Annexe: j'ai besoin de vos vêtements, de vos bottes et de votre moto

Je dois admettre que la lecture de VM Spec 2.17.1 était très amusante.

... la ligne de commande

Java Terminator Hasta la Vista Baby!

va démarrer une machine virtuelle Java en appelant la méthode main de la classe Terminator (une classe dans un package sans nom) et en lui passant un tableau contenant les quatre chaînes "Hasta", "la", "Vista" et "Baby!".

Nous décrivons maintenant les étapes que la machine virtuelle peut prendre pour exécuter Terminator, comme exemple des processus de chargement, de liaison et d'initialisation qui sont décrits plus loin dans les sections suivantes.

La tentative initiale ... découvre que la classe Terminator n'est pas chargée ...

Une fois que Terminator est chargé, il doit être initialisé avant que main puisse être invoqué, et un type (classe ou interface) doit toujours être lié avant d'être initialisé. La liaison (§2.17.3) implique la vérification, la préparation et (éventuellement) la résolution ...

La vérification (§2.17.3) vérifie que la représentation chargée de Terminator est bien formée ...

La résolution (§2.17.3) est le processus de vérification des références symboliques de la classe Terminator...


Références symboliques de Terminator oh ouais.

38
gnat

Cela me semble vaguement abusif. Un constructeur est utilisé pour l'initialisation d'un objet: il configure un objet, qui est ensuite utilisé par le code qui l'a créé.

Si vous placez des fonctionnalités d'utilisation de base à l'intérieur du constructeur et que vous n'utilisez jamais réellement l'objet que le constructeur crée dans du code externe, vous violez les principes de la POO. Fondamentalement, faire quelque chose de vraiment bizarre sans raison apparente.

Pourquoi voudriez-vous faire cela de toute façon?

16
Mason Wheeler

Pour Java je pense que le raisonnement est simple: lors du développement de Java, les développeurs savaient que la plupart des personnes apprenant le langage connaîtraient au préalable le C/C++.

Par conséquent Java ressemble non seulement beaucoup à C/C++ au lieu de dire Smalltalk, mais a également repris les idiosynchrasies de C/C++ (pensez simplement aux littéraux octaux entiers). Puisque c/c ++ utilisent tous deux un méthode principale, faire de même pour Java était logique de ce point de vue.

Je suis presque sûr de me souvenir de bloch ou de quelqu'un qui a dit quelque chose dans ce sens sur la raison pour laquelle ils ont ajouté des littéraux entiers octaux, je vais voir si je peux trouver des sources :)

9
Voo

Eh bien, il existe de nombreuses fonctions principales qui exécutent simplement une boucle infinie. Un constructeur travaillant de cette façon (avec un objet qui ne se construit jamais) est ce qui me semble étrange.

Il y a tellement de choses drôles sur ce concept. Votre logique qui court sur un objet à naître, des objets qui sont nés pour mourir (puisqu'ils font tout leur travail chez le constructeur), ...

Tous ces effets secondaires ne corrompraient-ils pas beaucoup plus le OO wagon qu'un simple public (car il doit être accessible par un inconnu)) statique (car aucune instance n'est nécessaire pour commencer) ) void main (parce que c'est le point d'entrée)?

Pour qu'un point d'entrée de fonction simple et simple existe en Java, public et statique seraient automatiquement requis. Bien qu'étant un méthode statique, cela se résume à ce que nous pouvons nous rapprocher d'une fonction simple pour accomplir ce que nous recherchons: un simple point d'entrée.

Si vous n'allez pas adopter un point d'entrée simple et simple comme point d'entrée. Quelle est la prochaine étape qui ne semble pas étrange en tant que constructeur qui n'est pas censé construire?

6
pepper_chico

Vous pouvez rapidement exécuter des tests autonomes sur une classe, pendant le développement, en collant une main() dans la classe que vous essayez de tester.

3
Graham Borland

À ma connaissance, la raison principale est simple. Sun était une société Unix vendant des machines Unix et Unix est ce pour quoi le C "main (args)" convention pour invoquer un binaire a été conçu.

De plus Java a été explicitement conçu pour être facile à comprendre pour les programmeurs C et C++, il n'y avait donc aucune bonne raison de ne pas simplement se contenter de reprendre la convention C.

L'approche choisie où chaque classe peut avoir une méthode d'invocation est assez flexible, surtout en combinaison avec le Main-Classline dans le fichier MANIFEST.MF dans un pot exécutable.

0
user1249

Vous devez commencer quelque part. Un environnement principal statique est l'environnement d'exécution le plus simple que vous puissiez avoir - aucune instance de quoi que ce soit (en dehors de la JVM et des paramètres de chaîne simples) ne doit être créée - afin qu'il puisse "arriver" avec un minimum de tracas (et une faible probabilité d'une erreur de codage empêchant le démarrage, etc.) et peut faire des choses simples sans beaucoup d'autres configurations.

Fondamentalement, une application de KISS.

[Et, bien sûr, la raison principale est: pourquoi pas?]

0
Daniel R Hicks