L'équivalent de #define en Java?
Je suis en train d'écrire une bibliothèque, qui a besoin d'avoir un peu de code si une bibliothèque est incluse. Étant donné que ce code est dispersés tout autour de ce projet, ce serait bien si les utilisateurs n'ont pas à commenter/décommenter tout eux-mêmes.
En C, ce serait assez facile avec un #define
dans un en-tête, puis les blocs de code entouré avec #ifdefs
. Bien sûr, Java n'a pas le préprocesseur C...
À préciser - plusieurs bibliothèques externes sera distribué avec le mien. Je ne veux pas avoir à les inclure tous pour minimiser ma taille de l'exécutable. Si un développeur ne comprennent une bibliothèque, j'ai besoin d'être en mesure de l'utiliser, et si non, alors il peut simplement être ignoré.
Quelle est la meilleure façon de le faire en Java?
OriginalL'auteur Justin | 2009-12-21
Vous devez vous connecter pour publier un commentaire.
Comme d'autres l'ont dit, il n'y a pas une telle chose comme #define/#ifdef en Java. Mais en ce qui concerne le problème d'avoir en option des bibliothèques externes, ce qui vous permettrait d'utiliser, le cas échéant, et de ne pas l'utiliser si ce n', à l'aide des classes de proxy peut être une option (si la bibliothèque d'interfaces ne sont pas trop gros).
J'ai dû le faire une fois pour le système Mac OS X d'extensions spécifiques pour AWT/Swing (qui se trouve dans com.apple.eawt.*). Les classes sont, bien sûr, que sur le chemin de classe si l'application est en cours d'exécution sur Mac OS. Pour être en mesure de les utiliser, mais permettent toujours de la même application pour être utilisé sur d'autres plates-formes, j'ai écrit simple des classes proxy, qui vient d'offrir les mêmes méthodes que l'original EAWT classes. En interne, les proxy utilisé une partie de la réflexion afin de déterminer si, en réalité, les classes ont été sur le chemin de classe et permettrait de passer à travers tous les appels de méthode. À l'aide de la java.lang.de réfléchir.Proxy de classe, vous pouvez même créer et de faire passer des objets d'un type défini dans la bibliothèque externe, sans l'avoir disponible au moment de la compilation.
Par exemple, le proxy pour com.apple.eawt.ApplicationListener ressemblait à ceci:
Tout cela n'a de sens que si vous avez juste besoin d'un peu de classes à partir d'une bibliothèque externe, parce que vous avez à faire tout par la réflexion au moment de l'exécution. Pour les grandes bibliothèques, vous avez probablement besoin d'un peu de manière à automatiser la génération de la procuration. Mais alors, si vous êtes vraiment à qui dépend d'un grand bibliothèque externe, vous devez juste besoin d'elle au moment de la compilation.
Commentaire par Peter Lawrey: (Désolé pour le modifier, il est très difficile de mettre le code dans un commentaire)
L'exemple suivant est générique par la méthode de sorte que vous n'avez pas besoin de connaître toutes les modalités. Vous pouvez aussi faire de ce générique en classe si vous avez seulement besoin d'un InvocationHandler classe codé de manière à couvrir tous les cas.
OriginalL'auteur Simon Lehmann
Il n'y a pas moyen de faire ce que vous voulez de dans Java. Vous pourriez prétraiter les fichiers source Java, mais c'est en dehors du champ d'application de Java.
Pouvez-vous pas résumé les différences et ensuite varier la mise en œuvre?
Basé sur vos éclaircissements, il semble que vous pourriez être en mesure de créer une usine méthode qui retourne un objet à partir de l'une des bibliothèques externes ou un "stub" classe dont les fonctions vont faire ce que vous avez fait dans le "non-disponible" code conditionnel.
Le compilateur Java permettra d'optimiser loin conditionnelle des contrôles basés sur des valeurs constantes. Ainsi, il est certainement possible.
Mais encore, elle compile les deux branches. il a juste optimise loin le code inutilisé, non? Aussi, BEAUCOUP de temps, la restructuration de votre architecture pour éliminer ces problèmes peuvent être VRAIMENT salissant. Si vous avez un tas de hasard lieux que vous voulez #ifdefed... vous vous retrouvez avec une classe de base, puis un groupe de sous-classes, avec des fonctions d'aide, et il devient tout simplement un gâchis.
Vous avez une classe, pas de fonctions d'assistance, et un tas de constantes symboliques. Je ne vois pas le besoin de sous-classement quoi que ce soit.
Nous avons besoin de plus de détails pour savoir si une solution existe.
OriginalL'auteur Steve Emmerson
En Java, on pourrait utiliser une variété d'approches pour atteindre le même résultat:
L'Injection De Dépendance
Les Annotations
La réflexion
La Java façon est de mettre un comportement qui varie dans un ensemble de classes distinctes l'une abstraction par une interface, puis branchez la classe requise au moment de l'exécution. Voir aussi:
Modèle de fabrique
Le générateur de modèle
Modèle de stratégie
OriginalL'auteur Vlad Gudim
Bien, la syntaxe Java est assez proche de C que vous pouvez simplement utiliser le préprocesseur C, qui est habituellement expédié comme un exécutable séparé.
Mais Java n'est pas vraiment de faire les choses au moment de la compilation de toute façon. La manière dont j'ai géré des situations analogues est avec la réflexion. Dans ton cas, puisque vos appels à la peut-être-non-présent de la bibliothèque sont dispersés dans tout le code, je voudrais faire une classe wrapper, remplacer tous les appels à la bibliothèque avec les appels à la classe wrapper, et ensuite utiliser la réflexion à l'intérieur de la classe wrapper pour appeler à la bibliothèque, s'il est présent.
OriginalL'auteur JaakkoK
Utiliser un constant:
ce sujet de la compilation conditionnelle? Comment faites-vous cela en java?
L'article que j'ai lié discute de cela.
Comme une note rapide sur l'article lié, l'ensemble de "l'interface pour votre constantes et le mettre en œuvre" est obsolète et ridicule maintenant qu'il est
import static
.Le conditionnel compiler encore ne fonctionne que si le tout se compile. si, lorsque la branche est vrai, la branche else ne compile pas, parce que ces méthodes n'existent pas, ou quelque chose, alors il ne compile pas. #si résout ce bien.
OriginalL'auteur Andrew Hare
Je ne crois pas qu'il y est vraiment une telle chose. La plupart des utilisateurs Java vous diront que c'est une Bonne Chose, et que s'appuyant sur la compilation conditionnelle devrait être évitée à presque tous les frais.
Je ne suis pas vraiment d'accord avec eux...
Vous POUVEZ utiliser des constantes qui peuvent être définies à partir de la ligne de compilation, et qu'ont certains de l'effet, mais pas vraiment tout. (Par exemple, vous ne pouvez pas avoir des choses qui ne compile pas, mais vous voulez toujours, à l'intérieur de #if 0... (et non, les commentaires ne sont pas toujours résoudre ce problème, parce que l'imbrication des commentaires peut être délicat...)).
Je pense que la plupart des gens vous diront d'utiliser une certaine forme d'héritage pour ce faire, mais qui peut être très laid, avec beaucoup de code à répétition...
Cela dit, vous POUVEZ toujours configurer votre IDE de jeter votre java par le pré-processeur avant de l'envoyer à javac...
OriginalL'auteur Brian Postow
"pour minimiser ma taille de l'exécutable"
Qu'entendez-vous par "la taille de l'exécutable"?
Si vous voulez dire la quantité de code chargé lors de l'exécution, puis vous pouvez conditionnellement classes de charge par le chargeur de classe. Si vous distribuez votre code alternatif n'importe quoi, mais c'est seulement chargé si la bibliothèque qu'il représente est manquant. Vous pouvez utiliser un Adaptateur (ou similaire) pour encapsuler l'API, de faire en sorte que presque tout votre code est exactement le même de toute façon, et l'une des deux classes wrapper est chargé en fonction de votre cas. La sécurité de Java SPI peut vous donner quelques idées de la façon dont cela peut être structuré et mis en œuvre.
Si tu parles de la taille de votre .fichier jar, vous pouvez le faire ci-dessus, mais parlez-en à vos développeurs comment dépouiller de l'inutile classes du pot, dans le cas où ils savent qu'ils ne vont pas être nécessaire.
Cela ne veut pas rencontrer les paramètres de votre question initiale. Si vous êtes à la reliant au moment de l'exécution, vous AVEZ toujours avoir le code qui appelle la bibliothèque compilée dans #ifdef n'aidera pas de toute façon. Si vous ne sont pas de liaison au moment de l'exécution, mais la compilation pour des cibles différentes, alors si(CONSTANTE) suffira. Quel est le réel problème?
Non, la constante ne suffira pas. Par exemple,
if(false) {LibraryIDontHave.action();}
ne compilera pas.OriginalL'auteur Steve Jessop
Utilisation des propriétés pour faire ce genre de chose.
Utiliser des choses comme la Classe.forName à identifier la classe.
Ne pas utiliser si relevés, vous pouvez trivialement traduire une propriété directement à une classe.
OriginalL'auteur S.Lott
En fonction de ce que vous faites (pas assez d'informations), vous pourriez faire quelque chose comme ceci:
et de fournir ensuite une classe abstraite de l'instanciation:
Puis exécuter java avec -Dfoo.nom=RealFoo|FakeFoo
Ignoré la gestion des exceptions dans le makeFoo méthode et vous pouvez le faire par d'autres moyens... mais l'idée est la même.
De cette façon, vous compilez les deux versions de l'Foo sous-classes et de permettre au développeur de choisir lors de l'exécution qu'ils souhaitent utiliser.
OriginalL'auteur TofuBeer
Je vous vois en spécifiant deux mutuellement exclusifs problèmes ici (ou, plus probablement, vous avez choisi un, et je suis tout simplement pas comprendre le choix que vous avez fait).
Vous avez un choix à faire: Êtes-vous à l'expédition deux versions de votre code source (si la bibliothèque existe, et si elle ne fonctionne pas), ou êtes-vous de livraison d'une version unique et attend-il pour travailler avec la bibliothèque si la bibliothèque existe.
Si vous ne voulez qu'une seule version pour détecter la bibliothèque de l'existence et de l'utilisation, si disponible, vous DEVEZ avoir tous les codes d'accès dans votre code, vous ne pouvez pas le couper. Puisque vous êtes en assimilant votre problème avec l'aide d'un #define, j'ai supposé que ce n'était pas votre but--vous voulez vous envoyer les 2 versions (La seule façon #define pouvez travailler)
Donc, avec 2 versions, vous pouvez définir un libraryInterface. Cela peut être soit un objet qui encapsule votre bibliothèque et transfère tous les appels à la bibliothèque pour vous ou une interface--dans les deux cas, cet objet DOIT exister au moment de la compilation pour les deux modes.
Maintenant, lorsque vous voulez UTILISER votre bibliothèque (au cas où vous auriez eu un #ifdef dans C), vous avez ceci:
Bibliothèque est une interface qui existe dans les deux cas. Depuis il est toujours protégé par LIBRARY_EXISTS, il va compiler (ne devrait jamais même charger votre chargeur de classe, mais c'est dépendant de l'implémentation).
Si votre bibliothèque est un pré-emballés, bibliothèque fournie par une 3ème partie, vous pourriez avoir à faire de la Bibliothèque une classe wrapper qui transmet les appels à votre bibliothèque. Depuis votre bibliothèque wrapper n'est jamais instanciée si LIBRARY_EXISTS est faux, il ne devrait même pas être chargé au moment de l'exécution (Heck, il ne devrait même pas être compilé en si la JVM est assez intelligent car il est toujours protégé par un final constante.) mais rappelez-vous que l'emballage DOIT être disponible au moment de la compilation dans les deux cas.
OriginalL'auteur Bill K
S'il permet d'avoir un regard sur j2me polonais ou En utilisant les directives de préprocesseur dans BlackBerry JDE plugin pour eclipse?
c'est pour les mobiles app, mais cela peut être réutilisé non ?
OriginalL'auteur RzR
Je n'ai plus la meilleure façon de le dire.
Ce que vous avez besoin est une variable finale.
Puis à l'intérieur du code dire que
Cela ne fonctionne que #ifdef. Un des blocs seront présents dans le code exécutable. D'autres seront éliminés au moment de la compilation elle-même
OriginalL'auteur Vivek MVK