Je suis un programmeur Java qui est nouveau dans le monde de l'entreprise. Récemment, j'ai développé une application utilisant Groovy et Java. Tout au long du code que j'ai écrit, j'ai utilisé un bon nombre de statistiques. Le lot technique senior m'a demandé de réduire le nombre de statiques utilisées. J'ai googlé à peu près la même chose et je trouve que de nombreux programmeurs sont assez contre l'utilisation de variables statiques.
Je trouve les variables statiques plus pratiques à utiliser. Et je suppose qu'ils sont aussi efficaces (veuillez me corriger si je me trompe), car si je devais faire 10 000 appels à une fonction dans une classe, je serais heureux de rendre la méthode statique et d'utiliser une méthode simple Class.methodCall()
au lieu de encombrant la mémoire avec 10 000 instances de la classe, non?
De plus, la statique réduit les interdépendances avec les autres parties du code. Ils peuvent agir comme des détenteurs d'État parfaits. Ajoutant à cela, je trouve que la statique est largement implémentée dans certains langages comme Smalltalk et Scala . Alors, pourquoi cette oppression pour la statique est-elle répandue chez les programmeurs (en particulier dans le monde de Java)?
PS: veuillez me corriger si mes hypothèses sur la statique sont fausses.
Réponses:
Les variables statiques représentent l'état global. C'est difficile à raisonner et à tester: si je crée une nouvelle instance d'un objet, je peux raisonner sur son nouvel état dans les tests. Si j'utilise du code qui utilise des variables statiques, il pourrait être dans n'importe quel état - et n'importe quoi pourrait le modifier.
Je pourrais continuer pendant un bon moment, mais le plus grand concept auquel penser est que plus la portée de quelque chose est étroite, plus il est facile de raisonner. Nous sommes bons à penser aux petites choses, mais il est difficile de raisonner sur l'état d'un système à un million de lignes s'il n'y a pas de modularité. Cela s'applique à toutes sortes de choses, d'ailleurs - pas seulement aux variables statiques.
la source
Ce n'est pas très orienté objet: une raison pour laquelle la statique peut être considérée comme "mauvaise" par certaines personnes est qu'elle est contraire au paradigme orienté objet . En particulier, il viole le principe selon lequel les données sont encapsulées dans des objets (qui peuvent être étendues, cacher des informations, etc.). La statique, dans la façon dont vous décrivez leur utilisation, consiste essentiellement à les utiliser comme variable globale pour éviter de traiter des problèmes tels que la portée. Cependant, les variables globales sont l'une des caractéristiques déterminantes du paradigme de programmation procédurale ou impérative, et non une caractéristique du "bon" code orienté objet. Cela ne veut pas dire que le paradigme procédural est mauvais, mais j'ai l'impression que votre superviseur attend de vous que vous écriviez du "bon code orienté objet" et que vous vouliez vraiment écrire "
Il existe de nombreux gotchyas en Java lorsque vous commencez à utiliser des statistiques qui ne sont pas toujours immédiatement évidentes. Par exemple, si vous avez deux copies de votre programme en cours d'exécution sur la même machine virtuelle, vont-elles représenter la valeur de la variable statique et gâcher l'état de l'autre? Ou que se passe-t-il lorsque vous étendez la classe, pouvez-vous remplacer le membre statique? Votre machine virtuelle manque de mémoire car vous avez un nombre insensé de statiques et cette mémoire ne peut pas être récupérée pour d'autres objets d'instance nécessaires?
Durée de vie des objets: en outre, les statiques ont une durée de vie qui correspond à la totalité de l'exécution du programme. Cela signifie que, même une fois que vous avez fini d'utiliser votre classe, la mémoire de toutes ces variables statiques ne peut pas être récupérée. Si, par exemple, vous avez rendu vos variables non statiques, et dans votre fonction main (), vous avez créé une seule instance de votre classe, puis demandé à votre classe d'exécuter une fonction particulière 10 000 fois, une fois ces 10 000 appels effectués , et vous supprimez vos références à l'instance unique, toutes vos variables statiques peuvent être récupérées et réutilisées.
Empêche une certaine réutilisation: De plus, les méthodes statiques ne peuvent pas être utilisées pour implémenter une interface, donc les méthodes statiques peuvent empêcher certaines fonctionnalités orientées objet d'être utilisables.
Autres options: Si l'efficacité est votre principale préoccupation, il pourrait y avoir d'autres meilleurs moyens de résoudre le problème de vitesse que de considérer uniquement l'avantage de l'invocation étant généralement plus rapide que la création. Déterminez si les modificateurs transitoires ou volatils sont nécessaires n'importe où. Pour conserver la possibilité d'être aligné, une méthode peut être marquée comme finale au lieu de statique. Les paramètres de méthode et d'autres variables peuvent être marqués comme définitifs pour permettre certaines optimisations du compilateur basées sur des hypothèses sur ce qui peut changer ces variables. Un objet d'instance peut être réutilisé plusieurs fois plutôt que de créer une nouvelle instance à chaque fois. Il peut y avoir des commutateurs d'optimisation du compilateur qui doivent être activés pour l'application en général. Peut-être, la conception devrait être configurée de sorte que les 10 000 exécutions puissent être multi-thread et profiter des cœurs multi-processeurs. Si la portabilité n'est pas
Si, pour une raison quelconque, vous ne voulez pas plusieurs copies d'un objet, le motif de conception singleton, présente des avantages sur les objets statiques, tels que la sécurité des threads (en supposant que votre singleton est bien codé), permettant l'initialisation paresseuse, garantissant que l'objet a été correctement initialisé lors de son utilisation, la sous-classification, les avantages de tester et de refactoriser votre code, sans oublier, si à un moment donné vous changez d'avis de ne vouloir qu'une seule instance d'un objet, il est BEAUCOUP plus facile de supprimer le code pour éviter les instances en double que de refactoriser tout votre code de variable statique pour utiliser des variables d'instance. J'ai dû le faire avant, ce n'est pas amusant, et vous finissez par devoir éditer beaucoup plus de classes, ce qui augmente votre risque d'introduire de nouveaux bugs ... tellement mieux pour mettre les choses en place "correctement" la première fois, même s'il semble avoir ses inconvénients. Pour moi, le retravail requis si vous décidez en cours de route que vous avez besoin de plusieurs copies de quelque chose est probablement l'une des raisons les plus convaincantes d'utiliser la statique aussi rarement que possible. Et donc je serais également en désaccord avec votre affirmation selon laquelle la statique réduit les interdépendances, je pense que vous vous retrouverez avec du code plus couplé si vous avez beaucoup de statistiques accessibles directement, plutôt qu'un objet qui "sait comment faire" quelque chose "sur lui-même.
la source
synchronized
méthodes), cela ne signifie pas que le code appelant est exempt de conditions de concurrence par rapport à l'état singleton.Object Lifetime
, est un point très important mentionné par @jessica.Le mal est un terme subjectif.
Vous ne contrôlez pas la statique en termes de création et de destruction. Ils vivent à la demande du programme de chargement et de déchargement.
Étant donné que les statiques vivent dans un seul espace, tous les threads qui souhaitent les utiliser doivent passer par le contrôle d'accès que vous devez gérer. Cela signifie que les programmes sont plus couplés et que ce changement est plus difficile à envisager et à gérer (comme le dit J Skeet). Cela entraîne des problèmes d'isolement de l'impact du changement et affecte ainsi la gestion des tests.
Ce sont les deux principaux problèmes que j'ai avec eux.
la source
Non. Les États mondiaux ne sont pas mauvais en soi. Mais nous devons voir votre code pour voir si vous l'avez utilisé correctement. Il est tout à fait possible qu'un débutant abuse des États mondiaux; tout comme il abuserait de toutes les fonctionnalités linguistiques.
Les États mondiaux sont une nécessité absolue. Nous ne pouvons pas éviter les États mondiaux. Nous ne pouvons pas éviter de raisonner sur les États mondiaux. - Si nous voulons comprendre notre sémantique d'application.
Les gens qui essaient de se débarrasser des États mondiaux pour le plaisir finissent inévitablement par un système beaucoup plus complexe - et les États mondiaux sont toujours là, habilement / idiotement déguisés sous de nombreuses couches d'indirections; et nous devons encore raisonner sur les états mondiaux, après avoir déballé toutes les indirections.
Comme les gens du printemps qui déclarent somptueusement les états mondiaux en xml et pensent en quelque sorte que c'est supérieur.
@ Jon Skeet
if I create a new instance of an object
vous avez maintenant deux raisons de raisonner - l'état dans l'objet et l'état de l'environnement hébergeant l'objet.la source
Il y a 2 problèmes principaux avec les variables statiques:
la source
Si vous utilisez le mot clé «statique» sans le mot clé «final», cela devrait être un signal pour examiner attentivement votre conception. Même la présence d'un «final» n'est pas un laissez-passer, puisqu'un objet final statique mutable peut être tout aussi dangereux.
J'évaluerais quelque part environ 85% du temps où je vois un «statique» sans un «final», c'est FAUX. Souvent, je trouverai d'étranges solutions de contournement pour masquer ou masquer ces problèmes.
Veuillez ne pas créer de mutables statiques. Surtout les collections. En général, les collections doivent être initialisées lorsque leur objet conteneur est initialisé et doivent être conçues de manière à être réinitialisées ou oubliées lorsque leur objet conteneur est oublié.
L'utilisation de la statique peut créer des bogues très subtils qui causeront des douleurs aux ingénieurs. Je sais, parce que j'ai à la fois créé et chassé ces bugs.
Si vous souhaitez plus de détails, lisez la suite…
Pourquoi ne pas utiliser la statique?
Il existe de nombreux problèmes avec la statique, y compris l'écriture et l'exécution de tests, ainsi que des bogues subtils qui ne sont pas immédiatement évidents.
Le code qui repose sur des objets statiques ne peut pas être facilement testé à l'unité, et les statistiques ne peuvent pas être facilement moquées (généralement).
Si vous utilisez de la statique, il n'est pas possible d'échanger l'implémentation de la classe afin de tester des composants de niveau supérieur. Par exemple, imaginez un CustomerDAO statique qui renvoie les objets Customer qu'il charge à partir de la base de données. J'ai maintenant une classe CustomerFilter, qui doit accéder à certains objets Customer. Si CustomerDAO est statique, je ne peux pas écrire de test pour CustomerFilter sans d'abord initialiser ma base de données et remplir des informations utiles.
Et le remplissage et l'initialisation de la base de données prennent beaucoup de temps. Et d'après mon expérience, votre cadre d'initialisation de base de données changera au fil du temps, ce qui signifie que les données se transformeront et que les tests pourraient se casser. IE, imaginez que le client 1 était un VIP, mais le cadre d'initialisation de la base de données a changé, et maintenant le client 1 n'est plus VIP, mais votre test a été codé en dur pour charger le client 1…
Une meilleure approche consiste à instancier un CustomerDAO et à le passer dans le CustomerFilter lors de sa construction. (Une approche encore meilleure consisterait à utiliser Spring ou un autre cadre d'inversion de contrôle.
Une fois cette opération effectuée, vous pouvez rapidement simuler ou supprimer un autre DAO dans votre CustomerFilterTest, ce qui vous permet d'avoir plus de contrôle sur le test,
Sans le DAO statique, le test sera plus rapide (pas d'initialisation db) et plus fiable (car il n'échouera pas lorsque le code d'initialisation db change). Par exemple, dans ce cas, s'assurer que le client 1 est et sera toujours un VIP, en ce qui concerne le test.
Exécution de tests
La statique pose un vrai problème lors de l'exécution simultanée de suites de tests unitaires (par exemple, avec votre serveur d'intégration continue). Imaginez une carte statique d'objets Socket réseau qui reste ouverte d'un test à l'autre. Le premier test peut ouvrir un socket sur le port 8080, mais vous avez oublié de vider la carte lorsque le test est détruit. Désormais, lorsqu'un deuxième test se lance, il risque de se bloquer lorsqu'il essaie de créer un nouveau socket pour le port 8080, car le port est toujours occupé. Imaginez également que les références de socket dans votre collection statique ne soient pas supprimées et (à l'exception de WeakHashMap) ne soient jamais éligibles pour être récupérées, provoquant une fuite de mémoire.
Il s'agit d'un exemple trop généralisé, mais dans les grands systèmes, ce problème se produit tout le temps. Les gens ne pensent pas aux tests unitaires démarrant et arrêtant leur logiciel à plusieurs reprises dans la même JVM, mais c'est un bon test de la conception de votre logiciel, et si vous avez des aspirations à une haute disponibilité, c'est quelque chose dont vous devez être conscient.
Ces problèmes surviennent souvent avec les objets d'infrastructure, par exemple, vos couches d'accès à la base de données, de mise en cache, de messagerie et de journalisation. Si vous utilisez Java EE ou certains des meilleurs frameworks, ils gèrent probablement beaucoup de cela pour vous, mais si comme moi vous avez affaire à un système hérité, vous pourriez avoir beaucoup de frameworks personnalisés pour accéder à ces couches.
Si la configuration système qui s'applique à ces composants de structure change entre les tests unitaires et que la structure de test unitaire ne détruit pas et ne reconstruit pas les composants, ces modifications ne peuvent pas prendre effet et lorsqu'un test s'appuie sur ces modifications, elles échouent .
Même les composants non-framework sont sujets à ce problème. Imaginez une carte statique appelée OpenOrders. Vous écrivez un test qui crée quelques commandes ouvertes, et vous vérifiez qu'elles sont toutes dans le bon état, puis le test se termine. Un autre développeur écrit un deuxième test qui place les commandes dont il a besoin dans la carte OpenOrders, puis affirme que le nombre de commandes est précis. Exécutés individuellement, ces tests réussiraient tous les deux, mais lorsqu'ils s'exécuteraient ensemble dans une suite, ils échoueraient.
Pire, l'échec peut être basé sur l'ordre dans lequel les tests ont été exécutés.
Dans ce cas, en évitant la statique, vous évitez le risque de persister les données entre les instances de test, garantissant ainsi une meilleure fiabilité des tests.
Bugs subtils
Si vous travaillez dans un environnement à haute disponibilité, ou n'importe où où les threads peuvent être démarrés et arrêtés, le même problème mentionné ci-dessus avec les suites de tests unitaires peut également s'appliquer lorsque votre code s'exécute en production.
Lorsqu'il s'agit de threads, plutôt que d'utiliser un objet statique pour stocker des données, il est préférable d'utiliser un objet initialisé pendant la phase de démarrage du thread. De cette façon, chaque fois que le thread est démarré, une nouvelle instance de l'objet (avec une configuration potentiellement nouvelle) est créée et vous évitez que les données d'une instance du thread ne saignent jusqu'à l'instance suivante.
Lorsqu'un thread meurt, un objet statique n'est pas réinitialisé ni récupéré. Imaginez que vous ayez un thread appelé «EmailCustomers», et quand il démarre, il remplit une collection de chaînes statiques avec une liste d'adresses e-mail, puis commence à envoyer par e-mail chacune des adresses. Supposons que le thread soit interrompu ou annulé d'une manière ou d'une autre, de sorte que votre infrastructure à haute disponibilité redémarre le thread. Ensuite, lorsque le thread démarre, il recharge la liste des clients. Mais comme la collection est statique, elle peut conserver la liste des adresses e-mail de la collection précédente. Maintenant, certains clients peuvent recevoir des e-mails en double.
An Side: finale statique
L'utilisation de «final statique» est effectivement l'équivalent Java d'un C #define, bien qu'il existe des différences de mise en œuvre technique. AC / C ++ #define est échangé hors du code par le pré-processeur, avant la compilation. Une «finale statique» Java terminera la mémoire résidente sur la pile. De cette façon, elle est plus semblable à une variable «const statique» en C ++ qu'à une #define.
Sommaire
J'espère que cela aide à expliquer quelques raisons fondamentales pour lesquelles la statique est problématique. Si vous utilisez un framework Java moderne comme Java EE ou Spring, etc., vous ne rencontrerez peut-être pas beaucoup de ces situations, mais si vous travaillez avec un grand corps de code hérité, elles peuvent devenir beaucoup plus fréquentes.
la source
Puisque personne * ne l'a mentionné: concurrence. Les variables statiques peuvent vous surprendre si plusieurs threads lisent et écrivent dans la variable statique. Ceci est courant dans les applications Web (par exemple, ASP.NET) et il peut provoquer des bogues plutôt exaspérants. Par exemple, si vous avez une variable statique mise à jour par une page et que la page est demandée par deux personnes «presque en même temps», un utilisateur peut obtenir le résultat attendu par l'autre utilisateur, ou pire.
J'espère que vous êtes prêt à utiliser des verrous et à gérer les conflits.
* En fait, Preet Sangha l'a mentionné.
la source
Résumant quelques avantages et inconvénients de base de l'utilisation de méthodes statiques en Java:
Avantages:
Désavantages:
la source
Vous devez équilibrer la nécessité d'encapsuler des données dans un objet avec un état, par rapport à la nécessité de simplement calculer le résultat d'une fonction sur certaines données.
L'encapsulation aussi. Dans les grandes applications, la statique a tendance à produire du code spaghetti et ne permet pas facilement la refactorisation ou le test.
Les autres réponses fournissent également de bonnes raisons contre une utilisation excessive de la statique.
la source
Les variables statiques sont généralement considérées comme mauvaises car elles représentent un état global et sont donc beaucoup plus difficiles à raisonner. En particulier, ils brisent les hypothèses de la programmation orientée objet. Dans la programmation orientée objet, chaque objet a son propre état, représenté par des variables d'instance (non statiques). Les variables statiques représentent l'état entre les instances, ce qui peut être beaucoup plus difficile à tester unitaire. Cela est principalement dû au fait qu'il est plus difficile d'isoler les modifications apportées aux variables statiques à un seul test.
Cela étant dit, il est important de faire une distinction entre les variables statiques régulières (généralement considérées comme mauvaises) et les variables statiques finales (constantes AKA; pas si mal).
la source
À mon avis, il ne s'agit presque jamais de performances, c'est de design. Je ne considère pas l'utilisation de méthodes statiques comme incorrecte par rapport à l'utilisation de variables statiques (mais je suppose que vous parlez en fait d'appels de méthode).
Il s'agit simplement d'isoler la logique et de lui donner une bonne place. Parfois, cela justifie l'utilisation de méthodes statiques, ce qui
java.lang.Math
est un bon exemple. Je pense que lorsque vous nommez la plupart de vos classesXxxUtil
ou queXxxhelper
vous feriez mieux de reconsidérer votre conception.la source
Je viens de résumer certains des points soulevés dans les réponses. Si vous trouvez quelque chose de mal, n'hésitez pas à le corriger.
Mise à l'échelle: nous avons exactement une instance d'une variable statique par machine virtuelle Java. Supposons que nous développons un système de gestion de bibliothèque et nous avons décidé de mettre le nom du livre une variable statique car il n'y en a qu'une par livre. Mais si le système se développe et que nous utilisons plusieurs machines virtuelles Java, nous n'avons pas de moyen de savoir à quel livre nous avons affaire?
Thread-Safety: les variables d'instance et les variables statiques doivent être contrôlées lorsqu'elles sont utilisées dans un environnement multithread. Mais dans le cas d'une variable d'instance, elle n'a pas besoin de protection à moins qu'elle ne soit explicitement partagée entre les threads mais dans le cas d'une variable statique, elle est toujours partagée par tous les threads du processus.
Test: Bien qu'un design testable ne soit pas égal à un bon design, nous observerons rarement un bon design qui n'est pas testable. Comme les variables statiques représentent l'état global et il devient très difficile de les tester.
Raisonnement sur l'état: si je crée une nouvelle instance d'une classe, nous pouvons raisonner sur l'état de cette instance, mais si elle a des variables statiques, elle pourrait être dans n'importe quel état. Pourquoi? Parce qu'il est possible que la variable statique ait été modifiée par une instance différente car la variable statique est partagée entre les instances.
Sérialisation: La sérialisation ne fonctionne pas non plus bien avec eux.
Création et destruction: La création et la destruction de variables statiques ne peuvent pas être contrôlées. Habituellement, ils sont créés et détruits au moment du chargement et du déchargement du programme. Cela signifie qu'ils sont mauvais pour la gestion de la mémoire et ajoutent également le temps d'initialisation au démarrage.
Et si on en avait vraiment besoin?
Mais parfois, nous pouvons en avoir un réel besoin. Si nous ressentons vraiment le besoin de nombreuses variables statiques qui sont partagées à travers l'application, alors une option est d'utiliser le modèle de conception Singleton qui aura toutes ces variables. Ou nous pouvons créer un objet qui aura ces variables statiques et peut être transmis.
De plus, si la variable statique est marquée finale, elle devient une constante et la valeur qui lui est attribuée une fois ne peut pas être modifiée. Cela signifie qu'il nous sauvera de tous les problèmes auxquels nous sommes confrontés en raison de sa mutabilité.
la source
Il me semble que vous posez des questions sur les variables statiques, mais vous indiquez également des méthodes statiques dans vos exemples.
Les variables statiques ne sont pas mauvaises - elles ont leur adoption en tant que variables globales comme des constantes combinées dans la plupart des cas avec le modificateur final, mais comme il l'a dit, ne les abusez pas.
Méthodes statiques ou méthode utilitaire. Ce n'est généralement pas une mauvaise pratique de les utiliser, mais la principale préoccupation est qu'elles pourraient entraver les tests.
Comme exemple d'un grand projet java qui utilise beaucoup de statistiques et le fait correctement, regardez Play! cadre . Il y a aussi une discussion à ce sujet dans SO.
Les variables / méthodes statiques combinées à l'importation statique sont également largement utilisées dans les bibliothèques qui facilitent la programmation déclarative en java comme: le rendre facile ou Hamcrest . Ce ne serait pas possible sans beaucoup de variables et de méthodes statiques.
Les variables statiques (et les méthodes) sont donc bonnes, mais utilisez-les judicieusement!
la source
Les variables statiques créent surtout un problème de sécurité des données (à tout moment modifié, tout le monde peut changer, accès direct sans objet, etc.)
Pour plus d'informations, lisez ces remerciements.
la source
On pourrait suggérer que dans la plupart des cas où vous utilisez une variable statique, vous voulez vraiment utiliser le modèle singleton .
Le problème avec les états globaux est que, parfois, ce qui a du sens comme global dans un contexte plus simple, doit être un peu plus flexible dans un contexte pratique, et c'est là que le modèle singleton devient utile.
la source
Encore une autre raison: la fragilité.
Si vous avez une classe, la plupart des gens s'attendent à pouvoir la créer et l'utiliser à volonté.
Vous pouvez documenter ce n'est pas le cas, ou vous protéger contre cela (modèle singleton / usine) - mais c'est un travail supplémentaire, et donc un coût supplémentaire. Même alors, dans une grande entreprise, il y a des chances que quelqu'un essaie à un moment donné d'utiliser votre classe sans prêter pleinement attention à tous les bons commentaires ou à l'usine.
Si vous utilisez beaucoup de variables statiques, cela se cassera. Les bugs sont chers.
Entre une amélioration des performances de .0001% et une robustesse au changement par des développeurs potentiellement désemparés, dans la plupart des cas, la robustesse est le bon choix.
la source
Je trouve les variables statiques plus pratiques à utiliser. Et je suppose qu'ils sont également efficaces (veuillez me corriger si je me trompe) parce que si je devais faire 10000 appels à une fonction dans une classe, je serais heureux de rendre la méthode statique et d'utiliser une classe simple.methodCall () dessus au lieu d'encombrer la mémoire avec 10 000 instances de la classe, non?
Je vois ce que vous pensez, mais un simple motif Singleton fera de même sans avoir à instancier 10 000 objets.
Des méthodes statiques peuvent être utilisées, mais uniquement pour les fonctions liées au domaine d'objet et qui n'ont pas besoin ou n'utilisent pas les propriétés internes de l'objet.
ex:
la source
Class.Instance
) est à peine meilleur qu'une variable statique. C'est un peu plus testable, mais toujours bien pire que les conceptions où vous créez simplement une seule instance au lieu de construire votre code en supposant qu'il n'y en a qu'une.Class.Instance
) qui porte un état mutable est une mauvaise conception de l'OMI. Dans ce cas, je préfère fortement une conception où j'obtiens les singletons que j'ai besoin d'utiliser passés en paramètre dans la classe qui les utilise (généralement avec l'aide de DI). Les singletons classiques logiquement immuables sont très bien OMI.La question de «la statique étant mauvaise» est davantage une question d'état mondial. Le moment approprié pour qu'une variable soit statique, c'est si elle n'a jamais plus d'un état; Les outils IE qui devraient être accessibles par l'ensemble du framework et toujours renvoyer les mêmes résultats pour les mêmes appels de méthode ne sont jamais «mauvais» que les statiques. Quant à votre commentaire:
La statique est le choix idéal et efficace pour les variables / classes qui ne changent jamais .
Le problème avec l'état global est l'incohérence inhérente qu'il peut créer. La documentation sur les tests unitaires résout souvent ce problème, car chaque fois qu'il existe un état global auquel peuvent accéder plus de plusieurs objets non liés, vos tests unitaires seront incomplets et ne seront pas `` unitaires ''. Comme mentionné dans cet article sur l'état global et les singletons , si les objets A et B ne sont pas liés (comme dans l'un, il n'est pas expressément fait référence à un autre), A ne devrait pas être en mesure d'affecter l'état de B.
Il existe quelques exceptions à l'interdiction de l'état global dans un bon code, comme l'horloge. Le temps est global et, dans un certain sens, il modifie l'état des objets sans avoir de relation codée.
la source
Mon montant de 0,02 $ est que plusieurs de ces réponses confondent le problème, plutôt que de dire "les statiques sont mauvaises". Je pense qu'il vaut mieux parler de la portée et des instances.
Ce que je dirais, c'est qu'une variable statique est une variable de "classe" - elle représente une valeur qui est partagée entre toutes les instances de cette classe. En règle générale, il doit également être défini de cette manière (protégé ou privé pour la classe et ses instances).
Si vous prévoyez de mettre le comportement au niveau de la classe autour de lui et de l'exposer à un autre code, un singleton peut être une meilleure solution pour prendre en charge les modifications à l'avenir (comme l'a suggéré @Jessica). En effet, vous pouvez utiliser des interfaces au niveau instance / singleton d'une manière que vous ne pouvez pas utiliser au niveau classe - en particulier l'héritage.
Quelques réflexions sur la raison pour laquelle je pense que certains aspects des autres réponses ne sont pas au cœur de la question ...
La statique n'est pas "globale". En Java, la portée est contrôlée séparément de statique / instance.
La concurrence n'est pas moins dangereuse pour la statique que les méthodes d'instance. C'est toujours un état qui doit être protégé. Bien sûr, vous pouvez avoir 1000 instances avec une variable d'instance chacune et une seule variable statique, mais si le code accédant à l'une ou l'autre n'est pas écrit de manière sécurisée pour les threads, vous êtes toujours vissé - cela peut prendre un peu plus de temps pour que vous le réalisiez .
La gestion du cycle de vie est un argument intéressant, mais je pense qu'il est moins important. Je ne vois pas pourquoi il est plus difficile de gérer une paire de méthodes de classe comme init () / clear () que la création et la destruction d'une instance singleton. En fait, certains pourraient dire qu'un singleton est un peu plus compliqué en raison de GC.
PS, En termes de Smalltalk, beaucoup de ses dialectes ont des variables de classe, mais dans les classes Smalltalk sont en fait des instances de Metaclass donc ce sont vraiment des variables sur l'instance de Metaclass. Pourtant, j'appliquerais la même règle d'or. S'ils sont utilisés pour un état partagé entre les instances, alors ok. S'ils prennent en charge la fonctionnalité publique, vous devriez regarder un Singleton. Soupir, je manque certainement Smalltalk ....
la source
Il y a deux questions principales dans votre message.
Tout d'abord, sur les variables statiques. Les variables statiques sont complètement inutiles et leur utilisation peut être évitée facilement. Dans les langages OOP en général, et en Java en particulier, les paramètres de fonction sont passés par référence, c'est-à-dire que si vous passez un objet à un funciont, vous passez un pointeur vers l'objet, vous n'avez donc pas besoin de définir de variables statiques puisque vous pouvez passer un pointeur sur l'objet vers n'importe quelle étendue qui a besoin de ces informations. Même si cela implique que vous remplissez votre mémoire de pointeurs, cela ne représentera pas nécessairement une mauvaise performance car les systèmes de pagination de la mémoire réels sont optimisés pour gérer cela, et ils conserveront en mémoire les pages référencées par les pointeurs que vous avez transmis au nouveau portée; l'utilisation de variables statiques peut amener le système à charger la page mémoire où elles sont stockées lorsqu'elles doivent être consultées (cela se produira si la page n'a pas été accédée depuis longtemps). Une bonne pratique consiste à rassembler tous ces éléments statiques dans de petites "classes de configuration", ce qui garantira que le système les mettra tous dans la même page de mémoire.
Deuxièmement, sur les méthodes statiques. Les méthodes statiques ne sont pas si mauvaises, mais elles peuvent rapidement réduire les performances. Par exemple, pensez à une méthode qui compare deux objets d'une classe et renvoie une valeur indiquant lequel des objets est le plus grand (méthode de comparaison typique), cette méthode peut être statique ou non, mais en l'invoquant, la forme non statique sera plus efficace car il ne devra résoudre que deux références (une pour chaque objet) face aux trois références qui devront résoudre la version statique de la même méthode (une pour la classe plus deux, une pour chaque objet). Mais comme je l'ai dit, ce n'est pas si mal, si nous jetons un coup d'œil à la classe Math, nous pouvons trouver beaucoup de fonctions mathématiques définies comme des méthodes statiques. C'est vraiment plus efficace que de mettre toutes ces méthodes dans la classe définissant les nombres,
En conclusion: évitez d'utiliser des variables statiques et trouvez le bon équilibre de performance lorsque vous traitez avec des méthodes statiques ou non statiques.
PS: Désolé pour mon anglais.
la source
Il n'y a rien de mal avec les variables statiques en soi. C'est juste la syntaxe Java qui est cassée. Chaque classe Java définit en fait deux structures: un objet singleton qui encapsule des variables statiques et une instance. Définir les deux dans le même bloc source est un mal absolu et entraîne un code difficile à lire. Scala l'a bien fait.
la source
a) Raison des programmes.
Si vous avez un programme de petite à moyenne taille, où la variable statique Global.foo est accessible, l'appel à celle-ci vient normalement de nulle part - il n'y a pas de chemin, et donc pas de chronologie, comment la variable arrive à l'endroit, où elle est utilisé. Maintenant, comment savoir qui l'a réglé à sa valeur réelle? Comment savoir ce qui se passe si je le modifie maintenant? J'ai grep sur toute la source, pour collecter tous les accès, pour savoir ce qui se passe.
Si vous savez comment vous l'utilisez, car vous venez d'écrire le code, le problème est invisible, mais si vous essayez de comprendre le code étranger, vous comprendrez.
b) En avez-vous vraiment besoin?
Les variables statiques empêchent souvent plusieurs programmes du même type de s'exécuter dans la même machine virtuelle Java avec des valeurs différentes. Souvent, vous ne prévoyez pas les utilisations, où plus d'une instance de votre programme est utile, mais si elle évolue, ou si elle est utile pour d'autres, ils pourraient rencontrer des situations, où ils aimeraient démarrer plus d'une instance de votre programme .
Seul un code plus ou moins inutile qui ne sera pas utilisé par beaucoup de gens sur une longue période de manière intensive pourrait bien aller avec des variables statiques.
la source
tout (peut :) avoir son but, si vous avez un tas de threads qui doivent partager / mettre en cache des données et aussi toute la mémoire accessible (donc vous ne devez pas vous diviser en contextes au sein d'une même machine virtuelle Java), la statique est le meilleur choix
-> bien sûr, vous pouvez forcer juste un exemple, mais pourquoi?
je trouve certains des commentaires dans ce fil mal, pas la statique;)
la source
Les variables statiques ne sont ni bonnes ni mauvaises. Ils représentent des attributs qui décrivent la classe entière et non une instance particulière. Si vous avez besoin d'un compteur pour toutes les instances d'une certaine classe, une variable statique serait le bon endroit pour contenir la valeur.
Des problèmes apparaissent lorsque vous essayez d'utiliser des variables statiques pour conserver des valeurs liées à l'instance.
la source
Toutes les réponses ci-dessus montrent pourquoi la statique est mauvaise. La raison pour laquelle ils sont mauvais, c'est parce que cela donne la fausse impression que vous écrivez du code orienté objet, alors qu'en fait vous ne l'êtes pas. C'est tout simplement mauvais.
la source
Il y a beaucoup de bonnes réponses ici, en y ajoutant,
Mémoire: Les variables statiques sont actives aussi longtemps que le chargeur de classe vit [en général jusqu'à ce que la VM meure], mais ce n'est que dans le cas d'objets en vrac / références stockés en tant que statiques.
Modularisation: considérez des concepts comme IOC, dependencyInjection, proxy, etc. Tous sont complètement contre les implémentations à couplage étroit / statique.
Autres inconvénients: sécurité des filetages, testabilité
la source
Pensez que si vous avez une application avec de nombreux utilisateurs et que vous avez défini un formulaire statique, chaque utilisateur modifiera également tous les autres formulaires des autres utilisateurs.
la source
Je pense que les utilisations excessives de variables globales avec un mot-clé statique entraîneront également une fuite de mémoire à un moment donné de l'applica
la source
De mon point de vue, la
static
variable ne devrait être que des données en lecture seule ou des variables créées par convention .Par exemple, nous avons une interface utilisateur d'un projet, et nous avons une liste de pays, de langues, de rôles d'utilisateurs, etc. Et nous avons une classe pour organiser ces données. nous sommes absolument sûrs que l'application ne fonctionnera pas sans ces listes. donc la première chose que nous faisons sur l'application init est de vérifier cette liste pour les mises à jour et d'obtenir cette liste depuis l'api (si nécessaire). Nous convenons donc que ces données sont "toujours" présentes dans l'application. Il s'agit pratiquement de données en lecture seule, nous n'avons donc pas besoin de prendre soin de son état - en pensant à ce cas, nous ne voulons vraiment pas avoir beaucoup d'instances de ces données - ce cas semble être un candidat parfait pour être statique .
la source
J'ai beaucoup joué avec la statique et puis-je vous donner une réponse légèrement différente - ou peut-être une façon légèrement différente de voir les choses?
Quand j'ai utilisé la statique dans une classe (membres et méthodes tous les deux), j'ai finalement commencé à remarquer que ma classe est en fait deux classes partageant la responsabilité - il y a la partie "statique" qui agit un peu comme un singleton et il y a le non -partie statique (une classe normale). Pour autant que je sache, vous pouvez toujours séparer complètement ces deux classes en sélectionnant simplement toutes les statistiques pour une classe et les non-statiques pour l'autre.
Cela arrivait souvent lorsque j'avais une collection statique à l'intérieur d'une classe contenant des instances de la classe et quelques méthodes statiques pour gérer la collection. Une fois que vous y pensez, il est évident que votre classe ne fait pas "juste une chose", c'est être une collection et faire quelque chose de complètement différent.
Maintenant, remanions un peu le problème: si vous divisez votre classe en une classe où tout est statique et une autre qui n'est qu'une "classe normale" et oubliez la "classe normale", votre question devient alors une classe purement statique vs Singleton qui est abordé en détail ici (et probablement une douzaine d'autres questions).
la source