Le mot-clé static ou les attributs et méthodes de classe en POO

Décembre 2016



(NOTE: Cet article explique la signification du mot-clé static au sein d'une classe. La signification de "static" en C n'a par exemple rien à voir.)

Vous êtes débutant en programmation orientée objet. En Java, en C++...ou que sais-je encore, vous êtes tombé sur le mot "static". Et vous ne savez pas bien pourquoi. Vous ne savez pas bien comment. Vous ne savez pas bien d'où... Mais pourtant il existe.

Voici donc un petit éclaircissement.



Le gâteau et la recette


Attributs d'instance


Nous sommes samedi après-midi, et ce soir vous recevez des amis. Vous avez la riche idée, pour le dessert, de leur préparer un gâteau.
Mais le problème, c'est que vous ne savez pas bien comment faire. Les desserts c'est pas votre truc.
Vous décidez alors de créer un gâteau : le plimpandard.
Vous ouvrez vos placards et votre frigo, et tout ce que vous trouvez, c'est ça:
  • Du beurre
  • Des œufs
  • De la farine
  • Du sucre
  • Des carottes

Vous avez que ça, mais alors vous en avez plein!
Ça vous laisse de quoi essayer. Mouais pourquoi pas. Au pire, on essaiera avec des dosages différents au fur et à mesure des essais.

3 heures plus tard

C'est le troisième plimpandard que vous essayez de faire. Il y en a un qui est tout plat. Il y en a un qui a brûlé, et un autre qui était pas mal mais vous l'avez mangé parce que vous aviez trop faim.

Il faut en refaire un.

Marre, vous êtes un geek, pas un pâtissier et là vous avez envie de programmer, pas de faire des gâteaux.
Mais vous vous dites que vous pourriez joindre l'utile à l'agréable.

Pourquoi ne pas modéliser votre recette en Java pour faire des statistiques : dans quel cas il est trop plat, dans quel cas il est trop amer etc...

Alors où est le gâteau, où est la recette?
La recette, c'est ce qui est constant, ce qui est commun à tous vos plimpandards. C'est-à-dire le fait qu'il y a du beurre, de la farine, des carottes etc....

Le plimpandard, quant à lui, est variable et on peut en faire pleins. Il seront tous différents.

Alors vous vous dites que la recette est une classe et que les gâteaux produits à partir de cette recette sont les instances de cette classe : les objets.

Alors voilà ce que ça donne:
class Gateau
{
    public int farine;
    public int sucre;
    public int oeufs;
    public int beurre;
    public int carotte;

    public Gateau(int farine, int sucre, int oeufs, int beurre, int carotte)
    {
        this.farine = farine;
        this.sucre = sucre;
        this.oeufs = oeufs;
        this.beurre = beurre;
        this.carotte = carotte;
    }

    public void cuire()
    {
         ....
    }
};

Notez que ces variables seront propres à chaque plimpandard que vous ferez. Le dosage de farine de l'un ne sera pas forcément le même qu'un autre. Et si vous remettez du sucre un peu plus tard avant la cuisson, ce changement ne se répercutera que sur le plimpandard sur lequel vous aurez rajouté de la farine, pas sur les autres.

Exemple:
//On créer deux plimpandards
Gateau a = new Gateau(100, 200, 3, 120, 4);
Gateau b = new Gateau(100, 200, 1, 120, 5);

a.farine = 400; //On met une bonne pâtée de farine

System.out.println(a.farine); // Affichera 400
System.out.println(b.farine); // Affichera 100

Comme vous pouvez le voir, le changement dans a ne s'est pas répercuté dans b.

C'est ce qu'on appelle une variable d'instance, ou attribut d'instance.
Il est propre à un seul objet, chaque objet possède son propre exemplaire.

Attributs de classe


Vous lâchez votre code deux secondes, et touché par la grâce, vous refaites un plimpandard, complètement réussi cette fois.
Vous l'adorez, ce gâteau. Du coup, vous vous dites que vous aimeriez bien que les gens sachent comment il s'appelle. Mais vous êtes conscient que les langues changent avec le temps, les noms aussi. Si votre gâteau a du succès, il y a fort à parier que la recette ira jusqu'en Ardèche en 2030, et que les gens voudront l'appeler le "métatron".

Vous faites face à un nouveau problème : vous voudriez une variable "nom" qui ait la même valeur pour tous vos gâteaux. Vous voudriez que si ce nom est changé, le changement se répercute sur tous les gâteaux.

L'idéal franchement, ce serait d'inscrire ce nom sur la recette et vous laisseriez n'importe qui donner le nom qu'il veut à ce gâteau.

Imaginons : je créer deux plimpandards, je vis en Ardèche et nous sommes en 2030. Vous placez un gâteau dans le salon, un autre dans la cuisine. Vous vous dites que Plimpandard c'est vraiment un nom ridicule, vous barrez le nom sur la recette et vous l'appelez "Métatron".
Quelqu'un arrive dans la cuisine et se demande ce que vous préparez. Il regarde la recette et voit "Métatron". Il s'exclame : un "Métatron, ça l'air bon, ça sent super bon la carotte !!".

Il va dans le salon et il s'exclame de nouveau : "Wah un autre métatron, génial !!".
Le pari est gagné, le changement s'est répercuté sur tous les gâteaux de la recette.

Un autre exemple, libérez votre recette sur internet : changez le nom plimpandard en métatron. Tous les gens qui verront la recette sauront que ça s'appelle un métatron. Les gâteaux qu'ils feront à partir de cette recette, ils l'appelleront toujours métatron.

Maintenant si vous n'aviez pas changé ça sur la recette mais sur le gâteau (en gravant son nom avec un couteau par exemple), le changement se répercutera sur ce gâteau là, mais pas sur les autres qui garderont le nom plimpandard.

Ce genre de variable, commune à toutes les instances d'une classe, et partagée par toutes les instances d'une classe s'appelle une variable de classe, ou attribut de classe.
Pour définir ce genre de variable, on utilise le mot-clé "static".
Pour y accéder, on utilise le nom de la classe suivi d'un point puis du nom de l'attribut.
Ça fonctionne aussi en utilisant le nom de l'objet suivi d'un point puis de l'attribut.

Exemple:
class Gateau
{
    public static String nom;

    public int farine;
    public int sucre;
    public int oeufs;
    public int beurre;
    public int carotte;

    public Gateau(int farine, int sucre, int oeufs, int beurre, int carotte)
    {
        this.farine = farine;
        this.sucre = sucre;
        this.oeufs = oeufs;
        this.beurre = beurre;
        this.carotte = carotte;
    }

    public void cuire()
    {
         ....
    }
};

Gateau.nom = "Plimpandard";

Gateau a = new Gateau(100, 200, 3, 120, 4);
Gateau b = new Gateau(100, 200, 1, 120, 5);

System.out.println(a.nom); //affiche "Plimpandard"

a.nom = "Metatron";
System.out.println(b.nom); //Affiche "Métatron"

Comme vous pouvez le voir ici, le changement dans a s'est répercuté dans b.

Le robot faiseur de Plimpandard


Les méthodes de classe


C'est bien beau tout ça, mais vous avez grandi et vous avez commercialisé votre recette, ça a fait un tabac ce Plimpandard ! Et vous avez même engagé des ingénieurs pour améliorer la recette.
Ils ont remarqué que les jours de pleine lune, les plimpadards étaient un peu fades et avaient besoin d'un peu plus de carottes. Sans compter que ça permettait aux gens d'avoir un meilleur teint sous la lumière blanche de la lune. C'était un bon coup de pub et les gens étaient heureux d'avoir un joli teint grâce au Plimpandard.

Alors vous avez commercialisé un robot intelligent capable de produire des plimpandards avec des dosages de carottes dépendants du cycle lunaire.
Il suffit de lui mettre plein d'œufs, de beurre, de farine, de carotte dans un petit réservoir et il est capable de vous produire votre gâteau avec le parfait dosage pour magnifier votre teint.

En l'utilisant chez lui, un petit jeune mordu de Java décide de faire des statistiques sur les dosages du robot en fonction de la lune.
Les gâteaux sont des objets, pas de problème, mais il se dit que le robot contient la recette, et qu'en plus de ça il est capable de doser en fonction de la lune. Il remarque aussi que le robot possède un compteur qui montre combien de gâteaux il a créé dans sa vie.

Alors il se dit : le robot est la classe puisqu'il est aussi la recette, mais en plus de ça il compte le nombre de gâteaux qu'il produit : on a une variable statique car ce nombre sera inscrit dans le robot (la recette) et en plus il est capable de produire des gâteaux. On va alors utiliser une méthode statique. C'est-à-dire une méthode qui se trouve dans une classe et qui peut être utilisée par tout le monde.

Notez que le robot se comporte comme une recette, la seule différence, c'est que c'est une recette capable de faire elle-même des gâteaux et qui le fait de manière intelligente.

Voilà ce que ça donne:
class Gateau
{
    public static String nom;
    public static nbGateauCree = 0;

    public int farine;
    public int sucre;
    public int oeufs;
    public int beurre;
    public int carotte;

    public static Gateau creeGateau(boolean pleineLune)
    {
         Geateau ret;

         if (pleineLune)
             ret = new Gateau(100, 200, 3, 120, 1000);
         else
             ret = new Gateau(100, 200, 3, 120, 500);

         nbGateauCree++;
         return ret;
    }

    private Gateau(int farine, int sucre, int oeufs, int beurre, int carotte)
    {
        this.farine = farine;
        this.sucre = sucre;
        this.oeufs = oeufs;
        this.beurre = beurre;
        this.carotte = carotte;
    }

    public void cuire()
    {
         ....
    }
};

//On créer un gâteau de pleine lune
Gateau a = Gateau.creeGateau(true);

//On créer un gâteau durant une lune en croissant
Gateau b = Gateau.creeGateau(false);

System.out.println(b.nbGateauCree); //Affiche 2

On remarque plusieurs choses ici. D'abord le constructeur est privé. Effectivement avec ce robot, on ne peut plus créer soi-même de plimpandard avec le dosage que l'on veut. C'est le robot qui décide.
Donc vous n'avez pas accès au constructeur par vous-même. Mais le robot, lui, a le droit. Effectivement une méthode statique fait partie d'une classe et a accès à tout.

Ce que ne peuvent pas faire les méthodes statiques


Voici ce que ne peut pas faire une méthode statique:
static void machin()
{
    thic.c = this.a + this.b;
    .....
}

Ceci est faux, nous sommes dans un contexte de classe et non pas d'objet (d'instance).
Imaginons que vous ayez la recette de votre gâteau sur internet. En utilisant un formulaire, vous pouvez changer le nom du gâteau dans la recette.
Si vous essayez ceci:
static void changeNom(String nom)
{
    this.nom = nom;
}

Ceci est faux, le mot this représente l'objet courant, c'est à dire un gâteau quelconque créé à partir de la recette. Or vous n'êtes pas dans un gâteau particulier, vous êtes dans la recette. Comment la recette peut-elle savoir à quel gâteau vous faites référence? Il y a eu plus de mille gâteaux créés à partir de cette recette.
Le mot-clé this est tout simplement interdit dans une méthode statique.

A voir également :

Ce document intitulé «  Le mot-clé static ou les attributs et méthodes de classe en POO  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.