2.
Les méthodes sont des fonctions
3.Transmission des paramètres en Java
Comme Java est un langage orienté objet, un programme Java est
composé de plusieurs classes, nous nous limiterons à une seule
classe.
On peut très grossièrement assimiler un programme Java ne
possédant qu'une seule classe, à un programme principal classique
d'un langage de programmation algorithmique.
1.1 Syntaxe d'une classe exécutable
Exemple1 de classe minimale :
class Exemple1 { } |
Cette classe ne fait rien et ne produit rien.
Comme en fait, une classe quelconque peut s'exécuter toute seule à condition qu'elle possède dans ses déclarations internes la méthode main qui sert à lancer l'exécution de la classe (fonctionnement semblable au lancement du programme principal).
Exemple2 de squelette d'une classe minimale exécutable :
class Exemple2 { static void main(String[ ] args) { // c'est ici que vous écrivez votre programme principal } } |
Exemple3 trivial d'une classe minimale exécutable :
class Exemple3 { static void main(String[ ] args) { System.out.println("Bonjour !"); } } |
1.2 Exemples d'applications à une classe
Nous reprenons deux exemples de programme utilisant la boucle for, déjà donnés au chapitre sur les instructions, cette fois-ci nous les réécrirons sous la forme d'une application exécutable.
Exemple1
class Application1 { static void main(String[ ] args) { /* inverse d'une suite de caractère dans un tableau par permutation des deux extrêmes */ char [ ] Tablecar ={'a','b','c','d','e','f'} ; int i, j ; System.out.println("tableau avant : " + String.valueOf(Tablecar)); for ( i = 0 , j = 5 ; i<j ; i++ , j-- ) { char car ; car = Tablecar[i]; Tablecar[i ]= Tablecar[j]; Tablecar[j] = car; } System.out.println("tableau après : " + String.valueOf(Tablecar)); } } |
Il est impératif de sauvegarder la classe dans un fichier qui porte le même nom (majuscules et minuscules inclues) ici "Application1.java". Lorsque l'on demande la compilation (production du bytecode) de ce fichier source "Application1.java" le fichier cible produit en bytecode se dénomme "Application1.class", il est alors prêt à être interprété par une machine virtuelle java.
Le résultat de l'exécution de ce programme est le suivant :
tableau avant : abcdef tableau après : fedcba |
Exemple2
class Application2 { static void main(String[ ] args) { // recherche séquentielle dans un tableau int [ ] table= {12,-5,7,8,-6,6,4,78,2}; int elt = 4, i ; for ( i = 0 ; i<8 ; i++ ) if (elt= =table[i]) break ; if (i = = 8) System.out.println("valeur : "+elt+" pas trouvée."); else System.out.println("valeur : "+elt+" trouvée au rang :"+i); } } |
Après avoir sauvegardé la classe dans un fichier qui porte le même nom (majuscules et minuscules inclues) ici "Application2.java", la compilation de ce fichier "Application2.java" produit le fichier "Application2.class" prêt à être interprété par notre machine virtuelle java.
Le résultat de l'exécution de ce programme est le suivant :
valeur : 4 trouvée au rang :6 |
Conseil de travail :
reprenez tous les exemples simples du chapitre sur les instructions de boucle et le switch en les intégrant dans une seule classe (comme nous venons de le faire avec les deux exemples précédents) et exécutez votre programme. |
2. Les méthodes sont des fonctions
Les méthodes ou bien fonctions représentent une encapsulation
des instructions qui déterminent le fonctionnement d'une classe.
Sans méthodes pour agir une classe ne fait rien de particulier, dans
ce cas elle ne fait que contenir des attributs.
2.1 Méthode élémentaire de classe
Bien que Java distingue deux sortes de méthodes : les méthodes
de classe et les méthodes d'instance, pour l'instant dans
cette première partie nous décidons à titre pédagogique
et simplificateur de n'utiliser que les méthodes de classe,
le chapitre sur Java et la programmation orientée objet apportera
les compléments adéquats.
Une méthode de classe commence obligatoirement par le mot clef static. |
Donc par la suite dans ce document lorsque nous emploierons le mot méthode
sans autre adjectif, il s'agira d'une méthode de classe, comme
nos applications ne possèdent qu'une seule classe, nous pouvons assimiler
ces méthodes aux fonctions de l'application et ainsi retrouver une
utilisation classique de Java en mode appplication.
La notion de fonction en Java est semblable à celle du C et à Delphi, elle comporte une en-tête avec des paramètres formels et un corps de fonction ou de méthode qui contient les instructions de la méthode qui seront exécutés lors de son appel. La déclaration et l'implémentation doivent être consécutives comme l'indique la syntaxe ci-dessous :
Syntaxe :
corps de fonction :
Nous dénommons en-tête de fonction la partie suivante :
<qualificateurs><type du résultat><nom
de fonction> (<liste paramètres
formels>)
Sémantique :
Exemples d'en-tête de méthodes sans paramètres
en Java
int calculer( ){.....} | renvoie un entier de type int |
boolean tester( ){.....} | renvoie un entier de type boolean |
void uncalcul( ){.....} | procédure ne renvoyant rien |
Exemples d'en-tête de méthodes avec paramètres en Java
int calculer(byte a, byte b, int
x ) {.....} |
fonction à 3 paramètres |
boolean tester( int k) {.....} |
fonction à 1 paramètre |
void uncalcul(int x, int y, int
z ) {.....} |
procédure à 3 paramètres |
L'appel de méthode en Java s'effectue très classiquement avec des paramètres effectifs dont le nombre doit obligatoirement être le même que celui des paramètres formels et le type doit être soit le même, soit un type compatible ne nécessitant pas de transtypage.
Exemple d'appel de méthode-procédure sans paramètres en Java
class Application3 { static void main(String[ ] args) { afficher( ); } static void afficher( ) { System.out.println("Bonjour"); } } |
Appel de la méthode afficher |
Exemple d'appel de méthode-procédure avec paramètres de même type en Java
class Application4 { static void main(String[ ] args) { // recherche séquentielle dans un tableau int [ ] table= {12,-5,7,8,-6,6,4,78,2}; long elt = 4; int i ; for ( i = 0 ; i<=8 ; i++ ) if (elt= =table[i]) break ; afficher(i,elt); } static void afficher (int rang , long val) { if (rang == 8) System.out.println("valeur : "+val+" pas trouvée."); else System.out.println("valeur : "+val+" trouvée au rang :"+ rang); } } |
Appel de la méthode afficher
afficher(i,elt);Les deux paramètres effectifs "i" et "elt" sont du même type que le paramètre formel associé. - Le paramètre effectif "i" est associé au paramètre formel rang. - Le paramètre effectif "elt" est associé au paramètre formel val. |
3. Transmission des paramètres en Java
Rappelons tout d'abord quelques principes de base :
Dans tous les langages possédant la notion de sous-programme (ou fonction ou procédure), il se pose une question à savoir, les paramètres formels décrits lors de la déclaration d'un sous-programme ne sont que des variables muettes servant à expliquer le fonctionnement du sous-programme sur des futures variables lorsque le sous-programme s'exécutera effectivement.
La démarche en informatique est semblable à celle qui, en
mathématiques, consiste à écrire la fonction f(x)
= 3*x - 7, dans laquelle x alors une variable muette indiquant comment
f est calculée : en informatique elle joue le rôle du paramètre
formel. Lorsque l'on veut obtenir une valeur effective de la fonction
mathématique f, par exemple pour x=2, on écrit f(2) et l'on
calcule f(2)=3*2 - 7 = -1. En informatique on "passera" un paramètre
effectif dont la valeur vaut 2 à la fonction. D'une manière
générale, en informatique, il y a un sous-programme
appelant et un sous-programme appelé
par le sous-programme appelant.
3.1 Compatibilité des types des paramètres
Resituons la compatibilité des types entier et réel en Java.
Un moyen mémotechnique pour retenir cette compatibilité est
indiqué dans les figures ci-dessous, par la taille en nombre décroissant
de bits de chaque type que l'on peut mémoriser sous la forme "qui
peut le plus peut le moins" ou bien un type à n bits accueillera
un sous-type à p bits, si p est inférieur à
n.
Les types entiers compatibles :
|
Les types réels compatibles :
|
Exemple d'appel de la même méthode-procédure avec paramètres de type compatibles en Java
class Application5 { static void main(String[ ] args) { // recherche séquentielle dans un tableau int [ ] table= {12,-5,7,8,-6,6,4,78,2}; byte elt = 4; short i ; for ( i = 0 ; i<8 ; i++ ) if (elt= =table[i]) break ; afficher(i,elt); } static void afficher (int rang , long val) { if (rang == 8) System.out.println("valeur : "+val+" pas trouvée."); else System.out.println("valeur : "+val+" trouvée au rang :"+ rang); } } |
Appel de la méthode afficher
afficher(i,elt);Les deux paramètres effectifs "i" et "elt" sont d'un type compatible avec celui du paramètre formel associé. - Le paramètre effectif "i" est associé au paramètre formel rang.(short = entier signé sur 16 bits et int = entier signé sur 32 bits) - Le paramètre effectif "elt"
est associé au paramètre formel val.(byte
= entier signé sur 8 bits et long = entier signé sur
64 bits) |
3.2 Les deux modes de transmission des paramètres
Un paramètre effectif transmis au sous-programme appelé est en fait un moyen d’utiliser ou d’accéder à une information appartenant au bloc appelant (le bloc appelé peut être le même que le bloc appelant, il s’agit alors de récursivité).
En Java, il existe deux modes de transmission (ou de passage) des paramètres (semblables à Delphi).
Le passage par valeur uniquement réservé à tous les types élémentaires (int, byte, short, long, boolean, double, float, char).
Le passage par référence uniquement réservé à tous les types objets.
Remarque :
Le choix de passage selon les types élimine les inconvénients dûs à l'encombrement mémoire et à la lenteur de recopie de la valeur du paramètre par exemple dans un passage par valeur, car nous verrons plus loin que les tableaux en Java sont des objets et qu'ils sont donc passés par référence. |
3.3 Les retours de résultat de méthode-fonction
Les méthodes en Java peuvent renvoyer un résultat de n'importe quel type élémentaire ou objet. Bien qu'une méthode ne puisse renvoyer qu'un seul résultat, l'utilisation du passage par référence d'objets permet aussi d'utiliser les paramètres de type objet d'une méthode comme des variables d'entrée/sortie.
En Java le retour de résultat est passé grâce au mot clef return placé n'importe où dans le corps de la méthode.
Syntaxe :
Sémantique :
Exemple la fonction f(x)=3x-7
class Application6 { static void main(String[ ] args) { // ... int x , y ; x = 4 ; y = f(5) ; y = f(x) ; System.out.println("f(x)="+ f(x) ); System.out.println("f(5)="+ f(5) ); } static int f (int x ) { return 3*x-7; } } |
Appel de la méthode f
f ( 5 ) ;Dans les deux cas la valeur 5 ou la valeur 4 de x est recopiée dans la zone de pile de la machine virtuelle java. |
Exemple de méthode-procédure
class Application7 { static void main(String[ ] args) { int a = 0 ; procedure ( a ); procedure ( a+4 ); } static void procedure(int x) { if (x = = 0) { System.out.println("avant return"); return ; } System.out.println("après return"); } } |
Appel de la méthode procedure
Dans le cas du premier appel (x ==0) est true donc ce sont les instructions:
Dans le cas du second appel (x ==0) est false c'est donc l'instruction:
|
Le principe de base est que les variables en Java sont visibles (donc
utilisables) dans le bloc dans lequel elles ont été définies.
Java est un langage à structure de blocs ( comme pascal et C ) dont le principe général de visibilité est :
Toute variable déclarée dans un bloc est visible dans ce bloc et dans tous les blocs imbriqués dans ce bloc. |
En java les blocs sont constitués par :
|
Le masquage des variables n'existe que pour les variables déclarées dans des méthodes :
Il est interdit
de redéfinir une variable déjà
déclarée dans une méthode soit :
|
4.2 Variables dans une classe, dans une méthode
Les variables définies (déclarées, et/ou initialisées) dans une classe sont accessibles à toutes les méthodes de la classe, la visibilité peut être modifiée par les qualificateurs public ou private que nous verrons au chapitre POO.
Exemple de visibilité dans une classe
class ExempleVisible1 { int a = 10; int g (int x ) int f (int x, int a ) } |
La variable "a" définie dans int
a =10; :
- Est une variable de la classe ExempleVisible. - Elle est visible dans la méthode g et dans la méthode f. C'est elle qui est utilisée dans la méthode g pour évaluer l'expression 3*x-a. - Dans la méthode f, elle est masquée par le
paramètre du même nom qui est utilisé pour évaluer
l'expression 3*x-a.
|
Contrairement à ce que nous avions signalé plus haut nous n'avons pas présenté un exemple fonctionnant sur des méthodes de classes (qui doivent obligatoirement être précédées du mot clef static), mais sur des méthodes d'instances dont nous verrons le sens plus loin en POO. Remarquons avant de présenter le même exemple cette fois-ci sur des méthodes de classes, que quelque soit le genre de méthode la visibilité des variables est identique.
Exemple identique sur des méthodes de classe
class ExempleVisible2 { static int a = 10; static int g (int x ) static int f (int x, int a ) } |
La variable "a" définie dans static
int a =10; :
- Est une variable de la classe ExempleVisible. - Elle est visible dans la méthode g et dans la méthode f. C'est elle qui est utilisée dans la méthode g pour évaluer l'expression 3*x-a. - Dans la méthode f, elle est masquée par le
paramètre du même nom qui est utilisé pour évaluer
l'expression 3*x-a.
|
Les variables définies dans une méthode (de classe ou d'instance)
subissent les règles classiques de la visibilité du bloc dans
lequel elles sont définies :
Elles sont visibles dans toute la méthode et dans tous les blocs imbriqués dans cette méthode et seulement à ce niveau (les autres méthodes de la classe ne les voient pas), c'est pourquoi on emploie aussi le terme de variables locales à la méthode. |
Reprenons l'exemple précédent en y adjoignant des variables locales aux deux méthodes f et g.
Exemple de variables locales
class ExempleVisible3 { static int a = 10; static int g (int x ) static int f (int x, int a ) } |
La variable de classe "a" définie dans
static int a = 10; est
masquée dans les deux méthodes f et g.
Dans la méthode g, c'est la variable locale longa = 123456 qui masque la variable de classe static int a. char car ='t'; est une variable locale à la méthode g. - Dans la méthode f, char car ='u'; est une variable locale à la méthode f, le paramètre inta masque la variable de classe static int a. Les variables locales char car n'existent
que dans la méthode où elles sont définies, les variables
"car" de f et celle de g n'ont aucun rapport entre elles,
bien que portant le même nom. |
4.3 Variables dans un bloc autre qu'une classe ou une méthode
Les variables définies dans des blocs du genre instructions composées, boucles, try..catch ne sont visibles que dans le bloc et ses sous-blocs imbriqués, dans lequel elle sont définies.
Toutefois attention aux redéfinitions de variables locales. Les blocs du genre instructions composées, boucles, try..catch ne sont utilisés qu'à l'intérieur du corps d'une méthode (ce sont les actions qui dirigent le fonctionnement de la méthode), les variables définies dans de tels blocs sont automatiquement considérées par Java comme des variables locales à la méthode. Tout en respectant à l'intérieur d'une méthode le principe de visibilité de bloc, Java n'accepte pas le masquage de variable à l'intérieur des blocs imbriqués.
Nous donnons des exemples de cette visibilité :
Exemple correct de variables locales
class ExempleVisible4 {
static int a = 10, b = 2; static int f (int x ) { char car = 't'; for (int i = 0; i
< 5 ; i++) if (a < 7) else b = 5-a+i*b; return 3*x-a+b; |
La variable de classe "a" définie dans static int a = 10; est masquée dans la méthode f dans le bloc imbriqué for. La variable de classe "b" définie dans static int b = 2; est masquée dans la méthode f dans le bloc imbriqué if. Dans l'instruction { intb = 8; b = 5-a+i*b; } , c'est la variable b interne à ce bloc qui est utilisée car elle masque la variable b de la classe. Dans l'instruction else b = 5-a+i*b; , c'est la variable
b de
la classe qui est utilisée (car la variable int b = 8 n'est plus visible ici) . |
Exemple de variables locales générant une erreur
class ExempleVisible5 {
static int a = 10, b = 2; static int f (int x ) { char car = 't'; for (int i = 0; i
< 5 ; i++) if (a < 7) else b = 5-a+i*b; return 3*x-a+b; |
Toutes les remarques précédentes restent valides puisque l'exemple ci-contre est quasiment identique au précédent. Nous avons seulement rajouté dans le bloc if la définition d'une nouvelle variable interne a à ce bloc. Java produit une erreur de compilation int
b = 8, a
= 9; sur la variable a, en indiquant que c'est
une redéfinition de variable à l'intérieur
de la méthode f, car nous avions déjà défini
une variable a ({ int
a=7;...)
dans le bloc englobant for {...}. |
Remarquons que le principe de visiblité des variables adopté en Java est identique au principe inclus dans tous les langages à structures de bloc y compris pour le masquage, s'y rajoute en Java uniquement l'interdiction de la redéfinition à l'intérieur d'une même méthode (semblable en fait, à l'interdiction de redéclaration sous le même nom, de variables locales à un bloc).