XII. Chapitre 10. Autres briques de base Java▲
Nous avons eu l'occasion d'utiliser pas mal d'éléments Java différents dans les chapitres précédents. Nous avons même créé un jeu de morpion. Mais j'ai laissé de côté d'importants éléments et techniques Java et il est temps de corriger ces omissions.
XII-A. Utilisation des valeurs de date et d'heure▲
Tous les ordinateurs ont une horloge interne. N'importe quel programme Java peut déterminer la date et l'heure courantes et les afficher dans différents formats, par exemple "15/06/2004" ou "15 juin 2004". De nombreuses classes Java permettent de gérer les dates et les heures, mais deux d'entre elles, java.util.Date et java.text.SimpleDateFormat, suffiront à couvrir la plupart de tes besoins.
Il est facile de créer un objet qui stocke les date et heure système courantes précises à la milliseconde près :
Date maintenant =
new
Date
(
);
System.out.println
(
"Nous sommes le "
+
SimpleDateFormat.getDateInstance
(
).format
(
maintenant)));
La sortie de ces lignes peut ressembler à ceci (7) :
Nous sommes le 23 juin 2005
La classe SimpleDateFormat permet d'afficher les dates et les heures selon différents formats. D'abord, tu dois créer une instance de cette classe avec le format souhaité. Ensuite, appelle sa méthode format() en lui passant un objet Date en argument. Le programme suivant formate et affiche la date courante sous différents formats.
import
java.util.Date;
import
java.text.SimpleDateFormat;
public
class
MonFormatDate {
public
static
void
main
(
String [] args ) {
// Crée un objet Date
// et l'affiche dans le format par défaut
Date maintenant =
new
Date
(
);
System.out.println
(
"Nous sommes le : "
+
SimpleDateFormat.getDateInstance
(
).format
(
maintenant));
// Affiche la date comme ceci : 23-06-05
SimpleDateFormat formatDate =
new
SimpleDateFormat
(
"dd-MM-yy"
);
String dateFormatée =
formatDate.format
(
maintenant);
System.out.println
(
"Nous sommes le (jj-MM-aa) : "
+
dateFormatée);
// Affiche la date comme ceci : 23-06-2005
formatDate =
new
SimpleDateFormat
(
"dd/MM/yyyy"
);
dateFormatée =
formatDate.format
(
maintenant);
System.out.println
(
"Nous sommes le (jj/MM/aaaa) : "
+
dateFormatée);
// Affiche la date comme ceci : jeudi 23 juin 2005
formatDate =
new
SimpleDateFormat
(
"EEEE d MMM yyyy"
);
dateFormatée =
formatDate.format
(
maintenant);
System.out.println
(
"Nous sommes le (JJJJ jj MMMM aaaa) : "
+
dateFormatée);
// Affiche l'heure comme ceci : 20h 30m 17s
formatDate =
new
SimpleDateFormat
(
"kk'h' mm'm' ss's'"
);
dateFormatée =
formatDate.format
(
maintenant);
System.out.println
(
"Il est (HHh MMm SSs) : "
+
dateFormatée);
}
}
Compile et exécute la classe MonFormatDate. Elle affiche ceci :
Nous sommes le : 23 juin 2005
Nous sommes le (jj-MM-aa) : 23-06-05
Nous sommes le (jj/MM/aaaa) : 23/06/2005
Nous sommes le (JJJJ jj MMMM aaaa) : jeudi 23 juin 2005
Il est (HHh MMm SSs) : 20h 30m 17s
La documentation Java de la classe SimpleDateFormat décrit d'autres formats. Tu peux aussi trouver d'autres méthodes de gestion des dates dans la classe java.util.Calendar.
XII-B. Surcharge de méthode▲
Il peut y avoir, dans une même classe, plusieurs méthodes de même nom mais ayant des listes d'arguments différentes. C'est ce qu'on appelle la surcharge de méthode (method overloading). Par exemple, la méthode println() de la classe System peut être appelée avec différents types d'arguments : String, int, char, etc.
System.out.println
(
"Bonjour"
);
System.out.println
(
250
);
System.out.println
(
'A'
);
Même s'il semble que l'on appelle trois fois la même méthode println(), il s'agit en fait de trois méthodes différentes. Tu te demandes peut-être pourquoi on ne crée pas des méthodes avec des noms différents, par exemple printString(), printInt() et printChar() ? Une raison en est qu'il est plus facile de mémoriser un nom de méthode d'affichage plutôt que plusieurs. Il y a d'autres raisons justifiant l'utilisation de la surcharge de méthode, mais elles sont un peu compliquées à expliquer et sont abordées dans des livres d'un niveau plus avancé.
Tu te rappelles notre classe Poisson du Chapitre 4 et sa méthode plonger(), qui attend un argument :
public
int
plonger
(
int
combienDePlus)
Créons une autre version de cette méthode qui n'aura pas besoin d'argument. Cette méthode va forcer le poisson à plonger de cinq mètres, sauf si la profondeur courante vient à dépasser 100 mètres. La nouvelle version de la classe Poisson a une nouvelle variable invariante, PROFONDEUR_PLONGEE, dont la valeur est cinq.
La classe Poisson a maintenant deux méthodes plonger() surchargées.
public
class
Poisson extends
AnimalFamilier {
int
profondeurCourante =
0
;
final
int
PROFONDEUR_PLONGEE =
5
;
public
int
plonger
(
) {
profondeurCourante =
profondeurCourante +
PROFONDEUR_PLONGEE;
if
(
profondeurCourante >
100
) {
System.out.println
(
"Je suis un petit"
+
" poisson et je ne peux pas plonger"
+
" plus profond que 100 mètres"
);
profondeurCourante =
profondeurCourante
-
PROFONDEUR_PLONGEE;
}
else
{
System.out.println
(
"Plongée de "
+
PROFONDEUR_PLONGEE
+
" mètres"
);
System.out.println
(
"Je suis à "
+
profondeurCourante
+
" mètres sous le niveau de la mer"
);
}
return
profondeurCourante;
}
public
int
plonger
(
int
combienDePlus) {
profondeurCourante =
profondeurCourante +
combienDePlus;
if
(
profondeurCourante >
100
) {
System.out.println
(
"Je suis un petit"
+
" poisson et je ne peux pas plonger"
+
" plus profond que 100 mètres"
);
profondeurCourante =
profondeurCourante
-
combienDePlus;
}
else
{
System.out.println
(
"Plongée de "
+
combienDePlus
+
" mètres"
);
System.out.println
(
"Je suis à "
+
profondeurCourante
+
" mètres sous le niveau de la mer"
);
}
return
profondeurCourante;
}
public
String dire
(
String unMot){
return
"Ne sais-tu pas que les poissons ne"
+
" parlent pas ?"
;
}
// Constructeur
Poisson
(
int
positionDépart) {
profondeurCourante =
positionDépart;
}
}
MaîtrePoisson peut désormais appeler l'une ou l'autre des méthodes plonger()surchargées :
public
class
MaîtrePoisson {
public
static
void
main
(
String[] args) {
Poisson monPoisson =
new
Poisson
(
20
);
monPoisson.plonger
(
2
);
monPoisson.plonger
(
); // nouvelle méthode surchargée
monPoisson.plonger
(
97
);
monPoisson.plonger
(
3
);
monPoisson.dormir
(
);
}
}
Les constructeurs peuvent aussi être surchargés, mais l'un d'entre eux seulement est utilisé lorsqu'un objet est créé. Java appelle le constructeur qui a la bonne liste d'arguments. Par exemple, si tu ajoutes un constructeur sans argument à la classe Poisson, MaîtrePoisson peut en créer une instance par l'un des moyens suivants :
Poisson monPoisson =
new
Poisson
(
20
);
ou
Poisson monPoisson =
new
Poisson
(
);
XII-C. Lecture des entrées clavier▲
Dans cette section, tu vas apprendre comment un programme peut afficher des questions dans la fenêtre de commande et comprendre les réponses que l'utilisateur entre au clavier. Cette fois, nous allons retirer de la classe MaîtrePoisson toutes les valeurs codées en dur qu'il passait à la classe Poisson. Le programme va maintenant demander "De combien ?" et le poisson va plonger en fonction des réponses de l'utilisateur.
A ce stade, tu dois être plutôt à l'aise dans l'utilisation de la sortie standard (standard output) System.out. A propos, la variable out est du type java.io.OutputStream. Je vais maintenant t'expliquer comment utiliser l'entrée standard (standard input) System.in. Au fait, comme tu peux t'en douter, le type de données de la variable in est java.io.InputStream.
La version suivante de la classe MaîtrePoisson affiche une invite de commande (prompt) sur la console système et attend la réponse de l'utilisateur. Une fois que l'utilisateur a tapé un ou plusieurs caractères et appuyé sur la touche Entrée, Java place ces caractères dans l'objet InputStream pour les passer au programme.
import
java.io.IOException;
import
java.io.BufferedReader;
import
java.io.InputStreamReader;
public
class
MaîtrePoisson {
public
static
void
main
(
String[] args) {
Poisson monPoisson =
new
Poisson
(
20
);
String chaîneNombreDeMètres =
""
;
int
entierNombreDeMètres;
// Crée un lecteur de flux d'entrée connecté à
// System.in et le passe au lecteur à tampon
BufferedReader entréeStandard =
new
BufferedReader
(
new
InputStreamReader
(
System.in));
// Continue à plonger tant que l'utilisateur
// ne tape pas "Q"
while
(
true
) {
System.out.println
(
"Prêt à plonger. De combien ?"
);
try
{
chaîneNombreDeMètres =
entréeStandard.readLine
(
);
if
(
chaîneNombreDeMètres.equals
(
"Q"
)) {
// Sort du programme
System.out.println
(
"Au revoir !"
);
System.exit
(
0
);
}
else
{
// Convertit chaîneNombreDeMètres en entier
// et plonge de la valeur de entierNombreDeMètres
entierNombreDeMètres =
Integer.parseInt
(
chaîneNombreDeMètres);
monPoisson.plonger
(
entierNombreDeMètres);
}
}
catch
(
IOException e) {
e.printStackTrace
(
);
}
}
// Fin du while
}
// Fin de main
}
Un dialogue entre l'utilisateur et le programme MaîtrePoisson ressemble à ceci :
Prêt à plonger. De combien ?
14
Plongée de 14 mètres
Je suis à 34 mètres sous le niveau de la mer
Prêt à plonger. De combien ?
30
Plongée de 30 mètres
Je suis à 64 mètres sous le niveau de la mer
Prêt à plonger. De combien ?
Q
Au revoir !
En premier lieu, MaîtrePoisson crée un flux BufferedReader connecté à l'entrée standard System.in. Il affiche ensuite le message "Prêt à plonger. De combien ?" et la méthode readLine() met le programme en attente jusqu'à ce que l'utilisateur appuie sur Entrée. La valeur saisie est passée au programme sous forme de String, que MaîtrePoisson convertit en entier avant d'appeler la méthode plonger() de la classe Poisson.
Ces actions sont répétées en boucle jusqu'à ce que l'utilisateur tape la lettre Q pour quitter le programme. La ligne chaîneNombreDeMètres.equals("Q") compare la valeur de la variable de type String chaîneNombreDeMètres avec la lettre Q.
Nous avons utilisé la méthode readLine() pour lire en une seule fois toute la ligne entrée par l'utilisateur, mais il existe une autre méthode, System.in.read(), qui permet de traiter les entrées de l'utilisateur caractère par caractère.
XII-D. Compléments sur les paquetages Java ▲
Quand les programmeurs travaillent sur des projets de grande taille, contenant de nombreuses classes, ils les organisent généralement en différents paquetages (packages). Par exemple, un paquetage pourrait contenir toutes les classes qui affichent les fenêtres (écrans), alors qu'un autre contiendrait tous les récepteurs d'événements. Java aussi range ses classes dans des paquetages, tels que java.io pour les classes responsables des opérations d'entrée/sortie ou javax.swing pour les classes Swing.
Créons un nouveau projet Eclipse appelé Ping Pong. Ce projet organisera ses classes en deux paquetages : écrans et moteur. Crée la classe TablePingPong et entre le mot écrans dans le champ Package :
Appuie sur le bouton Fin et Eclipse génère un code qui inclut une ligne contenant le nom du paquetage.
package
écrans;
public
class
TablePingPong {
public
static
void
main
(
String[] args) {
}
}
A propos, si ta classe inclut une ligne avec le mot-clé package, tu n'as le droit d'écrire que des commentaires au-dessus de cette ligne.
Comme chaque paquetage est stocké dans un répertoire différent du disque, Eclipse crée le répertoire écrans et y place le fichier TablePingPong.java. Vérifie - il doit y avoir sur ton disque un répertoire c:\eclipse\plan de travail\Ping Pong\écrans, contenant les fichiers TablePingPong.java et TablePingPong.class.
Crée maintenant une autre classe, nommée MoteurPingPong, et indique moteur comme nom de paquetage. Le projet Ping Pong contient maintenant deux paquetages :
Puisque nos deux classes sont situées dans deux paquetages (et répertoires) différents, la classe TablePingPong ne peut voir la classe MoteurPingPong que si tu ajoutes une instruction import.
package
écrans;
import
moteur.MoteurPingPong;
public
class
TablePingPong {
public
static
void
main
(
String[] args) {
MoteurPingPong moteurJeu =
new
MoteurPingPong
(
);
}
}
Non seulement les paquetages Java t'aident-ils à mieux organiser tes classes, mais ils peuvent aussi être utilisés pour limiter l'accès à leurs classes par des "étrangers" installés dans d'autres paquetages.
XII-E. Niveaux d'accès▲
Les classes, méthodes et variables membres Java peuvent avoir les niveaux d'accès public, private, protected et package. Notre classe MoteurPingPong a le niveau d'accès public, ce qui signifie que n'importe quelle classe peut y accéder. Faisons une petite expérience : ôtons le mot-clé public de la déclaration de la classe MoteurPïngPong. La classe TablePingPong ne peut même plus compiler ; le message d'erreur MoteurPingPong ne peut pas être résolu ou ne correspond pas à un type signifie que la classe TablePingPong ne voit plus la classe MoteurPingPong.
Si aucun niveau d'accès n'est spécifié, la classe a un niveau d'accès package, c'est-à-dire qu'elle n'est accessible qu'aux classes du même paquetage.
De la même façon, si tu oublies de donner un accès public aux méthodes de la classe MoteurPingPong, TablePingPong se plaindra en disant que ces méthodes ne sont pas visibles. Tu verras comment les niveaux d'accès sont utilisés dans le prochain chapitre, en créant le jeu de ping pong.
Le niveau d'accès private est utilisé pour cacher les variables ou méthodes de la classe aux yeux du monde extérieur. Pense à une voiture : la plupart des gens n'ont aucune idée de tout ce qui se cache sous le capot ou de ce qui se passe quand le conducteur appuie sur la pédale de frein.
Examine l'exemple de code suivant - en Java, on peut dire que l'objet Voiture expose une seule méthode publique - freiner(), qui en interne peut appeler plusieurs autres méthodes qu'un conducteur n'a pas besoin de connaître. Par exemple, si le conducteur appuie trop fort sur la pédale, l'ordinateur de bord peut mettre en action des freins spéciaux anti-blocage. J'ai déjà dit auparavant que des programmes Java contrôlaient des robots aussi compliqués que ceux de la mission Mars Rovers, sans même parler des simples voitures.
public
class
Voiture {
// Cette variable privée ne peut être utilisée
// qu'à l'intérieur de cette classe
private
String conditionFreins;
// La méthode publique freiner() appelle des méthodes
// privées pour décider quels freins utiliser
public
void
freiner
(
int
pressionPédale) {
boolean
utiliserFreinsNormaux;
utiliserFreinsNormaux =
vérifierBesoinABS
(
pressionPédale);
if
(
utiliserFreinsNormaux ==
true
) {
utiliserFreinsNormaux
(
);
}
else
{
utiliserFreinsAntiBlocage
(
);
}
}
// Cette méthode privée ne peut être appelée
// qu'à l'intérieur de cette classe
private
boolean
vérifierBesoinABS
(
int
pression) {
if
(
pression >
100
) {
return
true
;
}
else
{
return
false
;
}
}
// Cette méthode privée ne peut être appelée
// qu'à l'intérieur de cette classe
private
void
utiliserFreinsNormaux
(
) {
// Code qui envoie un signal aux freins normaux
}
// Cette méthode privée ne peut être appelée
// qu'à l'intérieur de cette classe
private
void
utiliserFreinsAntiBlocage
(
) {
// Code qui envoie un signal aux freins anti-blocage
}
}
Le dernier mot-clé Java pour contrôler le niveau d'accès est protected. Si tu utilises ce mot-clé dans la signature d'une méthode, celle-ci est visible à l'intérieur de la classe, de ses sous-classes et des autres classes du même paquetage. Mais elle n'est pas utilisable par les classes indépendantes situées dans d'autres paquetages.
L'une des caractéristiques principales des langages orientés objet est appelée encapsulation, c'est-à-dire la capacité à cacher et protéger les éléments d'une classe.
Quand tu conçois une classe, cache les méthodes et les variables membres qui ne doivent pas être visibles de l'extérieur. Si les concepteurs de voitures ne masquaient pas une partie des contrôles de la mécanique, le conducteur devrait gérer des centaines de boutons, d'interrupteurs et de jauges.
Dans la section suivante, la classe Score masque ses attributs en les déclarant private.
XII-F. Retour sur les tableaux▲
Le programme EnregistreurScores du Chapitre 9 crée un tableau d'objets String pour stocker les noms et les scores des joueurs dans un fichier. Il est temps d'apprendre à utiliser des tableaux pour stocker tous types d'objets.
Cette fois, nous allons créer un objet représentant un score et lui donner des attributs tels que les nom et prénom du joueur, son score et la date de sa dernière partie.
La classe Score ci-dessous définit des méthodes d'accès en lecture et en écriture (getters et setters) pour chacun des ses attributs, qui sont déclarés privés. Bon, il n'est peut-être pas évident de comprendre pourquoi la classe appelante ne peut pas simplement affecter la valeur de l'attribut score comme ceci :
Score.score =
250
;
au lieu de :
Score.affecterScore
(
250
);
Essaie d'élargir ton horizon. Imagine que, plus tard, nous décidions que notre programme doive jouer un morceau de musique quand un joueur atteint le score de 500 ? Si la classe Score a une méthode affecterScore(), il suffit de modifier cette méthode en lui ajoutant le code qui vérifie le score et joue de la musique si nécessaire. La classe appelante appelle toujours de la même façon la version musicale de la méthode affecterScore(). Si la classe appelante affectait directement la valeur, elle devrait elle-même implanter les changements musicaux. Et si tu voulais réutiliser la classe Score dans deux programmes de jeu différents ? En utilisant la modification directe d'attributs, tu devrais implanter les changements dans deux classes appelantes, alors qu'une méthode d'affectation encapsule les changements qui sont immédiatement fonctionnels pour chaque classe appelante.
import
java.util.Date;
import
java.text.SimpleDateFormat;
public
class
Score {
private
String prénom;
private
String nom;
private
int
score;
private
Date dateDernièrePartie;
public
String lirePrénom
(
) {
return
prénom;
}
public
void
affecterPrénom
(
String prénom) {
this
.prénom =
prénom;
}
public
String lireNom
(
) {
return
nom;
}
public
void
affecterNom
(
String nom) {
this
.nom =
nom;
}
public
int
lireScore
(
) {
return
score;
}
public
void
affecterScore
(
int
score) {
this
.score =
score;
}
public
Date lireDateDernièrePartie
(
) {
return
dateDernièrePartie;
}
public
void
affecterDateDernièrePartie
(
Date
dateDernièrePartie) {
this
.dateDernièrePartie =
dateDernièrePartie;
}
// Concatène tous les attributs en une chaîne
// et y ajoute un caractère fin de ligne.
// Cette méthode est pratique, par exemple pour
// afficher toutes les valeurs d'un coup, comme ceci :
// System.out.println(myScore.toString());
// NDT : comme cette méthode redéfinit Object.toString(),
// tu es certain que la bonne représentation de Score
// est utilisée partout où Java en a besoin (c'est pour
// cela que nous ne l'avons pas appelée convertirEnString).
public
String toString
(
) {
String chaîneScore =
prénom +
" "
+
nom +
" "
+
score +
" "
+
SimpleDateFormat.
getDateInstance
(
).format
(
dateDernièrePartie) +
System.getProperty
(
"line.separator"
);
return
chaîneScore;
}
}
Le programme EnregistreurScores2 crée des instances de l'objet Score et affecte des valeurs à leurs attributs.
import
java.io.FileWriter;
import
java.io.BufferedWriter;
import
java.io.IOException;
import
java.util.Date;
public
class
EnregistreurScores2 {
/**
La méthode main exécute les actions suivantes :
1. Crée une instance de tableau
2. Crée les objets Score et les stocke dans le tableau
3. Ecrit les données de scores dans un fichier
*/
public
static
void
main
(
String[] args) {
FileWriter monFichier =
null
;
BufferedWriter tampon =
null
;
Date ceJour =
new
Date
(
);
Score scores[] =
new
Score[3
];
// Joueur n°1
scores[0
]=
new
Score
(
);
scores[0
].affecterPrénom
(
"Jean"
);
scores[0
].affecterNom
(
"Dupont"
);
scores[0
].affecterScore
(
250
);
scores[0
].affecterDateDernièrePartie
(
ceJour);
// Joueur n°2
scores[1
]=
new
Score
(
);
scores[1
].affecterPrénom
(
"Anne"
);
scores[1
].affecterNom
(
"Durand"
);
scores[1
].affecterScore
(
300
);
scores[1
].affecterDateDernièrePartie
(
ceJour);
// Joueur n°3
scores[2
]=
new
Score
(
);
scores[2
].affecterPrénom
(
"Eskil"
);
scores[2
].affecterNom
(
"Pemieufer"
);
scores[2
].affecterScore
(
190
);
scores[2
].affecterDateDernièrePartie
(
ceJour);
try
{
monFichier =
new
FileWriter
(
"c:
\\
scores2.txt"
);
tampon =
new
BufferedWriter
(
monFichier);
for
(
int
i =
0
; i <
scores.length; i++
) {
// Convertit chaque Score en String
// et l'écrit dans scores2.txt
tampon.write
(
scores[i].toString
(
));
System.out.println
(
"Ecriture des données de "
+
scores[i].lireNom
(
));
}
System.out.println
(
"Ecriture du fichier terminée"
);
}
catch
(
IOException e) {
e.printStackTrace
(
);
}
finally
{
try
{
tampon.flush
(
);
tampon.close
(
);
monFichier.close
(
);
}
catch
(
IOException e1) {
e1.printStackTrace
(
);
}
}
}
}
Si un programme essaie d'accéder à un élément du tableau dont l'indice est trop grand, par exemple ici scores[5].lireNom(), Java lève l'exception ArrayIndexOutOfBoundsException.
XII-G. Classe ArrayList▲
Le paquetage java.util contient des classes plutôt pratiques pour stocker plusieurs instances (des collections) d'objets en mémoire. Certaines des collections populaires de ce paquetage sont les classes ArrayList (liste stockée dans un tableau), Vector (vecteur), Hashtable et HashMap (deux sortes de tables de hachage) et List (liste). Je vais te montrer comment utiliser la classe java.util.ArrayList.
L'inconvénient des tableaux normaux est que tu dois connaître à l'avance le nombre d'éléments du tableau. Rappelle-toi, pour créer une instance de tableau, tu dois mettre un nombre entre les crochets :
String[] mesAmis =
new
String[5
];
La classe ArrayList n'a pas cette contrainte. Tu peux créer une instance de cette collection sans savoir combien d'objets il y aura : ajoute simplement de nouveaux éléments quand tu en as besoin.
Pourquoi utiliser des tableaux, alors, et ne pas utiliser systématiquement des ArrayList ? Malheureusement, rien n'est gratuit et il faut payer le prix du confort : ArrayList est un peu plus lent qu'un tableau normal et on ne peut y stocker que des objets, pas des nombres de type int.
Pour créer et remplir un objet ArrayList, il faut l'instancier, créer des instances des objets que tu souhaites y stocker, puis les ajouter à l'ArrayList en appelant sa méthode add(). Le petit programme ci-dessous remplit un ArrayList avec des objets de type String puis affiche le contenu de cette collection.
import
java.util.ArrayList;
public
class
DémoArrayList {
public
static
void
main
(
String[] args) {
// Crée et remplit un ArrayList
ArrayList amis =
new
ArrayList
(
);
amis.add
(
"Marie"
);
amis.add
(
"Anne"
);
amis.add
(
"David"
);
amis.add
(
"Rémi"
);
// Combien d'amis y a-t-il ?
int
nombreAmis =
amis.size
(
);
// Affiche le contenu de l'ArrayList
for
(
int
i =
0
; i <
nombreAmis; i++
) {
System.out.println
(
"L'ami(e) n°"
+
i +
" est "
+
amis.get
(
i));
}
}
}
Ce programme affiche les lignes suivantes :
L'ami(e) n°0 est Marie
L'ami(e) n°1 est Anne
L'ami(e) n°2 est David
L'ami(e) n°3 est Rémi
La méthode get() extrait d'un ArrayList l'élément situé à une position donnée. Puisqu'on peut stocker n'importe quel objet dans une collection, la méthode get() renvoie chaque élément comme un Object Java ; le programme a la responsabilité de convertir explicitement cet objet en un type de données approprié. Nous n'avons pas besoin de le faire dans l'exemple précédent uniquement parce que nous stockons des objets de type String dans la collection amis et que Java convertit automatiquement Object en String. Mais si tu stockes d'autres objets dans un ArrayList, par exemple des instances de la classe Poisson, le code correct pour ajouter et extraire un Poisson ressemble plutôt à celui du programme BocalAPoissons ci-dessous. Le programme crée une paire d'instances de la classe Poisson, affecte des valeurs à leurs attributs couleur, poids et profondeurCourante, puis les stocke dans l'ArrayList bocalAPoissons. Le programme extrait ensuite les objets de cette collection, convertit chacun d'entre eux en Poisson et affiche les valeurs de ses attributs.
import
java.util.ArrayList;
public
class
BocalAPoissons {
public
static
void
main
(
String[] args) {
ArrayList bocalAPoissons =
new
ArrayList
(
);
Poisson lePoisson;
Poisson unPoisson =
new
Poisson
(
20
);
unPoisson.couleur =
"Rouge"
;
unPoisson.poids =
1
;
bocalAPoissons.add
(
unPoisson);
unPoisson =
new
Poisson
(
10
);
unPoisson.couleur =
"Vert"
;
unPoisson.poids =
2
;
bocalAPoissons.add
(
unPoisson);
int
nombrePoissons =
bocalAPoissons.size
(
);
for
(
int
i =
0
; i <
nombrePoissons; i++
) {
lePoisson =
(
Poisson) bocalAPoissons.get
(
i);
System.out.println
(
"Attrapé le poisson "
+
lePoisson.couleur +
" qui pèse "
+
lePoisson.poids +
" livres. Profondeur : "
+
lePoisson.profondeurCourante);
}
}
}
Voici la sortie du programme BocalAPoissons :
Attrapé le poisson Rouge qui pèse 1.0 livres. Profondeur : 20
Attrapé le poisson Vert qui pèse 2.0 livres. Profondeur : 10
Maintenant que tu connais les niveaux d'accès Java, on peut modifier un peu les classes AnimalFamilier et Poisson. Des variables telles que age, couleur, poids et taille devraient être déclarées comme protected et la variable profondeurCourante devrait être private. Tu dois ajouter de nouvelles méthodes publiques, telles que lireAge() pour renvoyer la valeur de la variable age et affecterAge() pour affecter la valeur de cette variable.
Les programmeurs élégants ne permettent pas à une classe de modifier directement les propriétés d'une autre ; la classe doit fournir les méthodes qui modifient ses internes. C'est pourquoi la classe Score de la section précédente est conçue avec des variables private, qui peuvent être modifiées et lues avec les méthodes d'accès appropriées.
Dans ce chapitre, je t'ai présenté divers éléments et techniques Java qui semblent sans relation les uns avec les autres. Mais tous ces éléments sont fréquemment utilisés par les programmeurs Java professionnels. Après avoir effectué les exercices pratiques de ce chapitre, tu devrais mieux comprendre comment tous ces éléments fonctionnent ensemble.
XII-H. Autres lectures▲
1. Collections Java : http://java.sun.com/ (...) /intro/ 2. Classe ArrayList: http://java.sun.com/ (...) /ArrayList.html 3. Classe Vector: http://java.sun.com/ (...) /Vector.html 4. Classe Calendar: |
XII-I. Exercices▲
XII-J. Exercices pour les petits malins▲
Regarde en ligne comment s'utilise la classe Vector et essaie de créer un programme DémoVector similaire au programme DémoArrayList. |