Licence CC BY-NC-SA

Les méthodes de classe

Ce contenu est obsolète. Il peut contenir des informations intéressantes mais soyez prudent avec celles-ci.

Maintenant que vous commencez à écrire de vrais programmes, vous vous rendez sûrement compte qu'il y a certaines choses que vous effectuez souvent. Plutôt que de recopier sans arrêt les mêmes morceaux de code, vous pouvez écrire une méthode…

Ce chapitre aura pour but de vous faire découvrir la notion de méthode (on l'appelle « fonction » dans d'autres langages). Vous en avez peut-être déjà utilisé une lors du premier TP, vous vous en souvenez ? Vous avez pu voir qu'au lieu de retaper le code permettant d'arrondir un nombre décimal, vous pouviez l'inclure dans une méthode et appeler celle-ci.

Le principal avantage des méthodes est de pouvoir factoriser le code : grâce à elles, vous n'avez qu'un seul endroit où effectuer des modifications lorsqu'elles sont nécessaires. J'espère que vous comprenez mieux l'intérêt de tout cela, car c'est ce que nous allons aborder ici. Cependant, ce chapitre ne serait pas drôle si nous ne nous amusions pas à créer une ou deux méthodes pour le plaisir. Et là, vous aurez beaucoup de choses à retenir !

Quelques méthodes utiles

Vous l'aurez compris, il existe énormément de méthodes dans le langage Java, présentes dans des objets comme String : vous devrez les utiliser tout au long de cet ouvrage (et serez même amenés à en modifier le comportement). À ce point du livre, vous pouvez catégoriser les méthodes en deux « familles » : les natives et les vôtres.

Des méthodes concernant les chaînes de caractères

La méthode toLowerCase() permet de transformer tout caractère alphabétique en son équivalent minuscule. Elle n'a aucun effet sur les chiffres : ce ne sont pas des caractères alphabétiques. Vous pouvez donc l'utiliser sans problème sur une chaîne de caractères comportant des nombres. Elle s'emploie comme ceci :

1
2
String chaine = new String("COUCOU TOUT LE MONDE !"), chaine2 = new String();
chaine2 = chaine.toLowerCase();   //Donne "coucou tout le monde !"

la méthode toUpperCase() est simple, puisqu'il s'agit de l'opposé de la précédente. Elle transforme donc une chaîne de caractères en capitales, et s'utilise comme suit :

1
2
String chaine = new String("coucou coucou"), chaine2 = new String();
chaine2 = chaine.toUpperCase();   //Donne "COUCOU COUCOU"

La méthode length() renvoie la longueur d'une chaîne de caractères (en comptant les espaces).

1
2
3
String chaine = new String("coucou ! "); 
int longueur = 0;
longueur = chaine.length();   //Renvoie 9

La méthode equals() permet de vérifier (donc de tester) si deux chaînes de caractères sont identiques. C'est avec cette fonction que vous effectuerez vos tests de condition sur les String. Exemple concret :

1
2
3
4
5
6
7
String str1 = new String("coucou"), str2 = new String("toutou");

if (str1.equals(str2))
  System.out.println("Les deux chaînes sont identiques !");

else
  System.out.println("Les deux chaînes sont différentes !");

Vous pouvez aussi demander la vérification de l'inégalité grâce à l'opérateur de négation. Vous vous en souvenez ? Il s'agit de « ! ». Cela nous donne :

1
2
3
4
5
6
7
String str1 = new String("coucou"), str2 = new String("toutou");

if (!str1.equals(str2))
  System.out.println("Les deux chaînes sont différentes !");

else
  System.out.println("Les deux chaînes sont identiques !");

Ce genre de condition fonctionne de la même façon pour les boucles. Dans l'absolu, cette fonction retourne un booléen, c'est pour cette raison que nous pouvons y recourir dans les tests de condition.

Le résultat de la méthode charAt() sera un caractère : il s'agit d'une méthode d'extraction de caractère. Elle ne peut s'opérer que sur des String ! Par ailleurs, elle présente la même particularité que les tableaux, c'est-à-dire que, pour cette méthode, le premier caractère sera le numéro 0. Cette méthode prend un entier comme argument.

1
2
String nbre = new String("1234567");
char carac = nbre.charAt(4);   //Renverra ici le caractère 5

La méthode substring() extrait une partie d'une chaîne de caractères. Elle prend deux entiers en arguments : le premier définit le premier caractère (inclus) de la sous-chaîne à extraire, le second correspond au dernier caractère (exclu) à extraire. Là encore, le premier caractère porte le numéro 0.

1
2
String chaine = new String("la paix niche"), chaine2 = new String();
chaine2 = chaine.substring(3,13);   //Permet d'extraire "paix niche"

La méthode indexOf() explore une chaîne de caractères à la recherche d'une suite donnée de caractères, et renvoie la position (ou l'index) de la sous-chaîne passée en argument. la méthode indexOf() explore à partir du début de la chaîne, lastIndexOf() explore en partant de la fin, mais renvoie l'index à partir du début de la chaîne. Ces deux méthodes prennent un caractère ou une chaîne de caractères comme argument, et renvoient un int. Tout comme charAt() et substring(), le premier caractère porte le numéro 0. Je crois qu'ici, un exemple s'impose, plus encore que pour les autres fonctions :

1
2
3
4
5
6
7
8
String mot = new String("anticonstitutionnellement");
int n = 0;

n = mot.indexOf('t');           //n vaut 2
n = mot.lastIndexOf('t');       //n vaut 24
n = mot.indexOf("ti");          //n vaut 2
n = mot.lastIndexOf("ti");      //n vaut 12
n = mot.indexOf('x');           //n vaut -1

Les méthodes que nous allons voir nécessitent la classe Math, présente dans java.lang. Elle fait donc partie des fondements du langage. Par conséquent, aucun import particulier n'est nécessaire pour utiliser la classe Math qui regorge de méthodes utiles :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
double X = 0.0;
X = Math.random();
//Retourne un nombre aléatoire 
//compris entre 0 et 1, comme 0.0001385746329371058

double sin = Math.sin(120);     //La fonction sinus
double cos = Math.cos(120);     //La fonction cosinus
double tan = Math.tan(120);     //La fonction tangente
double abs = Math.abs(-120.25); //La fonction valeur absolue (retourne le nombre sans le signe)
double d = 2;
double exp = Math.pow(d, 2);    //La fonction exposant
//Ici, on initialise la variable exp avec la valeur de d élevée au carré
//La méthode pow() prend donc une valeur en premier paramètre, et un exposant en second

Ces méthodes retournent toutes un nombre de type double.

Je ne vais pas vous faire un récapitulatif de toutes les méthodes présentes dans Java, sinon j'y serai encore dans mille ans… Toutes ces méthodes sont très utiles, croyez-moi. Cependant, les plus utiles sont encore celles que nous écrivons nous-mêmes ! C'est tellement mieux quand cela vient de nous.

Créer sa propre méthode

Voici un exemple de méthode que vous pouvez écrire :

1
2
3
public static double arrondi(double A, int B) {
  return (double) ( (int) (A * Math.pow(10, B) + .5)) / Math.pow(10, B);
}

Décortiquons un peu cela :

  • Tout d'abord, il y a le mot clé public. C'est ce qui définit la portée de la méthode, nous y reviendrons lorsque nous programmerons des objets.
  • Ensuite, il y a static. Nous y reviendrons aussi.
  • Juste après, nous voyons double. Il s'agit du type de retour de la méthode. Pour faire simple, ici, notre méthode va renvoyer un double !
  • Vient ensuite le nom de la méthode. C'est avec ce nom que nous l'appellerons.
  • Puis arrivent les arguments de la méthode. Ce sont en fait les paramètres dont la méthode a besoin pour travailler. Ici, nous demandons d'arrondir le double A avec B chiffres derrière la virgule.
  • Finalement, vous pouvez voir une instruction return à l'intérieur de la méthode. C'est elle qui effectue le renvoi de la valeur, ici un double.

Nous verrons dans ce chapitre les différents types de renvoi ainsi que les paramètres que peut accepter une méthode.

Vous devez savoir deux choses concernant les méthodes :

  1. elles ne sont pas limitées en nombre de paramètres;
  2. il en existe trois grands types :
    • les méthodes qui ne renvoient rien. Les méthodes de ce type n'ont pas d'instruction return, et elles sont de type void ;
    • les méthodes qui retournent des types primitifs (double, int etc.). Elles sont de type double, int, char etc. Celles-ci possèdent une instruction return ;
    • les méthodes qui retournent des objets. Par exemple, une méthode qui retourne un objet de type String. Celles-ci aussi comportent une instruction return.

Jusque-là, nous n'avons écrit que des programmes comportant une seule classe, ne disposant elle-même que d'une méthode : la méthode main. Le moment est donc venu de créer vos propres méthodes. Que vous ayez utilisé ou non la méthode arrondi dans votre TP, vous avez dû voir que celle-ci se place à l'extérieur de la méthode main, mais tout de même dans votre classe !

Pour rappel, jetez un œil à la capture d'écran du premier TP, à la figure suivante.

Emplacement des méthodes

Si vous placez une de vos méthodes à l'intérieur de la méthode main ou à l'extérieur de votre classe, le programme ne compilera pas.

Puisque nous venons d'étudier les tableaux, nous allons créer des méthodes pour eux. Vous devez certainement vous souvenir de la façon de parcourir un tableau. Et si nous faisions une méthode qui permet d'afficher le contenu d'un tableau sans que nous soyons obligés de retaper la portion de code contenant la boucle ? Je me doute que vous n'en voyez pas l'intérêt maintenant, car exception faite des plus courageux d'entre vous, vous n'avez utilisé qu'un ou deux tableaux dans votre main du chapitre précédent. Si je vous demande de déclarer vingt-deux tableaux et que je vous dis : « Allez, bande de Zéros ! Parcourez-moi tout ça ! », vous n'allez tout de même pas écrire vingt-deux boucles for ! De toute façon, je vous l'interdis. Nous allons écrire une méthode. Celle-ci va :

  • prendre un tableau en paramètre ;
  • parcourir le tableau à notre place ;
  • effectuer tous les System.out.println() nécessaires ;
  • ne rien renvoyer.

Avec ce que nous avons défini, nous savons que notre méthode sera de type void et qu'elle prendra un tableau en paramètre. Voici un exemple de code complet :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class Sdz1
{
  public static void main(String[] args)
  {
    String[] tab = {"toto", "tata", "titi", "tete"};
    parcourirTableau(tab); 
  }

  static void parcourirTableau(String[] tabBis)
  {
    for(String str : tabBis)
      System.out.println(str);
  }
}

Je sais que cela vous trouble encore, mais sachez que les méthodes ajoutées dans la classe main doivent être déclarées static. Fin du mystère dans la partie sur la programmation orientée objet !

Bon. Vous voyez que la méthode parcourt le tableau passé en paramètre. Si vous créez plusieurs tableaux et appelez la méthode sur ces derniers, vous vous apercevrez que la méthode affiche le contenu de chaque tableau !

Voici un exemple ayant le même effet que la méthode parcourirTableau, à la différence que celle-ci retourne une valeur : ici, ce sera une chaîne de caractères.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Sdz1 {

  public static void main(String[] args)
  {
    String[] tab = {"toto", "tata", "titi", "tete"};
    parcourirTableau(tab);
    System.out.println(toString(tab));   
  }

  static void parcourirTableau(String[] tab)
  {
    for(String str : tab)
    System.out.println(str);
  }

  static String toString(String[] tab)
  {
    System.out.println("Méthode toString() !\n----------");
    String retour = "";

    for(String str : tab)
      retour += str + "\n"; 

    return retour;
  }         
}

Vous voyez que la deuxième méthode retourne une chaîne de caractères, que nous devons afficher à l'aide de l'instruction System.out.println(). Nous affichons la valeur renvoyée par la méthode toString(). La méthode parcourirTableau, quant à elle, écrit au fur et à mesure le contenu du tableau dans la console. Notez que j'ai ajouté une ligne d'écriture dans la console au sein de la méthode toString(), afin de vous montrer où elle était appelée.

Il nous reste un point important à aborder. Imaginez un instant que vous ayez plusieurs types d'éléments à parcourir : des tableaux à une dimension, d'autres à deux dimensions, et même des objets comme des ArrayList (nous les verrons plus tard, ne vous inquiétez pas). Sans aller aussi loin, vous n'allez pas donner un nom différent à la méthode parcourirTableau pour chaque type primitif !

Vous avez dû remarquer que la méthode que nous avons créée ne prend qu'un tableau de String en paramètre. Pas un tableau d'int ou de long, par exemple. Si seulement nous pouvions utiliser la même méthode pour différents types de tableaux… C'est là qu'entre en jeu ce qu'on appelle la surcharge.

La surcharge de méthode

La surcharge de méthode consiste à garder le nom d'une méthode (donc un type de traitement à faire : pour nous, lister un tableau) et à changer la liste ou le type de ses paramètres. Dans le cas qui nous intéresse, nous voulons que notre méthode parcourirTableau puisse parcourir n'importe quel type de tableau. Nous allons donc surcharger notre méthode afin qu'elle puisse aussi travailler avec des int, comme le montre cet exemple :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
static void parcourirTableau(String[] tab)
{
  for(String str : tab)
    System.out.println(str);
}

static void parcourirTableau(int[] tab)
{
  for(int str : tab)
    System.out.println(str);
}

Avec ces méthodes, vous pourrez parcourir de la même manière :

  • les tableaux d'entiers ;
  • les tableaux de chaînes de caractères.

Vous pouvez faire de même avec les tableaux à deux dimensions. Voici à quoi pourrait ressembler le code d'une telle méthode (je ne rappelle pas le code des deux méthodes ci-dessus) :

1
2
3
4
5
6
7
8
static void parcourirTableau(String[][] tab)
{
  for(String tab2[] : tab)
  {
    for(String str : tab2)
      System.out.println(str);
  }
}

La surcharge de méthode fonctionne également en ajoutant des paramètres à la méthode. Cette méthode est donc valide :

1
2
3
4
5
6
7
8
static void parcourirTableau(String[][] tab, int i)
{
  for(String tab2[] : tab)
  {
    for(String str : tab2)
      System.out.println(str);
  }
}

En fait, c'est la JVM qui va se charger d'invoquer l'une ou l'autre méthode : vous pouvez donc créer des méthodes ayant le même nom, mais avec des paramètres différents, en nombre ou en type. La machine virtuelle fait le reste. Ainsi, si vous avez bien défini toutes les méthodes ci-dessus, ce code fonctionne :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
String[] tabStr = {"toto", "titi", "tata"};
int[] tabInt = {1, 2, 3, 4};
String[][] tabStr2 = {{"1", "2", "3", "4"}, {"toto", "titi", "tata"}};

//La méthode avec un tableau de String sera invoquée
parcourirTableau(tabStr);
//La méthode avec un tableau d'int sera invoquée
parcourirTableau(tabInt);
//La méthode avec un tableau de String à deux dimensions sera invoquée
parcourirTableau(tabStr2);

Vous venez de créer une méthode qui vous permet de centraliser votre code afin de ne pas avoir à retaper sans arrêt les mêmes instructions. Dans la partie suivante, vous apprendrez à créer vos propres objets. Elle sera très riche en informations, mais ne vous inquiétez pas : nous apprendrons tout à partir de zéro. ;)


En résumé

  • Une méthode est un morceau de code réutilisable qui effectue une action bien définie.
  • Les méthodes se définissent dans une classe.
  • Les méthodes ne peuvent pas être imbriquées. Elles sont déclarées les unes après les autres.
  • Une méthode peut être surchargée en modifiant le type de ses paramètres, leur nombre, ou les deux.
  • Pour Java, le fait de surcharger une méthode lui indique qu'il s'agit de deux, trois ou X méthodes différentes, car les paramètres d'appel sont différents. Par conséquent, Java ne se trompe jamais d'appel de méthode, puisqu'il se base sur les paramètres passés à cette dernière.