next up previous contents index
suivant: 3.2 Méthodes monter: 3. Classes d'objets précédent: 3. Classes d'objets   Table des matières   Index

3.1 Classes et instances, membres et constructeurs

Les classes sont tout d'abord des types. Ainsi, si une classe Point a été définie afin de modéliser les points du plan, il est possible de déclarer un nom dont le type est Point :

  Point p;

Cette déclaration de p, qui ne crée aucun objet, dit simplement que le nom p pourra désormais être employé pour désigner des objets de classe Point (mais pas, par exemple, pour désigner des chaînes de caractères). Les objets sont créés par instanciation, en utilisant l'opérateur new, l'un des constructeurs de la classe, et une liste d'arguments. Par exemple, l'expression new Point(2, 3) permet de créer un objet, instance de la classe Point, de coordonnées $(2,3)$ ; la valeur de cette expression est une référence à l'objet créé et cette valeur est non nulle, c'est-à-dire différente de la valeur null. Après l'affectation

Figure: Création d'un Point et affectation à la variable p.
\begin{figure}\begin{center}
\leavevmode
\fbox{
\epsfig{file=fig/point.eps}
} \end{center} \end{figure}

  p = new Point(2, 3);

le nom p désignera l'objet nouvellement créé (figure [*]). La déclaration d'un nom d'objet peut aussi comporter la création d'un objet ; les définitions suivantes de p et o introduisent ces noms et les initialisent par des références à des objets de la classe Point :

  Point p = new Point(2, 3);
  Point o = new Point();

Un constructeur d'une classe a le même nom que la classe, et une liste de paramètres. Il peut y avoir plusieurs constructeurs, qui sont distingués par le nombre et le type de leurs paramètres. L'opérateur new, appliqué à un constructeur d'une classe, a pour effet de créer un objet, instance de cette classe, et retourne une référence vers cet objet. C'est cette référence qui est affectée, comme valeur initiale, aux noms p et o. Une référence n'est pas un objet, c'est plutôt un numéro d'identification unique, qui est géré de façon interne par la Machine Virtuelle Java, alors que les noms sont choisis et gérés par le programmeur. L'unicité signifie que chaque invocation d'un constructeur retourne une référence à un objet différent. Malgré les apparences, les deux points suivants sont différents, et le test d'égalité p1 == p2 aura pour valeur false :

  Point p1 = new Point(2, 3);
  Point p2 = new Point(2, 3);

Figure: Deux points p1 et p2 ; les deux variables désignent le même point après l'affectation p2 = p1.
\begin{figure}\begin{center}
\leavevmode
\fbox{
\epsfig{file=fig/point2.eps}
} \end{center} \end{figure}

Il est préférable de dire que p « désigne » un point, ou « réfère » à tel point, plutôt que de dire qu'il « est » un point. D'ailleurs, l'opération d'affectation permet de remplacer le point désigné par un autre. Après l'affectation suivante, les deux noms p1 et p2 désigneront le même point, celui référencé par p1 (figure [*]):

  p2 = p1;


3.1.0.0.1 Champs

Définir une classe consiste à définir ses constructeurs ainsi que ses membres. Les membres d'une classe sont des champs, des méthodes (et éventuellement des classes ou interfaces imbriquées). Nous allons définir une classe Point pour les points du plan. Il est naturel de doter cette classe de deux champs3.1 de type double, de nom x et y, qui représentent les coordonnées d'un point. Les champs sont parfois appelés des variables d'instance ou encore des variables d'état, car ils décrivent l'état interne de l'objet (figure [*]). La définition de la classe Point, membre du paquet geometrie, comprendra au moins ces deux champs :

package geometrie;

class Point {
  double x, y;

  // ...
}

Figure: Une instance de Point avec ses deux champs initialisés à zéro.
\begin{figure}\begin{center}
\leavevmode
\fbox{
\epsfig{file=fig/champs.eps}
} \end{center} \end{figure}

Les champs sont d'abord initialisés à la valeur nulle de leur type. Ces valeurs nulles sont 0 pour les types numériques, false pour le type boolean, '\u0000' pour le type char, et null pour les références à des objets (tableaux et instances).

On accède à un champ d'une instance en suffixant le nom d'un objet par le nom du champ ; par exemple, on accède aux champs x et y du point p au moyen des expressions p.x et p.y. C'est une erreur d'accéder à un champ d'un objet qui n'existe pas. Ainsi, l'évaluation de p.x, qui suit une déclaration de p et son initialisation par null, provoque le déclenchement de l'exception NullPointerException :

  Point p = null;
  p.x = 2;                // ERREUR -> NullPointerException

Pour éviter cette erreur, il est souvent nécessaire de commencer par faire le test p != null, avant d'accéder à un champ.


3.1.0.0.2 Constructeurs

Outre ses champs, la définition d'une classe comporte la définition de ses constructeurs, qui portent le même nom que la classe, ont comme les méthodes, une liste de paramètres, mais n'ont pas de type de retour. Quand un constructeur est invoqué au moyen de l'opérateur new, une instance est créée, ce qui signifie qu'une zone de la mémoire lui est attribuée, et les champs de cette instance peuvent alors être initialisés. La définition des constructeurs consiste souvent à spécifier les différents cas d'initialisation utiles. Par exemple, on pourra initialiser les champs d'un point à l'aide d'un couple de coordonnées, ou bien on pourra les initialiser à zéro :

package geometrie;

class Point {
  // ...

  // les deux constructeurs :

  Point() {}

  Point(double x, double y) {
    this.x = x;
    this.y = y;
 }
  // ...
}

Employé dans un constructeur, le nom this réfère à l'instance créée par ce constructeur. Ceci permet en particulier d'employer le nom du champ x comme paramètre du constructeur, dans this.x = x.

Il n'est pas obligatoire de définir des constructeurs. Si l'on n'en définit pas explicitement, le constructeur sans paramètre et de corps vide est toujours défini implicitement : c'est le constructeur par défaut. Par contre, dès que l'on définit un (autre) constructeur, ce constructeur par défaut n'est plus défini implicitement et ne peut donc plus être utilisé. C'est pourquoi, il faut ici définir explicitement le constructeur par défaut, du moins si l'on envisage de l'utiliser.


3.1.0.0.3 Méthodes

Analogues à des fonctions, les méthodes de la classe rassemblent des instructions qui opèrent sur les instances de la classe. On pourra doter la classe Point d'une méthode translater, qui a deux paramètres dx et dy, de type double et qui applique à un point une translation selon le vecteur (dx, dy). On invoque une méthode d'une instance en suffixant le nom d'un objet par le nom de la méthode, suivi par ses arguments entre parenthèses : par exemple, on invoque la méthode translater sur le point p au moyen de l'expression p.translater(1, 1). Dans un langage procédural, on devrait faire figurer le point p comme argument d'une procédure et écrire translater(p, 1, 1). En programmation à objets, on dit parfois que l'on envoie à l'objet p le message translater, avec les arguments 1, 1, selon l'usage consacré par le langage Smalltalk. C'est une erreur d'invoquer une méthode d'un objet qui n'existe pas. Ainsi, l'évaluation de p.translater(1, 2), quand p a été initialisé par null ou n'a pas été initialisé, provoque le déclenchement de l'exception NullPointerException, de la même façon que l'accès à un champ de p :

  Point p = null;
  p.translater(1, 2);   // ERREUR -> NullPointerException

Voici enfin la définition de la classe Point, qui comprend deux champs, deux constructeurs et une méthode :

package geometrie;

class Point {
  double x, y;

  Point() {}

  Point(double x, double y) {
    this.x = x;
    this.y = y;
 }

  void translater(double dx, double dy) {
    this.x = this.x + dx;        // x = x + dx
    this.y = this.y + dy;        // y = y + dy
 }
}


3.1.0.0.4 Publication du type

Si cette classe est destinée à être utilisée dans d'autres applications, on doit la déclarer publique et faire de même pour les membres et les constructeurs que l'on veut rendre utilisables ; par exemple, on peut exporter les deux constructeurs et la méthode translater mais pas les deux champs x et y :

package geometrie;

public class Point {
  double x, y;

  public Point() {}

  public Point(double x, double y) {
    this.x = x;
    this.y = y;
 }

  public void translater(double dx, double dy) {
    this.x = this.x + dx;        // x = x + dx
    this.y = this.y + dy;        // y = y + dy
 }
}

3.1.0.0.5 this

Employé dans une méthode, le nom this réfère à l'instance de la classe à laquelle la méthode sera appliquée : c'est un paramètre implicite de toute méthode d'instance, qui permet d'accéder aux membres de l'instance (par exemple, this.x, this.y et this.translater(...)).

D'autre part, le nom this() peut être employé avec une liste d'arguments, mais seulement en première instruction du corps d'un constructeur, pour invoquer explicitement un autre constructeur de la classe. Par exemple, le constructeur sans argument pourrait être défini à l'aide du constructeur à deux arguments en invoquant this(0,0) :

 Point() {
   this(0, 0);
}


next up previous contents index
suivant: 3.2 Méthodes monter: 3. Classes d'objets précédent: 3. Classes d'objets   Table des matières   Index
Rene' LALEMENT 2001-11-07