V - Java et les objets
Comme nous l'avons déjà dit à plusieurs reprises, Java est un véritable langage orienté objet. Dans
ce chapitre, nous allons tenter de présenter les principaux concepts de la programmation orientée
objet tout en voyant comment ces concepts sont appliqués en Java.
1. Introduction à la POO
La Programmation Orientée Objet (POO) est souvent introduite en la comparant à la
programmation procédurale.
En C, par exemple, quand on conçoit un programme, on le "découpe" en plusieurs modules ou
fonctions ayant chacun un rôle précis. Le but est en effet de décomposer un problème compliqué
(que le programme doit résoudre) en une succession de petits problèmes simples à traiter.
La modularité ainsi introduite est quelque peu artificielle et ne permet pas une réutilisabili aisée
du code produit. C'est pourquoi on s'est intéressé à une autre façon de concevoir un logiciel : au
lieu de l'articuler autour de ses fonctionnalités qui, par définition, sont susceptibles d'évoluer de
façon importante au cours du cycle de vie d'un produit, on conçoit le logiciel en partant des
données qu'il manipule. Ces données étant généralement plus stables, cela facilite l'évoluabilité du
logiciel.
Avec Java, nous allons donc travailler avec des objets. Un objet est une entité qui possède des
attributs et à laquelle on peut envoyer des messages. Ces messages correspondent en fait à
l'exécution (ou invocation) d'une méthode (ou fonction) propre à l'objet.
2. Les classes
En POO, l'élément de base est la classe. Une classe est une sorte de "moule à objets". Avant de
pouvoir créer un objet, on définit sa classe d'appartenance. On dit qu'un objet est une instance d'une
classe. Une classe peut servir à créer plusieurs objets ou même d'autres classes, mais nous en
reparlerons plus bas.
Nous avons vu plus haut qu'un objet possédait des attributs. Il s'agit en fait de variables, définies
dans la classe dont est issu l'objet considéré. Les méthodes quant à elles ne sont rien d'autre que des
fonctions, ayant pour but d'effectuer des traitements, susceptibles ou non de modifier les attributs
d'un objet. Il est important de remarquer que quand on programme en Java, on code des classes,
pas des objets.
Afin de faciliter certains concepts que nous introduirons plus loin, définissons un formalisme
graphique pour représenter une classe.
Dans ce graphique, qui représente une classe voiture, on indique les attributs de la classe dans la
partie centrale du diagramme. La zone inférieure contient les méthodes.
Avant d'aller plus loin, voyons comment on définit une classe en Java. En fait, on utilise le même
mot clé qu'en C++, à savoir class. Voici la syntaxe de définition d'une classe de base :
class NomDeLaClasse {
// données membres
// méthodes
}
Reprenons l'exemple de la classe voiture et voyons comment on l'implémente en Java :
class Voiture {
// données membres
int Couleur;
int Vitesse;
// méthodes
void AugmenteVitesse()
{
if (Vitesse<5)
Vitesse++;
}
void DiminueVitesse()
{
if (Vitesse>0)
Vitesse--;
}
}
Dans cet exemple, on définit deux variables membres, Couleur et Vitesse, et deux fonctions
membres, AugmenteVitesse() et DiminueVitesse(). Nous allons examiner successivement les
caractéristiques des données et des fonctions membres.
3. Les données membres
Examinons l'exemple précédent de plus près. Nous constatons tout d'abord que les variables n'ont
pas été initialisées alors que l'une d'entre elles est utilisée dans les fonctions et que nous avons dit
plus haut qu'en Java, on devait affecter une valeur à toute variable avant de pouvoir l'utiliser...En
fait, cette règle ne s'applique pas aux données membres, car celles-ci sont initialisées
automatiquement à la création d'un objet à partir de la classe (nous étudierons la création d'objets
plus loin).
D'autre part, nous constatons que ces variables sont accessibles par les méthodes, sans qu'il ne soit
nécessaire de les passer en argument. C'est une des propriétés fondamentales des données membres
: toute fonction membre d'une classe peut accéder aux données qu'elle contient, nous en reparlerons
également plus bas.
4. Les fonctions membres
Avant d'examiner le cas des fonctions membres d'une classe, rappelons quelques définitions
concernant les fonctions.
Une fonction est une portion de code à laquelle on associe :
un nom,
une liste éventuelle d'arguments (i.e. variables auxquelles on veut pouvoir accéder dans la
fonction),
un type de retour.
Le nom d'une fonction doit être unique et doit respecter les règles de dénomination précisées pour
les noms de variables.
Les arguments sont indiqués entre parenthèses après le nom de la fonction. S'il n'y a aucun
argument, la liste est vide : (). Chaque argument est spécifié par son type et le nom de la variable,
s'il y en a plusieurs, on les sépare d'une virgule.
Enfin, le type de retour est un des types que nous avons vu précédemment pour les variables, bien
qu'on puisse retourner autre chose qu'une valeur numérique, comme nous le verrons plus loin. Une
fonction qui ne renvoie rien est du type void.
La spécification du nom, type de retour et arguments d'une fonction s'appelle la signature de la
fonction.
Exemple:
void AugmenteVitesse()
{
// variable locale
int Var=0;
// code de la fonction
}
Dans cet exemple, on a défini une fonction AugmenteVitesse qui ne prend aucun argument et qui
ne renvoie rien. On a défini dans cette fonction une variable Var, de type int, dite variable locale.
Cette variable n'est accessible qu'à l'intérieur de la fonction dans laquelle elle est définie. Cette
variable n'étant pas une donnée membre d'une classe, nous devons l'initialiser explicitement avant
de pouvoir l'utiliser, comme nous l'avons dit plus haut.
Prenons un deuxième exemple :
int CalculeModuleAuCarre(int x, int y)
{
int resultat=0;
resultat=x*x+y*y;
return resultat;
}
Il s'agit cette fois-ci d'une fonction qui prend deux entiers x et y en argument et qui renvoie une
valeur de type int. On a défini une variable locale resultat, utilisée pour stocker le résultat du calcul
du module au carré d'un nombre complexe, pour lequel cette fonction a été écrite. Celle-ci renvoie
le résultat de ce calcul grâce au mot clé return. Ce mot clé indique que l'on désire quitter la
fonction. S'il est suivi d'un argument, c'est la valeur de celui-ci qui est renvoyée au module
appelant. Remarquons que dans l'exemple précédent, nous n'avions pas utilisé de return car la
fonction en question retournait un void. Nous aurions pu mettre un return sans argument, cela
aurait provoqué le même effet.
Avant de revenir aux fonctions membres, précisons un point très important, propre au langage
Java. Il faut en effet savoir qu'il y a principalement deux façons de passer une variable en argument
d'une fonction : par valeur et par référence.
Lorsque l'on passe une variable par valeur, on obtient en fait une copie de celle-ci. Si on la modifie
dans la fonction, cela n'aura aucune incidence sur la valeur de la variable définie dans le module
appelant. Il est donc impossible de modifier la valeur de cette variable dans une fonction, en
utilisant ce mécanisme.
Par contre, lorsqu'on passe une variable par référence, cela veut dire que l'on va travailler sur la
même variable que celle définie dans le module appelant, passée en argument de la fonction. Il est
donc possible de modifier la valeur de cette variable, dans la fonction.
Certains langages, comme le C, permettent de passer l'adresse d'une variable en vue de permettre la
modification du contenu de celle-ci dans une fonction. On appelle ça un pointeur. En Java, on
entend souvent dire que les pointeurs n'existent pas et que les variables sont passées par référence.
En fait, ce n'est pas complètement exact : les pointeurs existent, mais ce qui n'existe pas c'est
l'arithmétique des pointeurs, qui permet de faire directement des calculs avec des adresses et qui
rend la programmation en C si délicate et "risquée".
Nous verrons plus loin comment appeler une fonction. Revenons aux fonctions membres en
programmation objet.
Une fonction membre d'une classe peut accéder :
aux variables locales qu'elle contient,
aux variables passées en argument,
aux variables membres de la classe.
Certaines fonctions membres d'une classe peuvent avoir un rôle particulier : celui d'initialiser les
données membres, avec d'autres valeurs que celles définies par défaut. De telles fonctions sont
appelées constructeurs. D'autres fonctions sont également un peu particulières en Java. Par
exemple, toute application écrite en Java se doit de posséder une méthode main() dans une de ses
classes. C'est cette méthode qui sera appelée en premier lors de l'exécution du programme. Pour les
applets, il n'y a pas de méthode main() mais il existe des équivalents. Nous en reparlerons dans le
chapitre consacré aux applets.
5. Constructeurs
Un constructeur est une fonction qui est appelée automatiquement à la création d'un objet de la
classe, et qui permet d'initialiser les données membres. Cette fonction a un nom précis : celui de la
classe.
Exemple :
class Exemple {
// donnée membre
int val;
// constructeur
Exemple()
{
val=1;
}
}
Ici, on a défini une méthode Exemple(), constructeur de la classe du même nom. Si on crée un
objet à partir de cette classe, la valeur de la variable val sera mise à 1 automatiquement, sans qu'il
ne soit nécessaire d'appeler la fonction Exemple.
A noter qu'un constructeur n'admet jamais aucun type de retour.
Nous avons dit plus haut que, par défaut, les données membres d'une classe sont initialisées à 0
quand on instancie (i.e. crée) un objet. En fait, dans ce cas précis, on fait appel à un constructeur
par défaut qui va initialiser les variables membres. Dans l'exemple précédent, nous avons défini un
constructeur, il ne sera donc plus possible d'appeler le constructeur par défaut.
Maintenant, si l'on souhaite pouvoir spécifier la valeur que l'on veut attribuer aux variables
membres à la création d'un objet, on doit définir un deuxième constructeur tel que celui-ci :
Exemple (int ValeurInit)
{
val = ValeurInit;
}
Remarque : Notez qu'il existe un mot clé this qui désigne l'objet courant, lorsque l'on veut, par
exemple, initialiser une variable membre portant le même nom que l'argument d'un constructeur :
Exemple (int val)
{
this.val = val;
}
Il est parfaitement possible de définir plusieurs constructeurs pour une même classe, à condition
qu'ils aient tous une signature différente (en fait, des arguments différents puisque le nom doit
toujours être celui de la classe pour un constructeur et qu'une telle fonction n'admet aucun type de
retour). L'opération permettant de définir plusieurs constructeurs du même nom s'appelle la
surdéfinition.
Lorsqu'une fonction a été surdéfinie, le compilateur saura quelle fonction appeler en examinant les
arguments d'appel de cette fonction (dans certains cas, le compilateur peut être amené à faire des
conversions de type, comme par exemple passer d'un short à un int).
Maintenant que nous avons présenté en détail le contenu d'une classe, il est grand temps de voir
comment on peut créer un objet à partir d'une classe.
6. L'instanciation et l'utilisation des objets
L'opération permettant de créer un objet à partir d'une classe s'appelle l'instanciation. On dit qu'on
instancie (i.e. on crée) un objet.
La création d'un objet consiste tout simplement à réserver un certain espace mémoire, contenant,
entre autres, les données membres définies dans la classe dont l'objet est issu.
Cependant, s'il est intéressant de pouvoir créer un objet, il est encore mieux de pouvoir l'utiliser.
Pour ce faire, on doit disposer d'une variable permettant d'y faire référence. Cette variable est
parfois appelée un handle, elle contient une référence à l'objet, mais ce n'est pas l'objet en lui-
même. Précisons ces notions grâce à un exemple :
Voiture Clio; // Ces 2 lignes sont équivalentes à
Clio = new Voiture(); // Voiture Clio = new Voiture();
Ici, on définit tout d'abord une référence à un objet de type Voiture. Cette référence s'appelle Clio.
Pour le moment, aucun objet n'a été créé. On a juste défini une référence pour un objet de type
Voiture.
C'est via la deuxième ligne que l'on va créer l'objet de type Voiture, accessible grâce à la variable
Clio. En Java, comme en C++, on utilise le mot clé new pour créer un objet à partir de la classe
spécifiée en argument.
Ce mot clé a pour effet de :
créer un objet,
appeler le constructeur de cet objet, s'il en existe un, ou utiliser celui par défaut,
renvoyer une référence à l'objet nouvellement créé, permettant ainsi de le manipuler.
Dans le cas de la classe Voiture, il n'existe pas de constructeur, c'est donc le constructeur par défaut
qui est appelé. Si on reprend le cas de la classe Exemple, il est possible d'appeler le deuxième
constructeur que nous avons défini plus haut, en procédant de la façon suivante :
Exemple expl = new Exemple(1997);
Cette fois-ci, on a passé la valeur 1997 en argument, cette valeur sera affectée à la donnée membre
val définie plus haut, dans la classe Exemple.
Voyons maintenant comment on peut manipuler un objet.
Manipuler signifie accéder aux données d'un objet ou appeler une méthode de cet objet (i.e. lui
envoyer un message). Dans les deux cas, on utilise en Java l'opérateur "." séparant le nom de l'objet
du nom du membre auquel on veut accéder.
Exemple :
Clio.Vitesse = 1;
Clio.DiminueVitesse();
A la première ligne, nous modifions la variable Vitesse de l'objet, en lui attribuant la valeur 1. A la
deuxième, nous appelons la méthode DiminueVitesse qui va donc remettre à 0 la variable Vitesse
considérée (rappelons que cette méthode diminue d'une unité la variable Vitesse).
Il est important de remarquer que, en Java, il n'existe pas de mot clé permettant de détruire un objet
qui n'est plus utilisé. Cette opération est en effet effectuée automatiquement par le garbage
collector, processus que nous avons présenté dans le chapitre dédié à la Machine Virtuelle Java.
Cela simplifie d'autant plus la programmation qu'il est alors impossible de désallouer par erreur un
objet toujours utilisé dans une autre partie d'un programme, comme cela pouvait être le cas en C++.
1 / 12 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !