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 technicien supérieur m'a demandé de réduire le nombre de statiques utilisées. J'ai googlé à peu près de la même façon et je trouve que beaucoup de programmeurs s'opposent assez à l'utilisation de variables statiques.
Je trouve les variables statiques plus pratiques à utiliser. Et je présume qu'elles sont également efficaces (corrigez-moi si je me trompe), car si je devais passer 10 000 appels à une fonction dans une classe, je serais heureux de rendre la méthode statique et d'utiliser une simple fonction Class.methodCall()
d'encombrer la mémoire avec 10 000 instances de la classe, non?
De plus, la statique réduit les interdépendances sur les autres parties du code. Ils peuvent agir en tant que détenteurs d'un état parfait. En ajoutant à cela, je trouve que la statique est largement implémentée dans certaines langues 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: corrigez-moi si mes hypothèses sur la statique sont erronées.
Les variables statiques représentent l'état global. C'est difficile à raisonner et difficile à tester: si je crée une nouvelle instance d'un objet, je peux raisonner de son nouvel état dans les tests. Si j'utilise un code qui utilise des variables statiques, il peut être dans n'importe quel état et tout peut être en train de le modifier.
Je pourrais continuer pendant un bon bout de temps, mais le plus gros concept à considérer est que plus on restreint la portée de quelque chose, plus il est facile de raisonner. Nous pensons bien aux petites choses, mais il est difficile de raisonner sur l’état d’un système à lignes multiples s’il n’ya pas de modularité. Cela s'applique à toutes sortes de choses, d'ailleurs, et pas seulement aux variables statiques.
Il n’est pas très orienté objet: Une des raisons pour lesquelles la statistique peut être considérée par "mal" est qu’elles sont contraires au paradigme orienté objet . En particulier, cela viole le principe selon lequel les données sont encapsulées dans des objets (pouvant être étendus, masquant des informations, etc.). La statique, dans la façon dont vous décrivez les utiliser, 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 s'attend à ce que vous écriviez un "bon code orienté objet" et que vous souhaitiez réellement écrire un "bon code procédural".
Il existe de nombreux gotchyas en Java lorsque vous commencez à utiliser des statistiques qui ne sont pas toujours immédiatement évidentes. Par exemple, si deux copies de votre programme s'exécutent sur la même machine virtuelle, vont-elles indiquer la valeur de la variable statique et perturber l'état de l'autre? Ou que se passe-t-il lorsque vous étendez la classe, pouvez-vous remplacer le membre statique? Est-ce que votre VM manque de mémoire parce que vous avez des nombres de statiques insensés et que la mémoire ne peut pas être récupérée pour d'autres objets d'instance nécessaires?
Durée de vie des objets: De plus, les statiques ont une durée de vie qui correspond à l'exécution entière 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 nettoyée. Si, par exemple, vous avez rendu vos variables non statiques, et dans votre fonction main (), vous avez créé une instance unique de votre classe, puis demandé à votre classe d'exécuter une fonction particulière 10 000 fois, une fois que ces 10 000 appels ont été effectués et que vous supprimez vos références à une seule instance, toutes vos variables statiques peuvent être récupérées et réutilisées.
Empêche certaines utilisations: De plus, les méthodes statiques ne peuvent pas être utilisées pour implémenter une interface, elles peuvent donc empêcher certaines fonctionnalités orientées objet d'être utilisables.
Autres options: Si l’efficacité est votre principale préoccupation, il existe peut-être un meilleur moyen de résoudre le problème de rapidité que de considérer uniquement l’avantage de l’appel étant généralement plus rapide que la création. Déterminez si les modificateurs transitoires ou volatiles sont nécessaires n'importe où. Pour préserver la possibilité d'être en ligne, une méthode peut être marquée comme finale au lieu d'être statique. Les paramètres de méthode et autres variables peuvent être marqués comme finaux 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 au lieu de créer une nouvelle instance à chaque fois. Il peut y avoir des commutateurs d'optimisation de compléteur qui devraient être activés pour l'application en général. La conception devrait peut-être être configurée de sorte que les 10 000 exécutions puissent être multi-threadées et tirer parti des cœurs multi-processeurs. Si la portabilité n’est pas un problème, une méthode native vous permettrait de gagner en rapidité par rapport à vos statistiques.
Si, pour une raison quelconque, vous ne souhaitez pas utiliser plusieurs copies d'un objet, le modèle de conception d'un singleton présente des avantages par rapport aux objets statiques, tels que la sécurité du thread (en supposant que votre singleton est bien codé), ce qui permet une initialisation lente. garantir que l'objet a été correctement initialisé lors de son utilisation, sous-classification, avantages de tester et de refactoriser votre code, sans oublier, si à un moment donné, vous changez d'avis à ne plus vouloir qu'une seule instance d'un objet, il est BEAUCOUP plus facile à supprimer le code pour éviter les instances en double, il est nécessaire de refactoriser tout votre code de variable statique pour utiliser des variables d'instance. J'ai déjà eu à le faire auparavant, ce n'est pas amusant, et vous finissez par éditer beaucoup plus de classes, ce qui augmente le risque d'introduire de nouveaux bogues ... tellement mieux de configurer les choses correctement dès la première fois, même si cela semble avoir des inconvénients. Pour moi, le remaniement nécessaire si vous décidez par la suite que vous avez besoin de plusieurs copies de quelque chose est probablement l'une des raisons les plus convaincantes pour utiliser la statique aussi rarement que possible. Et donc, je ne suis pas non plus d'accord avec votre affirmation selon laquelle la statique réduit les interdépendances. Je pense que vous obtiendrez un 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.
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.
Comme les statiques résident dans un seul espace, tous les threads souhaitant les utiliser doivent passer par un contrôle d’accès que vous devez gérer. Cela signifie que les programmes sont davantage couplés et que ce changement est plus difficile à prévoir et à gérer (comme le dit J Skeet). Cela conduit à des problèmes d'isolement de l'impact du changement et affecte donc la gestion des tests.
Ce sont les deux principaux problèmes que j'ai avec eux.
Les états globaux ne sont pas pervers 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 globaux 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 tenons à comprendre notre sémantique d’application.
Les personnes qui tentent de se débarrasser des États mondiaux pour le gagner se retrouvent inévitablement avec un système beaucoup plus complexe - et les États mondiaux sont toujours là, habilement/stupidement déguisés sous de nombreuses couches de indirections; et nous devons encore raisonner sur les états globaux, après avoir dévoilé toutes les indirections.
Comme le printemps, les gens déclarent somptueusement des états globaux 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 choses à raisonner: l'état dans l'objet et l'état de l'environnement hébergeant l'objet.
Les variables statiques posent deux problèmes principaux:
Si vous utilisez le mot-clé ‘static’ sans le mot-clé ‘final’, cela devrait être un signal vous permettant d’examiner attentivement votre conception. Même la présence d’une ‘finale’ n’est pas un laissez-passer, puisqu’un objet final statique modifiable peut être tout aussi dangereux.
J’estimerais quelque part environ 85% du temps où je vois un ‘statique’ sans un ‘final’, c’est FAUX. Souvent, je trouverai des solutions de contournement étranges pour masquer ou masquer ces problèmes.
Merci de ne pas créer de mutables statiques. Surtout les collections. En général, les collections doivent être initialisées lors de l’initialisation de leur objet conteneur et conçues pour qu’elles soient réinitialisées ou oubliées lors de l’oubli de leur objet conteneur.
L'utilisation de la statique peut créer des bugs très subtils qui vont causer des jours de souffrance aux ingénieurs. Je sais, car j’ai à la fois créé et chassé ces bugs.
Si vous souhaitez plus de détails, veuillez lire la suite…
Pourquoi ne pas utiliser la statique?
La statique pose de nombreux problèmes, notamment l'écriture et l'exécution de tests, ainsi que des bugs subtils qui ne sont pas immédiatement évidents.
Le code qui repose sur des objets statiques ne peut pas être facilement testé par unité, et la statique ne peut pas être facilement fausse (en général).
Si vous utilisez la statique, il n'est pas possible de permuter l'implémentation de la classe afin de tester les composants de niveau supérieur. Par exemple, imaginons un CustomerDAO statique qui retourne les objets du client qu’il charge de la base de données. Maintenant, j'ai une classe CustomerFilter, qui doit accéder à certains objets du client. Si CustomerDAO est statique, je ne peux pas écrire de test pour CustomerFilter sans d'abord initialiser ma base de données et renseigner des informations utiles.
Et la base de données et l’initialisation prennent beaucoup de temps. Et selon mon expérience, la structure d'initialisation de votre base de données changera avec le temps, ce qui signifie que les données vont se transformer et que les tests risquent de se rompre. Imaginons que le client 1 soit un VIP, mais que le cadre d'initialisation de la base de données ait été modifié et que le client 1 ne soit plus un VIP, mais que votre test était codé en dur pour le charger…
Une meilleure approche consiste à instancier un CustomerDAO et à le transférer dans CustomerFilter lors de sa construction. (Une approche encore meilleure serait d’utiliser Spring ou un autre cadre d’inversion de contrôle.
Une fois cette opération effectuée, vous pouvez rapidement simuler ou masquer 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 de la base de données) et plus fiable (car il n’échouera pas lorsque le code d’initialisation de la base de données sera modifié). Par exemple, dans ce cas, le client 1 est et sera toujours un VIP, en ce qui concerne le test.
Exécuter des tests
La statique pose un réel 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 réseau Socket 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 annulé. Désormais, lorsqu'un deuxième test est lancé, il risque de planter lorsqu'il tente de créer un nouveau Socket pour le port 8080, car le port est toujours occupé. Imaginez également que les références de sockets de votre collection statique ne sont pas supprimées et (à l'exception de WeakHashMap) ne sont jamais éligibles pour être récupérées, ce qui provoque une fuite de mémoire.
Ceci est un exemple sur-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 de démarrer et d’arrêter leur logiciel de manière répétée dans la même machine virtuelle, mais c’est un bon test de la conception de votre logiciel. Si vous aspirez à la haute disponibilité, vous devez en prendre conscience.
Ces problèmes surviennent souvent avec les objets de structure, 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 en gèrent probablement beaucoup pour vous, mais si, comme moi, vous utilisez un système hérité, vous pouvez disposer de nombreux 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 l'infrastructure de test unitaire ne supprime pas et ne reconstruit pas les composants, ces modifications ne peuvent pas prendre effet et, lorsqu'un test s'appuie sur ces modifications, elles échoueront. .
Même les composants non-framework sont soumis à ce problème. Imaginez une carte statique appelée OpenOrders. Vous écrivez un test qui crée quelques commandes en cours et vérifiez que tous les éléments sont 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 exact. Exécutés individuellement, ces tests réussissent tous les deux, mais s’ils sont exécutés ensemble dans une suite, ils échouent.
Pire encore, 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 persistance des données sur toutes les instances de test, assurant ainsi une meilleure fiabilité du test. Bugs subtiles .
Si vous travaillez dans un environnement à haute disponibilité, ou si des threads peuvent être démarrés ou arrêtés, le même problème mentionné ci-dessus avec les suites de tests d'unités peut s'appliquer également lorsque votre code est exécuté 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. Ainsi, 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 les données d'une instance du thread qui saigne jusqu'à l'instance suivante.
Quand un thread meurt, un objet statique ne sera ni réinitialisé ni mis au rebut. Imaginez que vous ayez un fil de discussion appelé «EmailCustomers» et qu’il commence à renseigner une collection statique de chaînes avec une liste d’adresses électroniques, puis commence à envoyer un courrier électronique à chacune de ces adresses. Disons que le fil est interrompu ou annulé d'une manière ou d'une autre, de sorte que votre infrastructure de haute disponibilité redémarre le fil. Ensuite, lorsque le thread démarre, il recharge la liste des clients. Mais comme la collection est statique, il peut conserver la liste des adresses électroniques de la collection précédente. Maintenant, certains clients peuvent recevoir des courriels en double.
Un aside: Static Final .
L’utilisation de «statique finale» est en réalité l’équivalent Java d’une définition C #define, bien qu’il existe des différences d’implémentation technique. Un fichier C/C++ #define est extrait du code par le pré-processeur, avant la compilation. Une «finale statique» Java finira par résider en mémoire sur la pile. De cette façon, elle ressemble plus à une variable «statique» en C++ qu’à une #define.
Résumé .
J'espère que cela aide à expliquer quelques raisons fondamentales pour lesquelles la statique est problématique. Si vous utilisez un framework Java moderne tel que Java EE ou Spring, vous ne rencontrerez peut-être pas beaucoup de ces situations, mais si vous travaillez avec une grande quantité de code hérité, elles peuvent devenir beaucoup plus fréquentes.
I hope this helps explain a few basic reasons why statics are problematic up. If you are using a modern Java framework like Java EE or Spring, etc, you may not encounter many of these situations, but if you are working with a large body of legacy code, they can become much more frequent.
Depuis que personne * ne l’a mentionné: concurrency. Les variables statiques peuvent vous surprendre si plusieurs threads lisent et écrivent dans la variable statique. C’est courant dans les applications Web (par exemple, ASP.NET) et cela peut causer des bogues plutôt énervants. Par exemple, si vous avez une variable statique mise à jour par une page et que la page est demandée par deux personnes "presque au même moment", un utilisateur peut obtenir le résultat attendu par l’autre utilisateur, voire pire.
la statique réduit les interdépendances sur les autres parties du code. Ils peuvent agir en tant que détenteurs d'un état parfait
J'espère que vous êtes prêt à utiliser des verrous et à régler les différends.
* En fait, Preet Sangha l’a mentionné.
si je devais passer 10 000 appels à une fonction dans une classe, je serais content de rendre la méthode statique et d’utiliser une méthode simple class.methodCall () dessus au lieu d'encombrer la mémoire avec 10 000 des instances de la classe, non?
Vous devez équilibrer le besoin d'encapsuler des données dans un objet avec un état et le besoin de simplement calculer le résultat d'une fonction sur certaines données.
De plus, la statique réduit les interdépendances sur les autres parties du code.
Il en va de même pour l’encapsulation. Dans les applications de grande taille, la statique a tendance à produire du code spaghetti et ne permet pas facilement de refactoriser ou de tester.
Les autres réponses fournissent également de bonnes raisons contre l'utilisation excessive de la statique.
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 cassent les hypothèses de la programmation orientée objet. En 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 de plusieurs instances, ce qui peut être beaucoup plus difficile à tester. Cela est principalement dû au fait qu’il est plus difficile d’isoler les modifications apportées aux variables statiques dans un seul test.
Cela dit, il est important de faire la 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).
Résumer quelques avantages et inconvénients de base de l’utilisation de méthodes statiques en Java:
Avantages:
Désavantages:
À mon avis, il n’ya pratiquement pas de performance, mais de design. Je ne considère pas que l'utilisation de méthodes statiques soit erronée par rapport à l'utilisation de variables statiques (mais je suppose que vous parlez en fait d'appels de méthodes).
Il s'agit simplement de savoir comment isoler la logique et lui donner une bonne place. Parfois, cela justifie l’utilisation de méthodes statiques dont Java.lang.Math
est un bon exemple. Je pense que lorsque vous nommez la plupart de vos classes XxxUtil
ou Xxxhelper
, vous feriez mieux de reconsidérer votre conception.
Je viens de résumer certains des points soulevés dans les réponses. Si vous trouvez quelque chose qui ne va pas, 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éveloppions un système de gestion de bibliothèque et que nous décidions de mettre le nom du livre sous la forme d'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, nous n'avons pas le 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, sauf si elle est 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 que la conception testable ne soit pas synonyme de bonne conception, nous observerons rarement une bonne conception qui ne soit pas testable. Comme les variables statiques représentent l’état global et qu’il devient très difficile de les tester.
Raisonnement à propos de l'état: Si je crée une nouvelle instance d'une classe, nous pouvons alors raisonner à propos de l'état de cette instance, mais si elle a des variables statiques, elle pourrait être dans n'importe quel état. Pourquoi? Dans la mesure où il est possible que la variable statique ait été modifiée par une instance différente, la variable statique étant partagée par plusieurs instances.
Sérialisation: La sérialisation ne fonctionne pas bien non plus avec eux.
Création et destruction: La création et la destruction de variables statiques ne peuvent pas être contrôlées. Ils sont généralement créés et détruits au moment du chargement et du déchargement du programme. Cela signifie qu'elles sont mauvaises pour la gestion de la mémoire et qu'elles ajoutent également le temps d'initialisation au démarrage.
Mais parfois, nous pouvons en avoir vraiment besoin. Si nous ressentons vraiment le besoin de nombreuses variables statiques partagées dans l’application, une option consiste à utiliser le modèle Singleton Design qui comportera toutes ces variables. Ou nous pouvons créer un objet qui aura ces variables statiques et pourra être transmis.
De plus, si la variable statique est marquée comme finale, elle devient une constante et la valeur qui lui est affectée une fois ne peut pas être modifiée. Cela signifie que cela nous sauvera de tous les problèmes auxquels nous sommes confrontés en raison de sa mutabilité.
On pourrait suggérer que dans la plupart des cas, lorsque vous utilisez une variable statique, vous souhaitez réellement utiliser le modèle singleton pattern .
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 motif singleton devient utile.
Il me semble que vous parlez de variables statiques, mais vous indiquez également des méthodes statiques dans vos exemples.
Les variables statiques ne sont pas diaboliques - elles ont son adoption en tant que variables globales, comme les constantes dans la plupart des cas, combinées avec le modificateur final, mais comme il est dit, ne les abusez pas.
Méthodes statiques aka méthode utilitaire. Ce n’est généralement pas une mauvaise pratique de les utiliser, mais l’objet principal est qu’ils pourraient gêner tester.
En tant qu'exemple d'un excellent projet Java qui utilise beaucoup de statistiques et le fait correctement, veuillez regarder Play! cadre . Il y a aussi discussion à ce sujet dans SO.
Les variables/méthodes statiques combinées avec l'importation statique sont également largement utilisées dans les bibliothèques qui facilitent la programmation déclarative en Java, telles que: make it easy ou Hamcrest . Cela ne serait pas possible sans beaucoup de variables et méthodes statiques.
Donc, les variables statiques (et les méthodes) sont bonnes mais utilisez-les judicieusement!
Les variables statiques posent le plus souvent des problèmes de sécurité des données (tout moment, tout le monde peut changer, accès direct sans objet, etc.)
Pour plus d'informations, lisez this Merci.
Encore une autre raison: la fragilité.
Si vous avez un cours, la plupart des gens s’attendent à pouvoir le créer et à l’utiliser à volonté.
Vous pouvez documenter que ce n'est pas le cas ou vous protéger contre cela (modèle singleton/usine) - mais cela représente un travail supplémentaire, et donc un coût supplémentaire . utilisez votre classe sans faire très attention à tous les commentaires ni à l’usine.
Si vous utilisez beaucoup de variables statiques, cela va casser. Les insectes sont chers.
Entre une amélioration des performances de 0,0001% et une robustesse au changement apportée par des développeurs potentiellement ignorants, dans de nombreux cas, la robustesse est le bon choix.
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 pur mal et donne un code difficile à lire. Scala a bien fait les choses.
La question de «la statique étant diabolique» est davantage une question d’état global. Le moment approprié pour qu'une variable soit statique est si elle n'a jamais plus d'un état; IE des outils qui devraient être accessibles par l'ensemble du cadre et renvoyer toujours les mêmes résultats pour les mêmes appels de méthodes ne sont jamais «pervers» comme les méthodes statiques. En ce qui concerne votre commentaire:
Je trouve les variables statiques plus pratiques à utiliser. Et je présume qu'ils sont efficaces aussi
La statique est le choix idéal et efficace pour les variables/classes qui ne changent jamais.
Le problème de 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'un état global est accessible à plus de plusieurs objets non liés, vos tests unitaires sont incomplets et ne sont pas grainés. Comme mentionné dans cet article à propos de état global et singletons , si les objets A et B ne sont pas liés (comme dans l'un ne fait pas explicitement référence à un autre), alors A ne devrait pas pouvoir affecter l'état de B.
Il existe quelques exceptions à l'état global d'interdiction dans un code correct, tel que l'horloge. Le temps est global et, dans un certain sens, il modifie l'état des objets sans avoir de relation codée.
Je trouve les variables statiques plus pratiques à utiliser. Et je suppose qu'ils sont également efficaces (corrigez-moi si je me trompe), car si je devais passer 10 000 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 la même chose sans avoir à instancier 10 000 objets.
les méthodes statiques peuvent être utilisées, mais uniquement pour les fonctions liées au domaine de l'objet et qui n'ont pas besoin ou n'utilisent pas les propriétés internes de l'objet.
ex:
public class WaterContainer {
private int size;
private int brand;
...etc
public static int convertToGallon(int liters)...
public static int convertToLiters(int gallon)...
}
Mon 0,02 $ est que plusieurs de ces réponses prêtent à confusion, plutôt que de dire "les statistiques sont mauvaises", je pense qu'il est préférable de parler de la portée et des exemples.
Ce que je dirais, c'est qu'une variable statique est une variable "classe" - elle représente une valeur partagée par toutes les instances de cette classe. En règle générale, il devrait également être ciblé de cette façon (protégé ou privé vers la classe et ses instances).
Si vous envisagez d'appliquer un comportement de niveau de classe autour de ce code et de l'exposer à un autre code, un singleton peut être une meilleure solution pour prendre en charge les modifications à venir (comme @Jessica l'a suggéré). En effet, vous pouvez utiliser des interfaces au niveau instance/singleton d'une manière que vous ne pouvez pas utiliser au niveau de la classe - en particulier l'héritage.
Quelques réflexions sur les raisons pour lesquelles 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 simultanéité n'est pas moins dangereuse pour la statique que les méthodes d'instance. C'est toujours l'état qui doit être protégé. Bien sûr, vous pouvez avoir 1000 instances avec une variable d’instance, une et une seule variable statique, mais si le code qui accède n’est écrit ni de manière sécurisée pour les threads, vous êtes toujours foiré - cela risque de prendre un peu plus de temps .
La gestion du cycle de vie est un argument intéressant, mais je pense que c'est un argument 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é à cause de GC.
PS, en termes de Smalltalk, beaucoup de ses dialectes ont des variables de classe, mais dans Smalltalk, les classes sont en fait des instances de Metaclass et sont donc réellement des variables de l’instance de Metaclass. Pourtant, je voudrais appliquer la même règle de base. Si elles sont utilisées pour un état partagé entre instances, alors ok. S'ils prennent en charge la fonctionnalité publique, vous devriez regarder un Singleton. Soupir, Smalltalk me manque ...
Il y a deux questions principales dans votre post.
Premièrement, à propos des variables statiques .. Les variables statiques sont complètement inutiles et son utilisation peut être facilement évitée. En 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 transmettez un objet à une fonction, vous passez un pointeur sur cet objet, vous n’avez donc pas besoin de le faire. Définissez des variables statiques, car vous pouvez passer un pointeur sur l'objet à toute portée ayant besoin de ces informations. Même si cela implique que vous remplissiez votre mémoire avec des pointeurs, cela ne représentera pas nécessairement une performance médiocre, car les systèmes de pagage de mémoire actuels sont optimisés pour le gérer, et ils conservent en mémoire les pages référencées par les pointeurs que vous avez passés au nouveau. portée; l'utilisation de variables statiques peut amener le système à charger la page de 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 à regrouper tout ce contenu statique dans quelques "classes de configuration", afin de garantir que le système place tout cela dans la même page de mémoire.
Deuxièmement, à propos des 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 plus grand (méthode de comparaison typique), cette méthode peut être statique ou non, mais si vous l'appelez, la forme non statique sera plus efficace. puisqu'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 grave, si nous examinons la classe de mathématiques, 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 de définition des nombres, car la plupart d’entre elles sont rarement utilisées et qu’elles seront toutes incluses dans la classe de nombres, ce qui rendra la classe très complexe et consommera énormément de ressources.
En conclusion: Évitez d'utiliser des variables statiques et trouvez le bon équilibre de performance lorsque vous utilisez des méthodes statiques ou non statiques.
PS: Désolé pour mon anglais.
Si vous avez un programme de taille petite à moyenne, où la variable statique Global.foo est utilisée, son appel provient normalement de nulle part - il n'y a pas de chemin, et donc pas de scénario, comment la variable arrive à l'endroit où elle se trouve. est utilisé. Maintenant, comment puis-je savoir qui a défini 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, parce que vous venez d'écrire le code, le problème est invisible, mais si vous essayez de comprendre du code étranger, vous comprendrez.
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 d'usages dans lesquels plus d'une instance de votre programme est utile, mais si cela évolue ou si cela est utile pour d'autres, ils peuvent 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é de manière intensive par de nombreuses personnes sur une longue période de temps peut très bien s’utiliser avec des variables statiques.
tout (peut :) avoir son but, si vous avez un groupe de threads devant partager/mettre en cache des données et aussi toute la mémoire accessible (afin de ne pas diviser en contextes au sein d'une machine virtuelle), la meilleure méthode choix
-> bien sûr, vous pouvez forcer une seule instance, mais pourquoi?
Je trouve certains commentaires dans ce fil diaboliques, pas la statique;)
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 n'êtes pas .
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 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 les valeurs liées à l'instance.
Il y a beaucoup de bonnes réponses ici, en plus,
Mémoire: Les variables statiques sont actives tant que le chargeur de classes est actif [en général jusqu'à ce que VM meurt]], mais cela ne concerne que les objets/références en vrac stockés de manière statique.
Modularisation: Considérons des concepts tels que IOC, dependencyInjection, proxy, etc. Tous sont totalement opposés aux implémentations étroitement couplées/statiques.
Autres inconvénients: sécurité du filetage, testabilité
De mon point de vue, la variable static
devrait être uniquement lecture seule data ou variables créées par convention .
Par exemple, nous avons une interface utilisateur d'un projet et une liste de pays, de langues, de rôles d'utilisateur, etc. Nous disposons également d'une classe pour organiser ces données. nous sommes absolument sûrs que cette application ne fonctionnera pas sans cette liste. La première chose que nous faisons sur init Init vérifie cette liste à la recherche de mises à jour et obtient cette liste de api (si nécessaire). Nous convenons donc que ces données sont "toujours" présentes dans l'application. Il ne s'agit pratiquement que de données lues, nous n'avons donc pas besoin de nous occuper de son état - en pensant à ce cas, nous ne voulons vraiment pas avoir beaucoup d'instances de ces données - ce cas semble un candidat idéal pour être statique .
Pensez que si vous avez une application avec de nombreux utilisateurs et que vous définissez un formulaire statique, chaque utilisateur modifiera également tous les autres formulaires des autres utilisateurs.
Je pense que des utilisations excessives de variables globales avec un mot clé statique conduiront également à une fuite de mémoire à un moment donné dans l'application.