UKOnline

Appeler les méthodes d'un objet

On sait maintenant créer des objets et on aimerait pouvoir effectuer des opérations sur ces objets, sans quoi ils ne serviraient pas à grand chose. On connait déjà des opérateurs applicables sur des données de type primitif : +, *, %, <<, --... Parmi ceux-ci, on vient de voir que les deux opérateurs == et != peuvent être utilisés avec les objets.

Un grand avantage des objets par rapport aux types primitifs est leur grande richesse au niveau des fonctionnalités disponibles. Rappelez-vous de l'exemple du GSM : on peut effectuer un appel, envoyer un SMS, etc. Ce qu'on veut pouvoir faire, c'est utiliser une fonctionnalité sur un objet précis. En Java, ce qu'on va faire, c'est invoquer (ou appeler) une méthode sur un objet. Une méthode représente une fonctionnalité qu'on va pouvoir utiliser en l'invoquant sur l'objet.

Opérateur d'invocation

Pour invoquer une méthode sur un objet, il faut utiliser l'opérateur d'invocation (ou d'appel, ou d'accès). Cet opérateur binaire se note par un point ( . ). L'opérande de gauche est l'objet sur lequel la méthode doit être invoquée et l'opérande de droite est le nom de la méthode à invoquer, suivi d'une liste de paramètres qui sont des expressions mises entre parenthèses. La figure 7 montre la syntaxe de l'instruction d'invocation de méthode.

Appel de méthode
Syntaxe de l'appel de méthode.

Cette instruction permet donc d'invoquer ou appeler la méthode de nom méthode sur l'objet référencé par la variable variable avec les paramètres spécifiés entre parenthèses. Ceux-ci sont appelés paramètres d'appel de la méthode. Tout comme les paramètres de création qu'on a vu à la section précédente, ce sont des expressions.

Méthode mutateur et méthode accesseur

Les méthodes représentent donc les opérations qu'on peut effectuer sur des objets et on peut les classer de différentes manières. Prenons un exemple avec des objets de type Date. La méthode setDate permet de modifier le jour de l'objet sur lequel elle est appelée. Cette méthode prend un paramètre qui doit être de type int et qui représente le nouveau jour que l'on veut pour la date.

Si on exécute ce programme, voici ce qu'on va voir s'afficher à l'écran :

Fri Aug 01 00:00:00 CEST 2008
Sat Aug 16 00:00:00 CEST 2008

On voit donc bien que l'état de l'objet référencé par la variable date a été modifié suite à l'appel de la méthode setDate. Avant l'appel, l'objet représentait le 1e aout 2008 et après l'appel, son état a été changé et il représente le 16 aout 2008. La figure 8 montre l'état de la mémoire avant et après l'appel de la méthode.

Appel de méthode mutateur
Appel de la méthode setDate sur un objet Date.

Une méthode qui change l'état de l'objet sur lequel elle est appelée est une méthode mutateur ou méthode de mise à jour. Un appel vers une telle méthode est généralement une instruction, mais on verra un peu plus loin que ce n'est pas toujours le cas.

L'exemple suivant utilise un autre type de méthode. Dans la classe Date, on retrouve une méthode de nom getMonth qui ne prend aucun paramètres. Elle permet d'obtenir le mois de l'objet Date sur lequel elle est appelée. Pour rappel, cette information est représentée par un entier qui est 0 pour le mois de janvier, 1 pour février...

Une méthode dont l'appel permet d'obtenir de l'information sur l'objet sur lequel elle est appelée est une méthode accesseur. Un appel vers une telle méthode est une expression dont la valeur correspond à l'information récupérée sur l'objet. Dans l'exemple, on stocke l'information obtenue sur l'objet dans la variable month, qui est donc initialisée à 7 (le mois d'aout). La figure 9 montre la mémoire avant et après l'appel de la méthode setMonth; vous voyez que l'appel vers la méthode n'a pas modifié l'état de l'objet.

Appel de méthode accesseur
Appel de la méthode getMonth d'un objet Date.

L'appel vers une méthode accesseur est une expression et on peut donc retrouver un tel appel partout où on peut utiliser une expression. La troisième instruction de l'exemple suivant utilise un appel vers la méthode getMonth comme paramètre pour la méthode println. Un tel appel peut également être utilisé comme une instruction, mais cela n'a aucun sens comme la seconde instruction de l'exemple suivant, qui ne sert strictement à rien.

La distinction entre les méthodes mutateurs et accesseurs n'est pas stricte car rien dans la syntaxe du langage Java n'impose qu'une méthode soit mutateur ou accesseur. Il y a en effet des méthodes qui peuvent être à la fois mutateur et accesseur, c'est-à-dire qu'appeler une telle méthode va changer l'état de l'objet et permettre d'obtenir une information sur son état.

Enfin, on ne parle habituellement de méthode accesseur que lorsqu'elle permet d'obtenir la valeur d'un des attributs de l'objet. Par exemple, une méthode qui permettrait d'obtenir l'année d'une date est considérée comme une méthode accesseur, mais une méthode qui permet de savoir si l'année d'une date est bissextile ne le serait pas forcément.

Méthode void et méthode qui renvoie une valeur

Il y a une autre manière de classer les méthodes : celles de type void et celles qui renvoient une valeur. Contrairement au classement qu'on a vu dans la section précédente, la distinction entre les méthodes void et celles qui renvoient une valeur est imposée par la syntaxe du langage Java. Toute méthode se retrouve donc dans l'une des deux catégories.

L'appel d'une méthode void effectue des opérations sur l'objet sur lequel elle est appelée, mais on ne reçoit aucune information en retour. Les appels vers ces méthodes doivent être des instructions. Si vous utilisez un tel appel comme une expression, le compilateur générera une erreur de compilation. Les méthodes mutateurs sont généralement des méthodes void, mais ce n'est pas toujours le cas.

Une méthode qui renvoie une valeur est une méthode dont l'appel va éventuellement effectuer des opérations sur l'objet sur lequel elle est appelée et va en plus fournir un résultat. Ce résultat est appelé valeur de retour de la méthode. Un appel vers une telle méthode est une expression et peut également être utilisé comme une instruction. Les méthodes accesseurs sont des méthodes qui renvoient une valeur avec comme contrainte supplémentaire que l'état de l'objet n'est pas modifié.

Voyons un nouvel exemple pour se fixer les idées :

La première instruction crée un nouvel objet de type Date représentant le 25 mai 1988. La seconde instruction affiche cet objet à l'écran. La troisième instruction appelle la méthode getMonth sur l'objet référencé par la variable d; cette méthode renvoie une valeur qui est le mois de la date (à savoir 4). On ajoute ensuite 1 à cette valeur et on stocke le résultat de l'addition dans la variable newmonth qui contient donc 5 (c'est-à-dire 4 + 1). Ensuite, on va appeler la méthode setMonth qui permet de changer le mois d'une date et on lui donne en paramètre la variable newmonth qui contient le nouveau mois que l'on souhaite. Enfin, la dernière instruction affiche à nouveau la date à l'écran.

Voici le résultat de l'exécution de ce programme :

Wed May 25 00:00:00 CEST 1988
Sat Jun 25 00:00:00 CEST 1988

La méthode getMonth est une méthode qui renvoie une valeur et un appel de celle-ci est donc une expression. Par contre, la méthode setMonth est une méthode void, son appel ne peut donc qu'être une instruction. On verra à la section 4 comment savoir de quel type est une méthode, le nombre de paramètres d'appel qu'il faut fournir et leurs types et le type de la valeur renvoyée par les méthodes qui renvoient une valeur.

Changer l'état d'un objet

Il est bien important de comprendre et se rappeler qu'une méthode qui renvoie une valeur permet de récupérer une information sur l'objet. Un appel vers une telle méthode est donc une expression et ne peut être utilisé que là où une expression est acceptable. Une erreur courante est de vouloir utiliser un appel à une telle méthode à droite de l'opérateur d'affectation, pour changer l'état de l'objet. Les instructions suivantes provoqueront une erreur de compilation :

Voici l'erreur de compilation produite :

TestDate.java:6: unexpected type
required: variable
found   : value
		d.getMonth() = 8;

Pour changer l'état d'un objet, il faut passer par les méthodes applicables à l'objet. Dans ce cas-ci, on aurait du utiliser la méthode setMonth pour changer le mois de la date.

Méthode de classe

Toutes les méthodes que l'on vient de voir s'appliquent toujours sur un objet; on les appelle par ailleurs méthodes d'instance. Elles permettent d'effectuer une opération sur un objet particulier. Il existe également des méthodes qui ne s'appliquent pas sur un objet, ce sont les méthodes de classe (également appelées méthodes statiques). La syntaxe pour les appeler est semblable à celle utilisée pour les méthodes d'instance si ce n'est qu'on ne spécifie pas une variable comme opérande de gauche de l'opérateur d'appel, mais le nom d'une classe comme l'illustre la figure 10.

Appel de méthode de classe
Syntaxe de l'appel de méthode de classe.

Les méthodes de classe ne sont pas liées à un objet. Elles reçoivent des paramètres, effectuent des opérations avec ces derniers et peuvent éventuellement renvoyer un résultat. La classe Math, par exemple, regorge de telles méthodes permettant d'effectuer des calculs mathématiques : sinus, cosinus, racine carrée, puissance, valeur absolue, etc. Le programme suivant calcule le sinus de 90 degrés :

Le programme affiche 1.0 à l'écran après exécution et il s'agit bien du sinus de 90 degrés. La seconde instruction appelle la méthode de classe toRadians qui se trouve dans la classe Math. Cette méthode prend un paramètre qui est un angle en degrés et elle renvoie sa conversion en radians comme résultat. Ce résultat est stockée dans la variable angleRadians. L'instruction suivante appelle la méthode sin qui se trouve également dans la classe Math et qui va calculer et renvoyer le sinus de l'angle en radians passé en paramètre. On stocke la valeur renvoyée dans la variable result que l'on va finalement afficher à l'écran.

Manipuler plusieurs objets

Il est important de bien comprendre que les méthodes d'instance s'appliquent sur un objet en particulier. Il s'agit de celui qui est référencé par la variable utilisée comme opérande gauche de l'opérateur d'appel de méthode, appelé objet cible. La méthode va pouvoir modifier l'état de cet objet et renvoyer des informations le concernant. Ce concept étant très important, voyons un exemple qui implique plusieurs objets.

Voici ce que l'exécution de ce programme affiche à l'écran :

Sat Jul 31 00:00:00 CEST 1999
Wed Mar 03 00:00:00 CET 1999
Wed Mar 03 00:00:00 CET 1999
Wed Mar 03 00:00:00 CET 1999

On voit que l'objet référencé par la variable d1 a changé et représente maintenant le 3 mars 1999. En effet, on a appelé la méthode setMonth sur cet objet en lui donnant comme paramètre la valeur de l'expression d2.getMonth() - 3 qui vaut $4 - 3 = 1$. Cette valeur correspond au mois de février, mais il n'y a pas de 31 février, et comme l'année 1999 était bissextile, on se retrouve en fait au 3 mars. Par contre, l'objet référencé par la variable d2 n'a pas changé puisqu'on n'a appelé aucune méthode mutateur dessus. La figure 11 montre l'état des deux objets avant et après l'appel setMonth.

Objet cible
Objet cible.

Comparaison d'objets

À la section 4.2.5, on a vu que l'opérateur == permet de comparer deux variables de type objet. Plus précisément, il permet de vérifier si deux variables référencent le même objet, mais pas si les objets référencés ont le même état.

Pour vérifier que les objets référencés par deux variables ont le même état, il faut faire appel à la méthode equals qui prend un objet en paramètre et renvoie un boolean. La méthode va comparer le contenu de l'objet cible avec l'objet passé en paramètre et renvoyer true si les deux objets ont le même état et false sinon.

Voyons un exemple :

L'expression d1 == d2 vaut false puisque les deux objets référencés par les variables d1 et d2 sont deux objets distincts. Par contre, l'expression d1.equals (d2) vaut true puisque les deux objets ont le même état, ils représentent tous les deux le 12 mars 2009.

Constante de classe

Enfin, il existe également des constantes de classe. Il s'agit de constante qui sont définies dans une classe. Pour y accéder, on utilise l'opérateur d'accès (le point). Il y a par exemple une constante qui représente la valeur de $\pi$ dans la classe Math.