
Ce que tout programmeur doit savoir sur le modificateur static en Java : Méthode statique. Classe statique.
Dans cette section, nous examinons les principaux aspects de l'utilisation des méthodes, champs et classes static en Java. Commençons par les variables.Tu ne peux PAS accéder aux membres non static d'une classe dans un contexte static, comme une méthode ou un bloc static. La compilation du code ci-dessous générera une erreur :
public class Counter { private int count; public static void main(String args []) { System.out.println(count); // Erreur au moment de la compilation } }
C'est une des erreurs les plus courantes commises par les programmeurs Java, en particulier les débutants. Comme la méthode main est static et que la variable counter ne l'est pas, utiliser la méthode println au sein de la méthode main produira une « erreur au moment de la compilation ».
Contrairement aux variables locales, les champs et méthodes static ne sont PAS thread-safe en Java. Dans la pratique, c'est une des causes les plus fréquentes de problèmes de sécurité dans la programmation multithread. Comme chaque instance d'une classe fait référence à la même copie d'une variable static, une telle variable doit être protégée ou « verrouillée » par la classe. Par conséquent, lors de l'utilisation des variables static, tu dois t'assurer qu'elles sont correctement synchronisées pour éviter des problèmes tels que les conditions de concurrence.
Les méthodes static ont un avantage pratique en cela qu'il n'y a pas besoin de créer un nouvel objet chaque fois que tu veux les appeler. Une méthode static peut être appelée en utilisant le nom de la classe qui la déclare. Voilà pourquoi ces méthodes sont parfaites pour les méthodes de fabrique et utilitaires. La classe java.lang.Math en est un merveilleux exemple : presque toutes ses méthodes sont static. Les classes utilitaires de Java sont marquées final, pour une raison quelconque.
Un autre point important est que tu ne peux pas remplacer (@Overridesous-classe, c'est-à-dire une méthode avec le même nom et la même signature, tu ne fais que « cacher » la méthode de la superclasse au lieu de la remplacer. Ce phénomène est connu sous le nom de masquage de méthode. Cela signifie que si une méthode static est déclarée à la fois dans la classe parent et la classe enfant, la méthode appelée sera toujours celle du type de la variable au moment de la compilation. Contrairement à ce qui arrive avec le remplacement de méthode, ces méthodes ne seront pas exécutées lors de l'exécution du programme. Prenons un exemple :
class Vehicle { public static void kmToMiles(int km) { System.out.println("Intérieur de la classe parent/méthode static"); } } class Car extends Vehicle { public static void kmToMiles(int km) { System.out.println("Intérieur de la classe enfant/méthode static"); } } public class Demo { public static void main(String args []) { Vehicle v = new Car(); v.kmToMiles(10); } }
Sortie de la console :
Intérieur de la classe parent/méthode static
Le code démontre clairement que, malgré le fait que l'objet est de type Car, c'est la méthode static de la classe Vehicle qui est appelée, car la méthode a été appelée au moment de la compilation. Et note qu'il n'y a pas eu d'erreurs de compilation !
Par ailleurs, en plus des classes de haut niveau, tu peux déclarer des classes static dans d'autres classes. Ces classes sont appelées classes static imbriquées. Elles sont utiles pour assurer une meilleure cohésion. Un exemple frappant d'une classe static imbriquée est HashMap.Entry, qui est une structure de données à l'intérieur d'une HashMap. Il est intéressant de noter que, comme les classes internes, les classes static imbriquées sont déclarées dans des fichiers .class séparés. Ainsi, si tu déclares cinq classes imbriquées dans ta classe principale, tu auras 6 fichiers avec l'extension .class. Un autre exemple est la déclaration de notre Comparator en tant que comparateur d'âge (AgeComparator) dans la classe Employee.
Le modificateur static peut également être utilisé dans un bloc d'initialisation static, plus connu sous le simple nom de « bloc static », qui est exécuté lorsque la classe est chargée. Si tu ne déclares pas un tel bloc, Java rassemble tous les champs static dans une même liste et les initialise lorsque la classe est chargée. Un bloc static ne peut PAS lever d'exceptions vérifiées, mais il peut lever des exceptions non vérifiées. Dans ce cas, une ExceptionInInitializerError se produira. Dans la pratique, toute exception qui se produit lors de l'initialisation des champs static sera enveloppée dans cette erreur en Java. C'est aussi la cause la plus commune de NoClassDefFoundError, car la classe ne sera pas en mémoire quand elle sera référencée.
Il est utile de savoir que les méthodes static sont liées au moment de la compilation, contrairement à ce qui se passe avec les méthodes virtual ou non static, qui sont liées au moment de l'exécution lorsqu'elles sont appelées sur un objet spécifique. Par conséquent, les méthodes static ne peuvent pas être remplacées en Java, car le polymorphisme ne les concerne pas au moment de l'exécution. C'est une limitation importante à prendre en compte lors de la déclaration d'une méthode static. Cela n'a de sens que lorsqu'il n'y a pas de capacité ou de besoin de remplacer la méthode dans une sous-classe. Les méthodes de fabrique et les méthodes utilitaires sont de bons exemples d'utilisation correcte du modificateur static. Joshua Bloch souligne plusieurs avantages que les méthodes de fabrique statiques ont par rapport aux constructeurs dans son livre Java efficace, une lecture incontournable pour tous les programmeurs Java.
L'initialisation est un aspect important d'un bloc static. Les champs ou variables static sont initialisés après que la classe est chargée en mémoire. L'ordre d'initialisation est de haut en bas, dans le même ordre de déclaration que dans le fichier source de la classe Java. Comme les champs static sont initialisés de manière thread-safe, ce processus est également utilisé pour implémenter le modèle de Singleton. Si tu n'utilises pas Enum comme Singleton pour une raison quelconque, tu disposes ainsi d'une bonne alternative. Mais dans ce cas, tu dois tenir compte du fait que ce n'est pas une initialisation « paresseuse ». Cela signifie que le champ static sera initialisé même AVANT que quelqu'un le « demande ». Si un objet est lourd en ressources ou rarement utilisé, l'initialiser dans un bloc static ne jouera pas en ta faveur.
Au cours de la sérialisation, les champs static, comme les variables transient, ne sont pas sérialisés. Toutes les données enregistrées dans un champ static contiendront la valeur initiale (par défaut) après la désérialisation. Par exemple, si un champ static est un int, sa valeur sera égale à zéro après la désérialisation. Si son type est float, la valeur sera 0.0. Si le champ est un Object, la valeur sera null. Pour tout te dire, c'est une des questions les plus fréquemment posées au sujet de la sérialisation dans les entretiens pour des postes de développeur Java. Ne stockez pas de données d'objet essentielles dans un champ static !
Enfin, nous allons parler de l'importation static. Cette utilisation du modificateur static est une variante de l'instruction import standard. Elle est différente en cela qu'elle te permet d'importer un ou tous les membres static de la classe. Une fois que les méthodes static sont importées, elles peuvent être consultées comme si elles avaient été déclarées dans la même classe. De même, en important des champs static, on peut y accéder sans préciser le nom de la classe. Cette fonctionnalité est apparue avec Java 1.5 et améliore la lisibilité du code lorsqu'elle est utilisée correctement. Cette construction se trouve le plus souvent dans les tests JUnit, car presque tous les développeurs de tests utilisent l'importation static pour les méthodes assert, par exemple assertEquals(), et leurs variantes surchargées.
Ce sera tout pour cette fois. Tout programmeur Java se doit de connaître tous les aspects du modificateur static mentionné ci-dessus. Cet article a passé en revue les informations de base sur les variables, champs, méthodes, blocs d'initialisation et importations static. Il a également évoqué certaines propriétés importantes qui sont essentielles à savoir pour écrire et comprendre les programmes Java. J'espère que chaque développeur perfectionnera son utilisation des membres static, car c'est un aspect très important pour le développement sérieux de logiciels. »
Cet article est également disponible en anglais: |
---|
Read the English version of this article to become an expert on Java’s static keyword. It points out some of the nuances of static Java classes and static Java methods. |

GO TO FULL VERSION