Les chaînes et les tableaux

Chapitres traités   


Choix des chapitres Chaînes de caractères

Les chaînes sont des suites de caractères (par exemple: "hello"). Java ne contient pas de type chaîne prédéfini. En revanche, la bibliothèque Java standard contient une classe prédéfinie appelée String. Chaque chaîne est un objet (une référence) de la classe String. Comme toute déclaration d'une variable objet, l'instruction :

String ch;

déclare que ch est destinée à contenir une référence à un objet de type String. Par ailleur, la notation "bonjour" désigne en fait un objet de type String (ou, pour être plus précis, sa référence), créé automatiquement par le compilateur. Ainsi, avec :

ch = "bonjour";

on abouti à une situation qu'on peut schématiser ainsi :

 

La classe String dispose de deux constructeurs, l'un sans argument créant une chaîne vide, l'autre avec un argument de type String qui crée une copie :

Il ne faut pas perdre de vue qu'on manipule constamment des références à des objets et que celles-ci peuvent voir leur valeur évoluer au fil du programme. Considérons l'instruction suivante :

Après l'exécution, nous obtenons la situation de droite

 

Exécutons maintenant ces instructions :

ch = ch1;
ch1 = ch2;
ch2 = ch;

Nous obtenons une permutation des références ch1 et ch2, par contre les deux objets de type chaîne n'ont pas été modifiés.

Choix du chapitre Concaténation

Java autorise l'emploi du signe + et += pour joindre (concaténer) deux chaînes.

Lorsque vous concaténez une chaîne et une valeur qui n'est pas une chaîne, cette valeur est convertie en chaîne.

Choix du chapitre Manipulation des chaînes

Il existe un certain nombre de méthodes intégrées à la classe String pour permettre différentes manipulations sur les chaînes :

  1. length : permet de connaître la longueur d'une chaîne
  2. charAt : renvoie le caractère (Unicode) situé à la position désirée (Attention, la première position est 0).
  3. indexOf : renvoie la position à partir du début de la chaîne la première occurence d'un caractère donné. (Attention, là aussi la première position est 0. Si le caractère n'existe pas dans la chaîne, la valeur retournée est -1).
  4. substring : permet de créer une nouvelle chaîne un extrayant de la chaîne courante tous les caractères compris entre deux positions données (la première incluse, la second exclue).

Attention : Les objets de la classe String sont inaltérables. Il n'existe donc pas de méthodes permettent de modifier un caractère dans une chaîne existante. Il faut alors utiliser une sous-chaîne.

Le fait que le compilateur construise un objet de type String lorsqu'il rencontre une constante chaîne (entre guillemets) signifie que vous pouvez parfaitement utiliser les méthodes de String avec cette chaîne. Vous pouvez écrire :

n = "Monsieur".length(); // n est initialisé avec la taille de la chaîne (ici 8)

Choix du chapitre Test d'égalité des chaînes


Attention : N'employez pas l'opérateur == pour tester l'égalité de deux chaînes! Cet opérateur détermine seulement si les chaînes sont stockées au même emplacement (même référence - adresse de la variable). Il est évident que si deux chaînes se trouvent à la même adresse, elles doivent être égales. Mais des copies de chaînes identiques peuvent être stockées à des emplacements différents dans la mémoire.

La méthode equals

Fort heureusement, la classe String dispose d'une méthode equals qui compare le contenu de deux chaînes et renvoie true si elles sont égales, et false dans le cas contaire.

La méthode equalsIgnoreCase

La méthode equalsIgnoreCase effectue la même comparaison, mais sans distinguer les majuscules et les minuscules.

Choix du chapitre Passage en majuscules ou en minuscules

La méthode toLowerCase crée une nouvelle chaîne en remplaçant toutes les majuscules par leur équivalent en minuscules (lorsque celui-ci existe). La méthode toUpperCase crée une nouvelle chaîne en remplaçant toutes les minuscules par leur équivalent en majuscules.

 

Conversions entre chaînes et types primitifs

Conversion d'un type primitif en une chaîne

Nous avons déjà vu comment l'opérateur "+" effectuait un "formatage" en convertissant n'importe quel type primitif en une chaîne. Vous pouvez effectuer directement de telles conversions, en utilisant la méthode valueOf de la classe String.

La méthode valueOf peut recevoir un argument de type quelconque et pas seulement de type entier.

Conversion d'une chaîne en un type primitif

On peut réaliser les conversions inverses des précédentes. Il faut alors recourir à une méthode de la classe enveloppe associée au type primitif : Integer pour int, Double pour double, etc...

Par exemple, pour convertir une chaîne en un entier de type int, on utilisera la méthode statique parseInt de la classe enveloppe Integer, comme ceci :

D'une manière générale, nous disposons des méthodes pour chaque type primitif comme cela est précisé ci-dessus.

Points de code et unités de code

Les chaînes Java sont implémentées sous forme de suites de valeurs char. Comme nous l'avons vu, le type char est une unité de code permettant de représenter des points de code Unicode en codage UTF-16. Les caractères Unicode les plus souvent utilisés peuvent être représentés par une seule unité de code. Les caractères complémentaires exigent, quant à eux, une paire d'unité de code.

 

Choix des chapitres Tableaux

Les tableaux permettent de regrouper une suite de variables de même type. Chaque élément du tableau est une variable que vous pouvez utiliser comme n'importe quelle variable de ce type. Il est possible de définir des tableaux pour les types primaires ou les classes. Cependant, tous les éléments doivent être du même type. En Java, les tableaux sont des objets. Pour pouvoir utiliser un tableau, vous devez respecter les trois étapes suivantes :

  1. Déclarer une variable pour référencer le tableau.
  2. Créer un objet de type tableau en initialisant la référence à ce tableau.
  3. Utiliser et manipuler les éléments de ce tableau.

Considérons cette déclaration :

int t[];

Elle précise que t est destiné à contenir la référence à un tableau d'entiers. Vous constatez qu'aucune dimension ne figure dans cette déclaration et, pour l'instant, aucune valeur n'a été attribuée à t.

On crée un tableau comme on crée un objet, c'est à dire en utilisant l'opérateur new. On précise à la fois le type des éléments, ainsi que leur nombre (dimension du tableau).

t = new int[5]; // t fait référence à un tableau de 5 entiers

Cette instruction alloue l'emplacement nécessaire à un tableau de 5 éléments de type int et place la référence dans t. Les 5 éléments sont initialisés par défaut (comme tous les champs d'un objet) à une valeur nulle (0 pour int).

Choix du chapitre Déclaration de tableaux

La déclaration d'une référence à un tableau précise donc simplement le type des éléments du tableau. Elle peut prendre deux formes différentes.

Création d'un tableau

Création par l'opérateur new

Après avoir déclaré la variable tableau, il faut allouer les éléments de ce tableau. On utilise pour ce faire l'opérateur new. Vous avez déjà mis en oeuvre cet opérateur pour créer des objets. A ce niveau, il est obligatoire de préciser le nombre d'éléments du tableau. Ces derniers sont initialisés automatiquement en fonction du type de tableau (0 pour les numériques, '\0' pour les caractères, false pour les boolean et null pour tout le reste).

Utilisation d'un initialiseur

Lors de la déclaration d'une référence, il est possible de fournir la valeur à chacune des cases du tableau. Il suffit de donner la liste entre accolades sans utiliser l'opérateur new. Java se sert du nombre de valeurs figurant dans l'initialiseur pour en déduire la taille du tableau à créer.

Choix du chapitre Utilisation d'un tableau

Accès individuel aux éléments d'un tableau

On peut manipuler un élément de tableau comme on le ferait avec n'importe quelle variable ou n'importe quel objet de ses éléments. On désigne un élément particulier en plaçant entre crochets, à la suite du nom du tableau, une expression entière nommée indice indiquant sa position. Le premier élément correspond à l'indice 0 (et non 1).

Affectation de tableaux

Java permet aussi de manipuler globalement des tableaux, par le biais d'affectations de leurs références.

Exécutons maintenant l'affectation :

t1 = t2; // la référence contenue dans t2 est recopiée dans t1


Nous aboutissons à la situation présentée ci-contre. Dorénavant, t1 et t2 désigne le même tableau. Ainsi, avec :

t1[1] = 5;
System.out.println (t2[1]);

on obtiendra l'affichage de la valeur 5, et non 11.

Si l'objet que constitue le tableau de trois entiers anciennement désigné par t1 n'est plus référencé par ailleurs, il deviendra candidat au ramasse-miettes.

Il est très important de noter que l'affectation de références de tableaux n'entraine aucune recopie des valeurs des éléments du tableau. On retrouve exactement le même phénomène que pour l'affectation d'objets.

Choix du chapitre Nombre d'éléments d'un tableau

Pour connaître le nombre d'éléments d'un tableau, vous pouvez utiliser l'attribut public length. Cet attribut peut être utilisé pour tous les types de tableaux. Considérez le code suivant :

int tab[] = new int [10];
int taille = tab.length; // taille est égal à 10

Après avoir déclaré un tableau, utilisez length pour récupérer le nombre d'éléments du tableau (ici 10).

Le mot length désigne en quelque sorte un attribut du tableau, attribut que l'on peut d'ailleurs uniquement lire ; ce n'est pas un attribut au même titre que les attributs d'une classe. Remarquons qu'il n'y a pas d'autre attribut pour une variable de type tableau.

Manipuler un tableau d'objets


Attention : Pour définir un tableau d'objets, il faut commencer par définir un tableau de références, puis, pour chaque référence, créer l'objet associé. Un tableau d'objets est en fait un tableau de références, et chaque référence pointe vers l'objet associé.

Le résultat est le suivant :

Point : 1, 2
Point : 4, 5
Point : 8, 9


Il est possible d'avoir une écriture plus concise de la classe TabPoint en utilisant l'initialiseur de tableau.

Choix du chapitre Tableau en argument

Lorsqu'on transmet un nom de tableau en argument d'une méthode, on transmet en fait (une copie) la référence au tableau. La méthode agit directement sur le tableau concerné et non sur une copie. Ce principe est d'ailleurs utilisé pour tous les types d'objets. D'une façon générale, lorsqu'on transmet un objet en argument d'une méthode, on transmet toujours sa référence.

Le résultat est :

Salut
bonjour
Hello
*
*
*

Tableau anonyme

Il est même possible d'initialiser un tableau anonyme :

new int[] { 2, 3, 5, 7, 11, 13 }

Cette expression alloue un nouveau tableau et le remplit avec les valeurs spécifiées entre parenthèses. Elle détermine le nombre de valeurs fournies et donne au tableau le même nombre d'éléments. Cette syntaxe est employée lorsqu'on désire passer un tableau à une méthode sans créer pour cela une variable locale. L'exemple :

printLabels(new String[] { "Région", "Ventes" });

est un raccourci pour :

String[] titres = { "Région", "Ventes"};
printLabels(titres);

Afficher un tableau dans la sortie standard

Il existe une méthode très très simple pour afficher toutes les valeurs d'un tableau dans la sortie standard, et ce grâce à la méthode toString() de la classe Arrays. L'appel Arrays.toString(tableau) renvoie une chaîne de caractères contenant les éléments du tableau, insérés entre crochets et séparés par des virgules :

System.out.println(Arrays.toString(tableau)); // affichepar exemple à l'écran "[2, 3, 5, 7, 11, 13]"

Copie des tableaux

Il est possible de copier une variable tableau dans une autre, mais attention, comme nous l'avons vu plus haut, les deux variables feront alors référence au même tableau :

int[ ] suite = {17, 19, 23, 29, 31, 37};
int[ ] entier = suite;
entier[3] = 12; // suite[3] vaut maintenant 12

Tri d'un tableau

Si vous voulez trier un tableau de nombres, utilisez une des méthodes sort() de la classe Arrays :

int[ ] nombre = new int[100];
...
Arrays.sort(nombre);

Cette méthode utilise une version adaptée de l'algorithme QuickSort qui se révèle très efficace sur la plupart des ensembles de données.
§

 

Exercices

Exercices

Soit la déclaration suivante dans la méthode main :
String bonjour = "salut la compagnie";

  1. Continuer le programme pour que le message bonjour s'affiche en majuscule.
  2. Compléter le programme en ajoutant une méthode qui permet de mettre uniquement la première lettre de chaque mot d'une chaîne de caractères en majuscule. Vous testerez cette méthode avec la chaîne bonjour.
  1. faire un programme qui utilise un tableau ordonné des 26 lettres de l'alphabet en minuscule. L'initialisation du tableau doit se faire en dehors de la déclaration (par une itérative). Le programme devra ensuite afficher le contenu du tableau dans l'ordre inverse.
  2. Faire un programme convivial (à l'aide d'un menu sommaire) qui permet de compléter un tableau d'entier de 10 cases, d'afficher son contenu, d'enlever des valeurs (le menu comporte 4 options :
    1. ajouter une valeur,
    2. enlever le dernière valeur,
    3. afficher le contenu du tableau
    4. et quitter le programme.

    Au départ le tableau doit être vide (valeur 0 dans toutes les cases). L'affichage lorsqu'il est demandé doit être sous la forme de, par exemple <5, 3> (on remarque dans cet affichage que le tableau dispose de deux valeurs entières respectivement 5 et 3). Il faut protéger votre programme par les malversation de l'utilisateur, en effet il ne doit pas y avoir plus de dix valeurs dans le tableau même si l'opérateur, sans le faire exprès, veut en rajouter d'autre.

  3. Définir une méthode appelée makeRange() qui admet deux entiers, une limite inférieure et une limite supérieure, et crée un tableau qui contient tous les entiers compris entre ces deux entiers (à l'inclusion des deux limites). Par exemple, lorsque j'écris ceci :
    makeRange(3, 7); le résultat doit-être : [ 3 4 5 6 7 ]
  1. Fabriquez une méthode qui permet d'afficher un tableau de chaînes de caractères, l'affichage de la chaîne sera systématiquement exprimé en lettres minuscules. A titre d'exemple, vous passerez à la méthode le tableau semaine ci-dessous :
    String semaine[] = {"Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"};
  2. Fabriquer une méthode qui admet comme argument un tableau de chaînes de caractères et qui retourne également un tableau de chaînes de caractères. Toutefois, toutes les chaînes du nouveau tableau seront systématiquement écrites en majuscules. Vous profiterez de cette méthode pour tester le passage de tableaux anonymes. Pour tester convenablement, vous afficherez le tableau original et le tableau final (sauf pour le tableau anonyme).

Récupération des sources des corrections