 |
3. STRUCTURES DE DONNEES |
Un tableau en Java est un objet, donc comme toute variable objet, une variable tableau est une
référence. Lors de sa déclaration, il n'est pas possible d'indiquer la taille
du tableau.
int t[];
La taille n'est fournie qu'au moment de l'allocation.
t=new int[10];
Pour connaître la taille d'un tableau, il suffit de consulter l'attribut
length de celui-ci.
int taille = t.length;
Il est possible d'allouer des tableaux à plusieurs dimensions, comme le montre l'exemple
suivant qui construit une matrice 3x4 de chaînes de caractères.
String m[][] = new String[3][4];
int i = 0;
int j;
while (i<3) {
j=0;
while (j<4) {
m[i][j]=new String("case "+i+";"+j);
++j;
}
++i;
}
Attention, lors de l'allocation d'un tableau d'éléments de type primitif, les
cases du tableau contiennent ces éléments. Lors de l'allocation d'un tableau d'objets
d'une classe quelconque, les cases du tableau contiennent des références d'objets
initialisées à null.
Un tableau à plusieurs dimensions est en fait un tableau de tableaux. Et il n'est pas
obligatoire que ces derniers soient tous de même taille.
int m[][] = new int[3][];
int i = 0;
while (i<3) {
m[i]=new int[5*(i+1)];
j=0;
while (j<5*(i+1)) {
m[i][j]=i+j;
++j;
}
++i;
}
Il est possible, comme en C++, d'initialiser directement un tableau à sa
déclaration.
int a[] = {1,2,3};
Contrairement au C++, les chaînes de caractères en Java ne sont pas des tableaux de
caractères. Le seul moyen d'obtenir une chaîne de caractères est d'utiliser la
classe String.
String r = new String("bonjour");
String t = "bonjour";
Pour connaître la taille d'une chaîne de caractères, il suffit d'appeler la
méthode length.
int taille = t.length();
Il est possible de concaténer deux chaînes de caractères grâce
à l'opérateur +.
String s = t+" toi";
Un objet de la classe String n'étant pas un tableau de caractères, il
n'est pas possible d'utiliser l'opérateur [] pour accéder à un
caractère de la chaîne. Pour cela, il faut utiliser la méthode
charAt.
char j = s.charAt(3);
L'opérateur == appliqué directement sur deux variables compare leurs
références et non pas les objets qu'elles pointent. Pour comparer réellement
deux objets, il faut utiliser leur méthode equals, héritée de la
classe Object, et normalement redéfinie dans leur classe véritable.
if (s.equals("bonjour")) ...
La méthode indexOf permet de déterminer la position d'une
chaîne de caractères dans une autre. Si aucune sous-chaîne n'est trouvée,
alors la méthode renvoie -1.
int position = s.indexOf("toi");
Enfin, la méthode substring permet d'extraire une partie d'une chaîne
de caractères, en indiquant la position du premier caractère et la position
après le dernier caractère de la sous-chaîne.
String toi = s.substring(position,position+3);
Voici la liste des types primitifs reconnus par Java. La plupart sont identiques à ceux
du C++. La différence importante est que la norme Java impose un codage standard des types.
| Type |
Description |
byte |
entier signé, 8 bits |
boolean |
booléen, 1 bit, true / false |
char |
caractère, 16 bits, norme Unicode |
short |
entier signé, 16 bits |
int |
entier signé, 32 bits |
long |
entier signé, 64 bits |
float |
flottant, 32 bits, norme IEEE 754 |
double |
flottant, 64 bits, norme IEEE 754 |
Les variables de type primitif ne sont pas reconnues comme des objets, ce qui est très
gênant lorsqu'on ne dispose pas des patrons de composant. Comment proposer par exemple une
liste chaînée qui puisse à la fois contenir des entiers de type
int et des objets de type String ? La solution est de transformer
les variables de type primitif en objets. Comme toutes les classes en Java héritent de la
classe Object, il est alors possible de proposer une liste chaînée
d'objets de type Object. Tous les types primitifs ont leur équivalent en objet.
| Type primitif |
Classe équivalente |
byte |
Byte |
boolean |
Boolean |
char |
Character |
short |
Short |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
Nous présentons quelques fonctionnalités de la classe Integer, celles
des autres classes sont très similaires. Tout d'abord, il est possible de créer
à partir d'un entier un objet Integer.
Integer i = new Integer(4);
D'une chaîne de caractères, il est possible d'extraire un entier grâce
à la méthode parseInt de la classe Integer. A noter que
l'accès aux propriétés de classes en Java se fait en appliquant
l'opérateur . sur la classe, alors qu'en C++ il s'agit de l'opérateur
::.
int i = Integer.parseInt("4");
La méthode lève une exception (cf. le dernier chapitre) si la conversion de la
chaîne en entier est impossible. Naturellement, d'un objet Integer, il est
possible de récupérer sa valeur sous la forme d'un entier.
int j = i.intValue();
A l'instar de C++ avec la STL (Standard Template Library), Java fournit en standard un
certain nombre de conteneurs très utiles pour accélérer le
développement des applications. Cependant, comme la notion de patron n'existe pas encore en
Java, les conteneurs sont conçus de manière à stocker des objets de la classe
Object, à laquelle tout objet appartient. Mais nous verrons dans cette
section que cela impose au programmeur d'employer le downcast, mécanisme lent puisqu'il
doit détecter en temps réel la classe de l'objet. En outre, pour les types primitifs,
les conteneurs ne sont pas utilisables directement, il faut transformer les variables en des
objets. En résumé, ces classes conteneurs sont très utiles, mais ne sont pas
d'une très grande efficacité. Nous ne citerons ici que deux conteneurs, le
vecteur et le dictionnaire, qui sont assez représentatifs. Nous aborderons
également l'énumération, qui permet un parcours séquentiel des
éléments d'un conteneur. Notons que tous ces éléments font partie du
package java.util.
Le vecteur, la classe Vector, équivalente à la classe
vector de la STL, représente un tableau redimensionnable, autrement dit quand
on lui ajoute des éléments, il adapte sa taille et réalloue de la
mémoire si nécessaire. Voici un exemple simple qui ajoute dix entiers dans un
vecteur.
Vector v = new Vector();
int i = 0;
while (i<10) {
v.addElement(new Integer(i));
++i;
}
Le tableau suivant propose une liste non exhaustive de méthodes qui permettent de
manipuler un vecteur.
| Méthode |
Description |
v.lastElement() |
Retourne le dernier élément de v. |
v.elementAt(i) |
Retourne l'élément de v à la
position i. |
v.setElementAt(o,i) |
Affecte o à l'élément de
v à la position i. |
v.insertElementAt(o,i) |
Insère l'élément o dans
v à la position i. |
v.removeElement(i) |
Supprime l'élément de v à la
position i. |
v.removeAllElements() |
Supprime tous les éléments de v. |
v.size() |
Retourne le nombre d'éléments de v. |
v.setSize(n) |
Redimensionne v à la taille n. |
v.indexOf(o) |
Retourne la position où se trouve l'élément de
valeur o, si aucun n'est trouvé, -1 est retourné. |
v.elements() |
Retourne une énumération des éléments de
v (cf. la dernière section). |
Le dictionnaire, la classe Dictionary, équivalente à la classe
map de la STL, représente un conteneur associatif, où un
élément est identifié par une clé. Voici un exemple simple qui associe
à des entiers leur forme textuelle.
Dictionary d = new Hashtable();
d.put(new Integer(1),"un");
d.put(new Integer(2),"deux");
d.put(new Integer(3),"trois");
...
La classe Dictionary est abstraite, la sous-classe que nous utilisons ici est
Hashtable. Pour récupérer ensuite la forme textuelle d'un nombre, il
suffit de fournir la clé, i.e. le nombre, au dictionnaire.
String s = (String)d.get(new Integer(3));
La méthode get renvoie null si la clé n'est pas
présente dans le dictionnaire. Il faut noter également que get retourne
une référence sur un objet de type Object, et qu'il est
nécessaire de le convertir, dans notre exemple en une référence sur un objet
de type String, la syntaxe pour cela est identique à celle du C++.
Il est également possible de supprimer un élément du dictionnaire, en
utilisant sa clé.
d.remove(new Integer(3));
La méthode size permet de connaître la taille d'un dictionnaire.
int taille = d.size();
Suivant les circonstances, il peut être intéressant de parcourir tous les
éléments du dictionnaire ou toutes ses clés. Pour cela, le dictionnaire
dispose de deux méthodes: keys qui renvoie une énumération des
clés, et elements qui renvoie une énumération des
éléments. La notion d'énumération est présentée dans la
section suivante.
Les conteneurs ne fournissent pas d'interface commune pour parcourir tous les
éléments qu'ils contiennent, ce qui est nécessaire pour que les algorithmes
soient indépendants des structures de données qu'ils manipulent. En outre, un
conteneur comme le dictionnaire possède deux ensembles d'éléments, les
clés et les valeurs associées. Pour disposer d'une manière commune de
parcourir un ensemble d'éléments, indépendamment du type de conteneur, il
existe la classe (ou plus exactement l'interface) Enumeration qui représente un
ensemble ordonné d'éléments. Un conteneur dispose de méthodes
permettant de le convertir en un objet de la classe Enumération (cf. les
méthodes keys et elements des conteneurs Vector et
Dictionary). Reprenons l'exemple de la section précédente pour parcourir
les clés du dictionnaire.
Enumeration e = d.keys();
while (e.hasMoreElements()) {
i=(Integer)e.nextElement();
...
}
| |
| |
| Copyright (c) 1999-2016 - Bruno Bachelet - bruno@nawouak.net -
http://www.nawouak.net |
| La permission est accordée de copier, distribuer et/ou modifier ce document
sous les termes de la licence GNU Free Documentation License, Version 1.1 ou toute
version ultérieure publiée par la fondation Free Software Foundation. Voir
cette licence pour plus de détails (http://www.gnu.org). |
|
|