En programmation tableau simple peut être vu comme une liste finie d'éléments
d'un même type. En Java, un type tableau simple s'obtient en ajoutant une
paire de crochets []
après le type des éléments du tableau. Par exemple
int[]
est le type tableau correspondant aux listes finies contenant des
entiers int
.
En Java, on peut définir la valeur d'un tableau directement lors de l'initialisation d'une variable de type tableau, comme dans l'exemple suivant :
import java.util.Arrays;
public class TableauEntier {
public static void main(String[] args) {
int[] x = { 2, -3, 4};
System.out.println(x);
System.out.println(Arrays.toString(x));
}
}
En effet, la ligne System.out.println(x);
produit un affichage de la forme
[I@57801e5f
. La partie [I
correspond au type du tableau, le @
est un
séparateur et le reste est un nombre (en hexadécimal) relié à l'adresse en
mémoire du tableau. Tout ceci n'est pas très utile en pratique, c'est pourquoi
on utilisera la méthode Arrays.toString
(attention à l'import
correspondant) qui associe à un tableau une chaîne de caractères lisible. Ici,
le programme affiche finalement :
[I@57801e5f [2, -3, 4]
L'attribut length
d'un tableau indique le nombre d'éléments contenus dans le
tableau (la longueur de la liste). Les éléments sont numérotés de 0
à
length-1
. On accède à un élément grâce à la construction [index]
, comme
dans l'exemple suivant :
public class TableauAccess {
public static void main(String[] args) {
int[] x = { -1, 2, -3, 4};
System.out.println(x.length);
for(int j = 0; j < x.length; j++) {
System.out.println(x[j]);
}
}
}
qui affiche :
4 -1 2 -3 4
On peut utiliser la construction [index]
, pour modifier le contenu d'un
tableau, par exemple :
import java.util.Arrays;
public class TableauModif {
public static void main(String[] args) {
double[] z = { 1.0, 5.0, 2.5 };
System.out.println(Arrays.toString(z));
for(int j = 0; j < z.length ; j++) {
z[j] = z[j] + j;
}
System.out.println(Arrays.toString(z));
}
}
qui affiche :
[1.0, 5.0, 2.5] [1.0, 6.0, 4.5]
length
est constant : on ne peut pas modifier la taille
d'un tableau.
Java propose une version spéciale de la boucle for
pour certains types,
notamment les tableaux. Comme le montre l'exemple suivant, cette version
simplifiée est utile pour parcourir tous les éléments d'un tableau, dans
l'ordre, car la variable j
prend, à chaque tour de la boucle, la valeur d'un
des éléments du tableau :
public class TableauFor {
public static void main(String[] args) {
int[] u = { 4, 2, 5, 27};
for(int j: u) {
System.out.println(j);
}
}
}
Le programme affiche donc :
4 2 5 27
On peut pas utiliser cette boucle pour modifier le contenu du tableau, comme le montre l'exemple suivant :
import java.util.Arrays;
public class TableauForModif {
public static void main(String[] args) {
int[] u = { 4, 2, 5, 27};
for(int j: u) {
j = j + 1;
}
System.out.println(Arrays.toString(u));
}
}
qui affiche :
[4, 2, 5, 27]
Une variable de type tableau ne contient pas le tableau mais un pointeur vers celui-ci (une référence dans le vocabulaire de Java, mais c'est la même chose en pratique). Cela conduit à des phénomènes d'alias comme dans l'exemple suivant :
import java.util.Arrays;
public class TableauAlias {
public static void main(String[] args) {
double[] x = { 2.5, 0.5 };
double[] y = x;
System.out.println("x = " + Arrays.toString(x));
System.out.println("y = " + Arrays.toString(y));
x[0] = -0.5;
System.out.println("x = " + Arrays.toString(x));
System.out.println("y = " + Arrays.toString(y));
System.out.println(x==y);
}
}
qui affiche :
x = [2.5, 0.5] y = [2.5, 0.5] x = [-0.5, 0.5] y = [-0.5, 0.5] true
ce qui montre que x
et y
sont deux noms différents pour le même
tableau (comme le confirme l'expression booléenne finale).
Une variable contenant un pointeur peut pointer sur rien, ce qui s'obtient en
utilisant en Java la référence particulière null
. Son emploi est cependant
déconseillé en pratique et il vaut mieux toujours donner une valeur
significative à un pointeur.
Bien que les valeurs littérales tableaux soient pratiques, on doit parfois s'en passer, comme dans l'exemple suivant où la taille du tableau est déterminée par l'utilisateur :
import java.util.Arrays;
import java.util.Scanner;
public class TableauNew {
public static void main(String[] args) {
System.out.println("Nombre de valeurs ?");
Scanner scan = new Scanner(System.in);
int nb = scan.nextInt();
int[] x = new int[nb];
for(int i = 0; i < x.length; i++) {
System.out.println("Valeur n° "+i+" ?");
x[i] = scan.nextInt();
}
System.out.println("x = " + Arrays.toString(x));
scan.close();
}
}
Ici, on permet à l'utilisateur de déterminer la taille du tableau. Celui-ci
est créé par l'instruction new int[nb]
qui fabrique donc un tableau de
longueur nb
dont toutes les cases sont initialisées à 0
. Puis
l'utilisateur remplit le tableau, comme dans l'interaction suivante :
Nombre de valeurs ? 4 Valeur n° 0 ? 2 Valeur n° 1 ? -2 Valeur n° 2 ? -4 Valeur n° 3 ? 5 x = [2, -2, -4, 5]
Comme indiqué ci-dessus, on ne peut pas changer la taille d'un tableau une fois que celui-ci a été créé. On peut en revanche recopier le contenu d'un tableau dans un autre, ce qui permet de faire comme si un tableau était de taille variable. Dans l'exemple ci-dessous, on calcule un « vol » de la suite de Syracuse. Cette suite est définie à partir d'un paramètre entier \(P\) par récurrence suivante :
La conjecture de Syracuse indique que pour tout \(P\), il existe un \(n\) tel que \(u_n=1\), terme après lequel la suite devient cyclique (elle prend les valeurs 4, 2, et 1 de façon infinie). Le programme ci-dessous construit un tableau contenant exactement les \(n+1\) termes correspondant au « vol » de la suite en partant d'un \(P\) fixé par l'utilisateur. Comme on ne connaît pas \(n\) à l'avance, le tableau « grossit » au fur et à mesure de la progression du programme.
import java.util.Scanner;
import java.util.Arrays;
public class Syracuse {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.printf("Entrez la valeur de P : ");
int P = scan.nextInt();
int n = 1; // on a calculé un terme
int[] u = { P }; // le seul terme connu
while(u[n - 1] > 1) {
// a-t-on assez de place pour stocker u[n] ?
if(n >= u.length) {
// non
int[] nouveau = new int[2*u.length];
// on recopie u dans nouveau
System.arraycopy(u, 0, nouveau, 0, u.length);
// puis on change de tableau
u = nouveau;
}
// on calcule u_n
if(u[n - 1] % 2 == 0) {
// cas pair
u[n] = u[n - 1] / 2;
} else {
// cas impair
u[n] = 3 * u[n - 1] + 1 ;
}
// on prépare le calcul suivant
n++;
}
// le tableau est peut être plus grand qu'il ne le fallait
if(n < u.length) {
// c'est le cas
int[] nouveau = new int[n];
// on recopie la partie utile
System.arraycopy(u, 0, nouveau, 0, n);
u = nouveau;
}
System.out.printf("Vol pour %d: %s%n",P,Arrays.toString(u));
scan.close();
}
}
Ce programme affiche par exemple :
Entrez la valeur de P : 50 Vol pour 50: [50, 25, 76, 38, 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
Notons l'utilisation de la méthode System.arraycopy
. Un appel de cette
méthode prend la forme System.arraycopy(source,s,destination,d,l)
avec :
source
désigne le tableau depuis lequel on copie les valeurs ;destination
désigne le tableau dans lequel on copie les valeurs ;s
indique l'indice de départ de la copie dans le tableau source (on copie
les cases à partir de la case de numéro s
) ;d
indique l'indice de départ de la copie dans le tableau destination (on copie
dans les cases à partir de la case de numéro d
) ;l
indique le nombre de cases à copier.