Programmation objet, notions de base
Objectifs du chapitre
-
Développer en Java des applications en programmation objet.
-
Utiliser les notions de classe, de membres (propriétés, méthodes).
-
Instancier des objets.
-
Utiliser l’encapsulation.
-
Utiliser des diagrammes de classes UML pour concevoir et représenter les classes.
Classe, propriétés, référence, instanciation
1. Classe Point
La classe Point possède deux propriétés x et y de type int. La classe Point et ses propriétés x et y sont précédées du mot-clé public. Elles seront utilisables dans n’importe quelle autre classe.
public class Point
{
public int x;
public int y;
}
2. Représentation UML de la classe Point
UML (Unified Modeling Language) est un langage de modélisation graphique à base de pictogrammes. Le schéma ci-dessous est une représentation de la classe Point en UML :
-
Le rectangle du haut contient le nom de la classe.
-
Celui du milieu contient les propriétés de la classe. Le + indique que la propriété x est publique. Le : est suivi du type de la propriété.
-
Le rectangle du bas contient les méthodes de la classe. Dans ce premier exemple, il n’y en a pas.
3. Utilisation de la classe Point
a. Classe principale
TestPoint est la classe "principale" de l’application, celle qui possède la méthode main().
public class TestPoint
{
public static void main(String argv[])
{
Point p;
p = new Point();
System.out.println("Référence...
Encapsulation
1. Le mot-clé private
L’encapsulation consiste à affecter le mot-clé private aux propriétés de la classe.
public class Point
{
private int x;
private int y;
}
On le note sur le diagramme UML en faisant précéder chaque propriété du signe -.
Une propriété privée n’est utilisable qu’à l’intérieur de sa classe.
Le compilateur s’en rend compte immédiatement en indiquant une erreur à chaque utilisation de x et y dans la classe TestPoint :
L’encapsulation, bien que très simple à mettre en œuvre, est une notion fondamentale de la programmation objet. C’est un guide très efficace pour programmer correctement, et placer les traitements dans la classe appropriée, comme nous allons le constater sur notre exemple.
Enlever le mot-clé private d’une propriété pour satisfaire le compilateur est une mauvaise idée. C’est en général le symptôme d’une mauvaise conception. Par défaut, dans tout l’ouvrage, les propriétés sont déclarées private.
2. Méthodes d’instance
a. Classe principale
La méthode main() de la classe TestPoint ne peut accéder aux propriétés de la classe Point car elles sont déclarées en private. Pour accéder à des propriétés private d’un objet Point, il faut passer par des méthodes public de la classe Point.
La méthode afficheXY() affiche...
Travail pratique : classe Employe
1. Objectif
Appliquer les notions étudiées :
-
Classe.
-
Propriétés.
-
Méthodes.
-
Instances, objets.
2. Sujet
La classe principale de l’application est fournie :
public class TestEmploye
{
public static void main(String argv[])
{
Employe e;
String nom;
int matricule;
e = new Employe();
e.afficheEmploye();
System.out.print("\nAprès changement de nom :\n");
nom = "VAUTOUR FAUVE";
e.setNom(nom);
e.afficheEmploye();
System.out.print("\nAprès changement de matricule :\n");
matricule = 17;
e.setMatricule(matricule);
e.afficheEmploye();
}
}
L’affichage obtenu à l’exécution est le suivant :
3. Travail
Écrire la classe Employe, qui possède deux propriétés : matricule (int), nom (String).
4. Annexe : la classe String
La classe String est une classe de l’API Java. Elle est très...
Constructeur
1. Classe Point
Lors de l’instanciation d’un objet, une méthode particulière appelée constructeur est systématiquement appelée.
Cette méthode porte le nom de la classe (c’est donc la seule dont le nom commence par une majuscule). Elle est non typée (pas de void, ni de type de retour).
Dans la classe Point, nous n’avons pas écrit de constructeur. Dans ce cas, juste après l’instanciation, la machine virtuelle exécute un constructeur par défaut dont le code est :
public Point()
{
}
Cette méthode ne fait rien…
Il est possible d’écrire notre propre constructeur. Ce n’est intéressant que s’il contient du code.
Exemple
On souhaite, dès l’instanciation, initialiser x et y à des valeurs autres que 0. Il est possible d’écrire un constructeur qui reçoit deux paramètres :
public class Point
{
. . .
// --------------------------------------------------------------------
// Constructeur
// --------------------------------------------------------------------
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
. . .
}
2. Classe principale
L’instanciation de deux objets p1 et p2 est faite avec le nouveau...
Surcharge de méthodes - Surdéfinition
1. Classe Point
Le langage Java autorise la surcharge des méthodes. Au sein d’une même classe, il est possible de créer plusieurs méthodes qui portent le même nom. Bien entendu, elles doivent se distinguer pour que la machine virtuelle puisse s’y retrouver et exécuter la bonne ! Elles doivent avoir une liste de paramètres différente (en nombre et/ou en type).
Ce type de surcharge est appelé surdéfinition.
public class Point
{
. . .
public Point()
{
}
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
. . .
public void reinit()
{
this.x = 0;
this.y = 0;
}
public void reinit(int x, int y)
{
this.x = x;
this.y = y;
}
}
La classe Point possède deux constructeurs et deux méthodes nommées reinit().
2. Classe principale
public class TestPoint
{
public static void...
Première approche de l’héritage - Surcharge - Redéfinition
1. L’héritage
Toutes les classes héritent de la classe Object (package java.lang de l’API Java).
Il en est ainsi de la classe Point, ce que schématise le diagramme de classes suivant :
Il s’agit ici d’une hiérarchie simple : en haut, la classe « mère », en bas, la classe « fille » (celle qui hérite).
Par héritage, la classe Point possède, en plus de ses propriétés x et y, toutes les propriétés de la classe Object. Elle possède également toutes les méthodes de la classe object.
Il est possible d’utiliser toutes les méthodes de la classe Object à partir de la référence d’un objet Point. Le programme suivant illustre cette possibilité : la méthode toString() de la classe Object retourne une chaîne de caractères composée du nom de la classe et de la valeur de la référence écrite en hexadécimal, séparés par le caractère @. Sa signature est : public String toString().
public class TestPoint
{
public static void main(String argv[])
{
Point p;
p = new Point(7, 17); ...
Propriétés d’instance, propriétés de classe
1. Déclaration
Les propriétés utilisées dans les exemples précédents sont des propriétés d’instance. Elles sont allouées en mémoire à chaque instanciation (à chaque new). Il y en a autant que d’objets créés.
Il est possible de déclarer des propriétés de classe, allouées en mémoire une et une seule fois dès le lancement de l’exécution du programme. Une propriété de classe est déclarée avec le mot-clé static.
Exemple
public class Point
{
private int x;
private int y;
private static int nombrePoints;
. . .
}
2. Conception
Quand on conçoit une classe, pour chaque propriété, il faut se poser les questions suivantes :
-
Cette propriété est-elle présente une fois par objet ? Si oui, c’est une propriété non static, une propriété d’instance, chaque objet a la sienne. Exemple : les coordonnées x et y d’un point.
-
Cette propriété est-elle unique pour la classe ? Si oui, c’est une propriété static, une propriété de classe. Exemple : le compteur du nombre de points...
Méthodes d’instance, méthodes de classe
Une méthode d’instance est appelée par un objet (une référence d’objet). Exemple : p.afficheXY().
Une méthode d’instance n’est vraiment intéressante que si son résultat varie en fonction de l’objet, donc si elle utilise des propriétés de l’objet. En général, ce sera le cas, même si ce n’est pas obligatoire.
Une méthode de classe est appelée à partir du nom de la classe et ne nécessite pas la création d’un objet. Exemple : Clavier.readString(). Une méthode de classe est déclarée avec le mot-clé static.
Une méthode de classe pouvant être utilisée sans instanciation, il est exclu qu’elle utilise des propriétés d’instance. Une méthode static ne peut utiliser que des propriétés static !
1. Exemple : classe Point
Pour compter le nombre d’objets Point créés, il faut incrémenter le compteur nombrePoints dans chaque constructeur. Une méthode static getNombrePoints() permet de retourner la valeur du compteur.
public class Point
{
private int x;
private int y;
private static int nombrePoints;
public Point()
{...
Constructeurs et méthodes ’private’
Dans tous les exemples précédents, nous avons choisi de déclarer les propriétés private, pour respecter l’encapsulation. Par contre, toutes les méthodes ont été déclarées en public.
Nous respecterons cette conception tout au long de l’ouvrage.
Il peut toutefois être intéressant de déroger à cette règle de façon exceptionnelle. Une méthode peut être déclarée private. Son usage est alors limité aux autres méthodes de la même classe. L’exemple suivant montre l’intérêt de la déclaration d’un constructeur en private.
1. Classe Lapin
Le concepteur de la classe Lapin a décidé de limiter le nombre d’instanciations possibles d’objets Lapin. Pour cela, le constructeur est déclaré en private. Cette déclaration empêche toute instanciation en dehors de la classe Lapin. Pour permettre à une autre classe d’instancier un Lapin, on met à sa disposition une méthode public creerLapin(), à l’intérieur de laquelle s’effectue le contrôle des naissances :
nombre : nombre de lapins créés.
nombreMaxi : nombre maximum de lapins de l’élevage.
public class Lapin
{
private static...
Ramasse-miettes (garbage collector)
L’application suivante crée deux instances de Point. Les références des deux objets sont stockées dans la même référence :
public class TestPoint7
{
public static void main(String argv[])
{
Point p;
p = new Point();
System.out.println("p : " + p);
À cause de la nouvelle instanciation de l’objet p, l’objet précédemment référencé par p n’est plus accessible, car son adresse a été écrasée. L’espace perdu est récupéré automatiquement par le "garbage collector" (ramasse-miettes).
p = new Point();
System.out.println("p : " + p);
}
}
Voici le résultat de l’exécution de ce programme :
Le ramasse-miettes (garbage collector) est un programme qui tourne automatiquement et qui libère la place occupée inutilement.
Travail pratique : classe Employe (deuxième version)
1. Objectif
Il s’agit d’appliquer l’ensemble des notions étudiées :
-
Classe ;
-
Propriétés ;
-
Méthodes ;
-
Instances, objets ;
-
Constructeurs ;
-
Surcharges (surdéfinition) ;
-
toString() (redéfinition).
2. Sujet
La classe principale de l’application est fournie :
import java.io.*;
import utilitairesMG.divers.*;
public class TestEmploye
{
public static void main(String argv[]) throws IOException
{
Employe e1, e2, e3;
String nom;
e1 = new Employe("MERLE");
System.out.println(e1);
e2 = new Employe(12, "COLIBRI");
System.out.println("\n" + e2);
e3 = new Employe("VAUTOUR");
System.out.println("\n" + e3);
System.out.println("\nNombre d'employés créés : " +
Employe.getCompteur());
System.out.println("Prochain matricule automatique : " +
...
Travail pratique : voitures
1. Objectif
Il s’agit de développer plusieurs classes liées entre elles.
2. Sujet
On fournit la classe principale suivante :
public class TestVoiture
{
public static void main(String argv[])
{
Garage g1, g2;
Vendeur vendeur1, vendeur2, vendeur3;
Voiture v1, v2, v3, v4;
// --------------------------------------------------------------------------
// Creation et affichage des garages
// --------------------------------------------------------------------------
System.out.println("LISTE DES GARAGES DE LA MARQUE "
+ Garage.getNomMarque() + "\n");
g1 = new Garage("Avenue des Champs Elysees 75008 PARIS");
g2 = new Garage();
System.out.println(g1);
System.out.println(g2);
// --------------------------------------------------------------------------
// Creation et affichage des vendeurs
// --------------------------------------------------------------------------
vendeur1 = new Vendeur("Oie", "BERNACHE", g1);
vendeur2 = new Vendeur("Aigle", "ROYAL", g2);
vendeur3 = new Vendeur("Balbuzard", "PECHEUR", g1);
System.out.println("\n\nLISTE DES VENDEURS");
System.out.println(vendeur1);
System.out.println(vendeur2);
System.out.println(vendeur3);
// --------------------------------------------------------------------------
// Creation et affichage des voitures :
// --------------------------------------------------------------------------
v1 = new Voiture();
v2 = new Voiture(2004);
v3 = new Voiture(vendeur1);
v4 = new Voiture(3010, vendeur2);
System.out.println("\n\nLISTE...