/**
POGL : programmation objet et génie logiciel
Champs d'instance, champs de classe.
@author Thibaut Balabonski @ Université Paris-Sud
@version 21 janvier 2019
*/
/**
Les attributs d'une classe définissent les états possibles des instances
de cette classe : chaque instance (c'est-à-dire chaque objet) a ses propres
valeurs pour chaque attribut, qui peuvent évoluer indépendamment des valeurs
des mêmes attributs pour les autres instances.
À l'inverse de ce comportement de référence, il existe des attributs dits
'attributs de classe' qui ne sont pas liés à un objet mais directement à
une classe, avec une valeur unique. Ces attributs sont qualifiés par le
mot-clé [static].
Ainsi, dans l'exemple suivant, un attribut de classe [instanceCount] est
attaché à la classe [Count], et compte le nombre d'instances qui ont été
créées.
*/
class Count {
// Déclaration d'un attribut de classe, initialisé à [0]
private static int instanceCount = 0;
public Count() {
// La valeur de l'attribut est incrémentée à chaque utilisation
// du constructeur
instanceCount++;
}
// Exemple : la valeur de [instanceCount] est partagée, et les
// modifications sont visibles sur toutes les instances
public static void main(String[] args) {
Count c0 = new Count();
System.out.println(c0.instanceCount); // Affiche 1
Count c1 = new Count();
System.out.println(c1.instanceCount); // Affiche 2
Count c2 = new Count();
System.out.println(c2.instanceCount); // Affiche 3
System.out.println(c1.instanceCount); // Affiche 3
System.out.println(c0.instanceCount); // Affiche 3
}
}
/**
Un attribut de classe n'étant pas lié à un objet particulier, on peut y
accéder ou le modifier à partir de n'importe quelle instance de la classe,
ou à partir de la classe elle-même avec une construction de la forme
NomClasse . nomAttribut
*/
class Acc {
private static int value = 0;
public static void main(String[] args) {
Acc a0 = new Acc();
Acc a1 = new Acc();
a0.value = 5;
System.out.println(a1.value); // Affiche 5
a1.value += 2;
System.out.println(Acc.value); // Affiche 7
Acc.value += 3;
System.out.println(a0.value); // Affiche 10
}
}
/**
La notion de champ de classe s'applique également aux méthodes. Pour
comprendre ce qui signifie pour une méthode de "ne pas être rattachée à un
objet", il faut se rappeler que tous les appels de méthodes vus jusqu'ici
avaient la forme
obj . m ( p1, ..., pn )
avec [obj] une instance particulière appelée "paramètre implicite", dont on
peut manipuler les attributs dans le corps de la méthode en y accédant avec
une construction de la forme
this . a
(Java autorise également à laisser [this] implicite en écrivant juste [a]).
Une méthode de classe se différencie d'une méthode d'instance en ce qu'elle
n'a pas de paramètre implicite. En particulier, il n'est pas possible de
faire référence à [this] dans le corps de la méthode, que ce soit
explicitement ou implicitement. Une méthode d'instance ne peut accéder qu'aux
attributs de classe, et aux attributs d'instances d'objets auxquels elle a
accès par ailleurs.
*/
class LimitedEdition {
// Un attribut de classe comptant le nombre d'instances créées
private static int nb = 0;
// Un attribut de classe fixant un nombre maximal d'instances
private static final int MAX = 10;
// Un attribut d'instance enregistrant le numéro de chaque instance
private final int id;
/**
Note : le qualificatif [final], appliqué à un attribut, indique que
l'attribut est "immuable", c'est-à-dire que sa valeur ne peut pas être
modifiée. Un tel attribut reçoit une fois une valeur, soit par défaut
comme [MAX] soit à la construction comme [id], et cette valeur est
définitive.
*/
// Constructeur qui incrémente le compteur et initialise l'attribut [id].
public LimitedEdition() {
assert LimitedEdition.nb < LimitedEdition.MAX;
this.id = ++LimitedEdition.nb;
}
// Une méthode ordinaire (méthode d'instance) peut accéder à [this] et
// aux attributs de classe
public void printId() {
System.out.println("Instance " + this.id + " sur " + LimitedEdition.nb);
}
// Une méthode de classe ne peut accéder qu'aux attributs de classe
public static void printTotal() {
System.out.println(nb + " sur " + LimitedEdition.MAX);
}
// De même que [this] peut être laissé implicite pour les attributs
// d'instance, le nom de la classe peut être laissé implicite pour les
// attributs de classe de la classe courante, ce qui est fait pour [id]
// dans la méthode précédente.
// Une méthode de classe peut accéder en revanche aux attributs de classe
// des instances qui lui sont fournies
public static void printInstance(LimitedEdition le) {
System.out.println("Instance " + le.id + " sur " + LimitedEdition.nb);
}
// Au fait, les méthodes de classe vous connaissiez déjà.
public static void main(String[] args) {
LimitedEdition le1 = new LimitedEdition();
LimitedEdition le2 = new LimitedEdition();
LimitedEdition.printTotal(); // Affiche 2 sur 10
le1.printId(); // Affiche 1 sur 2
LimitedEdition.printInstance(le1); // Affiche 1 sur 2
le1.printInstance(le2); // Affiche 2 sur 2
}
}