9
votes

Obtenez un bloc d'initialisation statique pour fonctionner dans un Java sans charger la classe

J'ai quelques classes comme indiqué ici ici xxx

... xxx

Comment puis-je modifier TrueFalezVetion classe de sorte que la méthode statique soit toujours exécutée pour que je reçois 1 au lieu de 0 quand je cours ma méthode principale? Je ne veux pas de changement dans la méthode principale.

J'essaie de mettre en œuvre les modèles d'usine où les sous-classes s'inscrivent avec l'usine, mais j'ai simplifié le code de cette question.


0 commentaires

4 Réponses :


6
votes

Vous pouvez appeler:

Class.forName("yourpackage.TrueFalseQuestion");


7 commentaires

Où puis-je appeler cette méthode? Chaque classe est dans un fichier différent.


Avant de réellement besoin du truefalentetion initialisateur à exécuter. Dans votre exemple - au début de la méthode principale


Y a-t-il quelque chose que je puisse y arriver sans changer quoi que ce soit dans la méthode principale, car cela créerait une sorte de dépendance de cette classe dans la méthode principale que je veux éviter.


Dans ce cas, vous n'avez pas de dépendance du temps compilé. Ce n'est qu'une dépendance du temps d'exécution. Selon la façon dont vous êtes "enregistrer" vos sous-classes, vous pouvez faire les chèques appropriés.


Y a-t-il un bon moyen de se débarrasser de la dépendance du temps d'exécution aussi?


@TP: Si vous pouviez énumérer toutes les classes dans un package, vous pouvez simplement interroger tous les noms de ceux de cette implémentation question et faire ceci. Depuis que cela ne peut pas être fait (voir ici: Stackoverflow.com/questions/520328/... ), vous êtes laissé avec examiner des pots à la main (UGH) ou en utilisant une sorte de fichier de configuration ...


@TP c'est exactement comme @martinho Fernandes dit



5
votes

Pour enregistrer la classe truefalentetion avec l'usine, son initialisateur statique doit être appelé. Pour exécuter l'initialiseur statique de la classe TrueFalentetion , la classe doit être référencée ou doit être chargée par réflexion avant questionfactory.map.size () est appelé. Si vous souhaitez quitter la méthode MAIN intacte, vous devez la réfléchir ou le charger par réflexion dans le InitializIzer STATIC STATIC. Je ne pense pas que ce soit une bonne idée, mais je vais juste répondre à votre question :) Si cela ne vous dérange pas du QuestionFactory Connaître toutes les classes qui implémentent Question Pour les construire, vous pouvez simplement les référer directement ou les charger par réflexion. Quelque chose comme: xxx

Assurez-vous que La déclaration S est avant le bloc statique . Si vous ne voulez pas QuestifFactory avoir une connaissance des implémentations de Question , vous devrez les énumérer dans un fichier de configuration qui est chargé par QuestifFactory . La seule autre autre voie (éventuellement folle) que je pouvais penser à le faire, serait de regarder à travers tout la classe de classe pour les classes qui implémentent question :) qui pourrait fonctionner mieux si toutes les classes qui ont mis en œuvre la question devait appartenir au même paquet - Remarque: je n'entraîne pas cette solution;)

La raison pour laquelle je ne pense pas faire de cela dans le QuestionFactory Initializer statique est parce que les classes comme truefalentetion ont leur propre initialisateur statique qui appelle dans questionnaire , qui à ce stade est un objet incomplètement construit, qui demande simplement des problèmes. Avoir un fichier de configuration qui répertorie simplement les classes que vous souhaitez QuestionFactory Pour savoir construire, puis les enregistrer dans son constructeur est une solution fine, mais cela signifie changer votre Main Méthode.


2 commentaires

Pour référence, cette conception est venue à éviter le besoin de l'usine de savoir sur les classes de questions (ici: Stackoverflow.com/Questtions/2582357/... ).


Je n'avais pas vu cette question. Quelque chose doit savoir sur les implémentations de l'interface de la question, qu'il s'agisse de l'usine directement ou d'une sorte de fichier de configuration. Comme je l'ai dit, le seul autre moyen est de passer à travers toutes les classes de la classe de classe et de voir s'ils mettent en œuvre la question. Notez également la mise en garde d'avoir une usine incomplètement construite dans ma réponse ci-dessus. Cela peut fonctionner maintenant, mais il n'y a aucune garantie sur l'état de l'objet à l'avenir (ni même dans le présent, à travers les plates-formes).



4
votes

L'initialiseur statique pour la classe ne peut pas être exécuté si la classe n'est jamais chargée.

Vous devez donc charger toutes les classes appropriées (ce qui sera difficile, car vous ne les connaissez pas tous à la compilation. temps) ou se débarrasser de l'exigence de l'initialisateur statique.

Une façon de faire ce dernier est d'utiliser le ServiceLoader .

avec le serveur vous simplement Mettez un fichier dans Meta-Inf / Services / Package.Question et énumérez toutes les implémentations. Vous pouvez avoir plusieurs fichiers de tels fichiers, un fichier par .jar. De cette façon, vous pouvez facilement expédier des implémentations supplémentaires séparément de votre programme principal.

dans le QuestionFactory Vous pouvez simplement utiliser serviceLodaer.load (Question.Class) Pour obtenir un ServiceLoader , qui implémente itérable et peut être utilisé comme ceci: xxx < / pré>


0 commentaires

2
votes

Pour exécuter les initialiseurs statiques, les classes doivent être chargées. Pour que cela se produise, votre classe "principale" doit dépendre (directement ou indirectement) sur les classes, soit directement ou indirectement les amener à être chargée de manière dynamique; par exemple. Utilisation de classe.forname (...) .

Je pense que vous essayez d'éviter les dépendances intégrées dans votre code source . Les dépendances statiques sont donc inacceptables et appelles à class.forname (...) avec des noms de classe codée dur sont également inacceptables.

Cela vous laisse deux alternatives:

  • Écrivez du code désordonné pour itérer sur les noms de ressources dans certains packages, puis utilisez class.forname (...) pour charger ces ressources qui ressemblent à vos cours. Cette approche est délicate si vous avez une classe de classe compliquée, et impossible si votre parcours de classe effectif comprend un URLClassloader avec une URL distante (par exemple).

  • Créez un fichier (par exemple une ressource de classier) contenant une liste des noms de classe que vous souhaitez charger et écrire un code simple pour lire le fichier et utiliser class.forname (...) charger chacun.


0 commentaires