Vous êtes sur la page 1sur 177

Universit e dAix-Marseille Facult e des Sciences

Le langage Java
Master CCI, I, BBSG, IMSA, etc.

Henri Garreta D epartement dInformatique & LIF

c H. Garreta, 2000-2013

` TABLE DES MATIERES

` TABLE DES MATIERES

Le langage Java
Henri Garreta
Universit e dAix-Marseille, Facult e des Sciences, Luminy Table des mati` eres
1 Introduction 1.1 Pratique eective de Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Consid erations lexicales 2.1 Jeu de caract` eres . . . 2.2 Commentaires . . . . . 2.3 Identicateurs . . . . . 2.4 Constantes litt erales . 7 7 9 9 9 9 10 11 11 11 12 12 13 13 13 13 14 14 15 16 17 18 19 21 22 22 23

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

3 Types 3.1 Les types de donn ees de Java . . . . . . . . . . . . . . . . . 3.2 Conversions entre types primitifs . . . . . . . . . . . . . . . 3.3 R ef erences . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 S emantique des valeurs et s emantique des r ef erences 3.3.2 R ef erence sur rien . . . . . . . . . . . . . . . . . . 3.3.3 Cas des param` etres des m ethodes . . . . . . . . . . . 3.4 Tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.1 D eclaration et initialisation . . . . . . . . . . . . . . 3.4.2 Acc` es aux el ements . . . . . . . . . . . . . . . . . . . 3.4.3 Tableaux ` a plusieurs indices . . . . . . . . . . . . . . 3.4.4 Tableaux initialis es et tableaux anonymes. . . . . . . 3.5 Conversions entre types tableaux ou classes . . . . . . . . . 3.6 Copie et comparaison des objets . . . . . . . . . . . . . . . 3.6.1 Copie . . . . . . . . . . . . . . . . . . . . . . . . . . 3.6.2 D enir la m ethode clone . . . . . . . . . . . . . . . 3.6.3 Comparaison . . . . . . . . . . . . . . . . . . . . . . 3.7 Cha nes de caract` eres . . . . . . . . . . . . . . . . . . . . . 3.7.1 Les classes String et StringBuffer . . . . . . . . . 3.7.2 Copie et comparaison des cha nes . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . .

4 Expressions et instructions 24 4.1 Rupture etiquet ee . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24


c H. Garreta, 2000-2013

` TABLE DES MATIERES

` TABLE DES MATIERES

5 Classes, paquets, chiers et r epertoires 5.1 Paquets et classes . . . . . . . . . . . . . . . . . . . . . 5.1.1 Les noms des paquets et linstruction package 5.1.2 Les noms des classes et linstruction import . . 5.2 Classes, chiers et r epertoires . . . . . . . . . . . . . . 5.2.1 Classes publiques et non publiques . . . . . . . 5.2.2 Point dentr ee dun programme. . . . . . . . . 5.2.3 O` u placer les chiers des classes ? . . . . . . . . 5.2.4 Comment distribuer une application Java ? . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

25 25 25 25 26 26 26 27 28 29 29 29 29 30 31 33 34 34 34 35 36 37 38 38 39 39 40 41 41 42 42 43 43 43 44 45 46 47 47 49 51 52 52 53 53 57 57 58 58 58 60 62 62 62 63 64 65

6 Les objets 6.1 Introduction : les langages orient es objets . . . . . . . . . . . . . . 6.2 Classes, variables et m ethodes . . . . . . . . . . . . . . . . . . . . . . 6.2.1 D eclaration des classes et des objets, instanciation des classes 6.2.2 Instances et membres dinstance . . . . . . . . . . . . . . . . 6.2.3 Membres de classe (membres statiques) . . . . . . . . . . . . 6.3 Surcharge des noms . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4 Contr ole de laccessibilit e . . . . . . . . . . . . . . . . . . . . . . . . 6.4.1 Membres priv es, prot eg es, publics . . . . . . . . . . . . . . . 6.4.2 Lencapsulation . . . . . . . . . . . . . . . . . . . . . . . . 6.5 Initialisation des objets . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.1 Constructeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.2 Membres constants (final) . . . . . . . . . . . . . . . . . . . 6.5.3 Blocs dinitialisation statiques . . . . . . . . . . . . . . . . . . 6.5.4 Destruction des objets . . . . . . . . . . . . . . . . . . . . . . 6.6 Classes internes et anonymes . . . . . . . . . . . . . . . . . . . . . . 6.6.1 Classes internes . . . . . . . . . . . . . . . . . . . . . . . . . . 6.6.2 Classes anonymes . . . . . . . . . . . . . . . . . . . . . . . . . 7 H eritage 7.1 Introduction : raner, abstraire . . . . . . . 7.2 Sous-classes et super-classes . . . . . . . . . . . 7.2.1 D enition de sous-classe . . . . . . . . . 7.2.2 Larbre de toutes les classes . . . . . 7.3 Red enition des m ethodes . . . . . . . . . . . . 7.3.1 Surcharge et masquage . . . . . . . . . . 7.3.2 Red enition des m ethodes . . . . . . . . 7.4 H eritage et constructeurs . . . . . . . . . . . . 7.5 Membres prot eg es . . . . . . . . . . . . . . . . 7.6 Le polymorphisme . . . . . . . . . . . . . . . 7.6.1 G en eralisation et particularisation . . . 7.6.2 Les m ethodes red enies sont virtuelles 7.6.3 M ethodes et classes nales . . . . . . . . 7.7 Abstraction . . . . . . . . . . . . . . . . . . . 7.7.1 M ethodes abstraites . . . . . . . . . . . 7.7.2 Classes abstraites . . . . . . . . . . . . . 7.7.3 Interfaces . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . .

8 Exceptions 8.1 Interception des exceptions . . . . . . . . . . . . . . . . . . 8.2 Lancement des exceptions . . . . . . . . . . . . . . . . . . . 8.2.1 Hi erarchie des exceptions . . . . . . . . . . . . . . . 8.2.2 D eclaration des exceptions lanc ees par une m ethode 8.3 Assert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Quelques classes utiles 9.1 Nombres et outils math ematiques . . . . . . . 9.1.1 Classes-enveloppes des types primitifs 9.1.2 Fonctions math ematiques . . . . . . . 9.1.3 Nombres en pr ecision innie . . . . . . 9.2 Collections et algorithmes . . . . . . . . . . . 4

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

c H. Garreta, 2000-2013

` TABLE DES MATIERES

` TABLE DES MATIERES

9.3 9.4

9.5

9.2.1 Collections et tables associatives . 9.2.2 It erateurs . . . . . . . . . . . . . . 9.2.3 Quelques m ethodes des collections 9.2.4 Algorithmes pour les collections . . 9.2.5 Algorithmes pour les tableaux . . . R eexion et manipulation des types . . . Entr ees-sorties . . . . . . . . . . . . . . . 9.4.1 Les classes de ux . . . . . . . . . 9.4.2 Exemples . . . . . . . . . . . . . . 9.4.3 Analyse lexicale . . . . . . . . . . . 9.4.4 Mise en forme de donn ees . . . . . 9.4.5 Repr esentation des dates . . . . . 9.4.6 La s erialisation . . . . . . . . . . . Expressions r eguli` eres . . . . . . . . . . . 9.5.1 Principe . . . . . . . . . . . . . . . 9.5.2 Exemples . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . .

65 69 70 71 73 74 76 76 79 82 84 87 88 90 90 90 94 94 94 96 96 97 98 100 100 101 103 105 106 107 109 110 114 115 115 116 118 119 120 121 122 122 123 123 125 125 125 126 128 131 133 134 136 137 138 143 144 145 147 5

10 Threads 10.1 Cr eation et cycle de vie dun thread . . . . . . . . . 10.1.1 D eclaration, cr eation et lancement de threads 10.1.2 Terminaison dun thread . . . . . . . . . . . . 10.2 Synchronisation . . . . . . . . . . . . . . . . . . . . . 10.2.1 Sections critiques . . . . . . . . . . . . . . . . 10.2.2 M ethodes synchronis ees . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

11 Interfaces graphiques 11.1 JFC = AWT + Swing . . . . . . . . . . . . . . . . . . . . . 11.2 Le haut de la hi erarchie . . . . . . . . . . . . . . . . . . . . . 11.3 Le point de d epart : JFrame et une application minimale. . . 11.4 Le thread de gestion des ev enements . . . . . . . . . . . . . . enements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.5 Ev 11.5.1 Exemple : d etecter les clics de la souris. . . . . . . . . 11.5.2 Adaptateurs et classes anonymes . . . . . . . . . . . . 11.5.3 Principaux types d ev enements . . . . . . . . . . . . . 11.5.4 Exemple : fermeture prudente du cadre principal . . 11.6 Peindre et repeindre . . . . . . . . . . . . . . . . . . . . . . . 11.6.1 La m ethode paint . . . . . . . . . . . . . . . . . . . . 11.6.2 Les classes Graphics et Graphics2D . . . . . . . . . . 11.6.3 Exemple : la mauvaise mani` ere de dessiner . . . . . . 11.6.4 Exemple : la bonne mani` ere de dessiner. . . . . . . . . 11.7 Gestionnaires de disposition . . . . . . . . . . . . . . . . . . . 11.7.1 FlowLayout . . . . . . . . . . . . . . . . . . . . . . . . 11.7.2 BorderLayout . . . . . . . . . . . . . . . . . . . . . . 11.7.3 GridLayout . . . . . . . . . . . . . . . . . . . . . . . . 11.7.4 GridBagLayout . . . . . . . . . . . . . . . . . . . . . . 11.7.5 Exemple : un panneau muni dun GridBagLayout . . 11.7.6 Exemple : imbrication de gestionnaires de disposition 11.7.7 Bordures . . . . . . . . . . . . . . . . . . . . . . . . . 11.8 Composants pr ed enis . . . . . . . . . . . . . . . . . . . . . . 11.8.1 Exemple : mise en place et emploi de menus . . . . . . 11.8.2 Exemple : construire une boite de dialogue . . . . . . 11.8.3 Exemple : saisie de donn ees . . . . . . . . . . . . . . . 11.8.4 Exemple : choisir un chier . . . . . . . . . . . . . . . 11.8.5 Exemple : une table pour acher des donn ees . . . . . 11.8.6 Exemple : s election et modication dans une table . . 11.9 Le mod` ele MVC (Mod` ele-Vue-Controleur) . . . . . . . . . . . 11.9.1 Exemple : les vues arborescentes (JTree) . . . . . . . 11.10Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.10.1 Exemple : utiliser des ic ones . . . . . . . . . . . . . . . 11.10.2 Exemple : charger une image depuis un chier . . . . 11.10.3 Exemple : construire une image pixel par pixel . . . .
c H. Garreta, 2000-2013

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

` TABLE DES MATIERES

` TABLE DES MATIERES

12 Java 5 12.1 Types enum er es . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.1.1 Enums . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.1.2 M ethodes des types enum er es . . . . . . . . . . . . . . . 12.1.3 Aiguillages command es par des types enum er es . . . . . 12.1.4 Dictionnaires et ensembles bas es sur des types enum er es 12.2 Emballage et d eballage automatiques . . . . . . . . . . . . . . . 12.2.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2.2 Op erations d eriv ees et autres cons equences . . . . . . . 12.2.3 La r esolution de la surcharge en Java 5 . . . . . . . . . 12.3 Quelques outils pour simplier la vie du programmeur . . . . . 12.3.1 Importation de membres statiques . . . . . . . . . . . . 12.3.2 Boucle for am elior ee . . . . . . . . . . . . . . . . . . . . 12.3.3 M ethodes avec une liste variable darguments . . . . . . 12.3.4 Entr ees-sorties simpli ees : printf et Scanner . . . . . 12.4 Annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.4.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.4.2 Exploitation des annotations . . . . . . . . . . . . . . . 12.4.3 Annotations pr ed enies . . . . . . . . . . . . . . . . . . 12.4.4 M eta-annotations . . . . . . . . . . . . . . . . . . . . . . 12.5 G en ericit e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.5.1 Classes et types param etr es . . . . . . . . . . . . . . . . 12.5.2 Types bruts . . . . . . . . . . . . . . . . . . . . . . . . . 12.5.3 Types param etr es et jokers . . . . . . . . . . . . . . . . 12.5.4 Limitations de la g en ericit e . . . . . . . . . . . . . . . . 12.5.5 M ethodes g en eriques . . . . . . . . . . . . . . . . . . . . Index

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

149 149 149 150 151 151 152 152 153 154 155 155 156 158 159 161 161 163 164 164 165 166 168 168 170 171 173

e le 28 janvier 2013 (premi` Edit ere edition : janvier 2000).

henri.garreta@univ-amu.fr

La plus r ecente version de ce document peut etre t el echarg ee ` a ladresse http://henri.garreta.perso.luminy.univmed.fr/Polys/PolyJava.pdf

c H. Garreta, 2000-2013

INTRODUCTION

Introduction

Ce polycopi e est le support de plusieurs cours de Java donn es ` a la Facult e des Sciences de Luminy. Tr` es succinct, il ne remplace pas la consultation douvrages plus approfondis et illustr es, parmi lesquels 1 : pour d ebuter : Patrick Niemeyer & Jonathan Knudsen Introduction ` a Java, 2 eme edition OReilly, 2002 deuxi` eme lecture : Ian Darwin Java en action OReilly, 2002

Ce texte sadresse ` a des lecteurs connaissant le langage C. De nombreux el ements importants de Java, comme les expressions, les instructions, lappel des fonctions, etc., ne sont pas expliqu es ici, tout simplement parce quils sont r ealis es en Java comme en C. En outre, lexpos e nest pas progressif : chaque notion est introduite comme si les autres concepts du langage avaient d ej` a et e trait es. Cela rend la lecture initiale de ce document plus eprouvante, mais la consultation ult erieure plus ecace. Ces notes traitent de la version courante de la plate-forme Java (le langage et ses biblioth` eques ocielles) et de son environnement de d eveloppement, appel es d esormais respectivement JavaTM Platform Standard Edition 7 et JavaTM SE Development Kit 7 (le num ero de version 1.7.x appara t parfois ` a la place de 7). Cependant, pour la clart e des id ees, nous avons introduit la plupart des el ements comme il convenait de le faire a l ` epoque de Java 1.4 (par exemple, lh eritage et le polymorphisme sont dabord expliqu es sans mentionner ni la g en ericit e ni lemballage automatique). Les principales nouveaut es introduites lors du passage de Java 1.4 ` a Java 5 sont pr esent ees ` a la section 12. Dautres nouveaut es ont et e introduites par la suite, mais elles d epassent lambition de ce polycopi e. Un document est rigoureusement indispensable pour programmer en Java : la documentation en ligne de lAPI (Interface du Programmeur dApplications ). Cest un chier hypertexte qui contient tout ce quil faut savoir ` a propos de tous les paquets, interfaces, classes, variables et m ethodes de la plate-forme Java. On peut le consulter en ligne et le t el echarger ` a ladresse http://java.sun.com/javase/6/docs/api/ Enn, un excellent document pour apprendre Java est le tutoriel ociel, quon peut consulter en ligne ou t el echarger ` a ladresse http://java.sun.com/tutorial/

1.1

Pratique eective de Java

Dans cette section nous supposons que vous travaillez sur un syst` eme Windows, Linux, Solaris ou Mac OS X. Certains des produits mentionn es ici ont egalement des versions pour des syst` emes plus condentiels. Pour pratiquer le langage Java, cest-` a-dire pour saisir, compiler et ex ecuter vos programmes, il vous faut un environnement de d eveloppement Java, comportant un compilateur, une machine Java et des biblioth` eques au moins la biblioth` eque standard. Vous obtenez tout cela en installant le JDK (Java Development Kit ), que vous pouvez t el echarger gratuitement depuis le site de Sun, ` a ladresse http://java.sun.com/javase/ downloads. Vous pouvez utiliser nimporte quel editeur de textes pour saisir vos programmes. Supposons que vous ayez tap e le texte de la c el` ebre classe Bonjour : public class Bonjour { public static void main(String[] args) { System.out.println("Bonjour ` a tous!"); } } Le chier dans lequel vous avez enregistr e ce texte doit sappeler Bonjour.java. Vous en obtenez la compilation en tapant la commande javac Bonjour.java Si le programme est correct, la compilation se d eroule sans produire aucun message. Vous lancez alors lex ecution de votre programme (pour obtenir lachage du texte Bonjour ` a tous ! ) en tapant la commande java Bonjour Notez bien qu` a la commande javac on donne un nom de chier (Bonjour.java ), tandis qu` a la commande java on doit donner un nom de classe (Bonjour ).
1. H elas, les editions OReilly France ont et e ferm ees d enitivement (cf. http://www.oreilly.fr/)

c H. Garreta, 2000-2013

1.1

Pratique eective de Java

INTRODUCTION

Quel que soit le syst` eme dexploitation que vous utilisez, vous pouvez vous constituer un environnement de travail plus agr eable en installant le JDK puis un petit editeur de textes orient e Java. Vous en trouverez plusieurs sur le web, par exemple jEdit, ` a ladresse http://www.jedit.org/. Vous obtenez un confort incomparablement sup erieur si, apr` es JDK, vous installez Eclipse, un puissant IDE 2 avec de nombreuses fonctionnalit es pour aider ` a la programmation en Java, telles que la compl etion automatique des expressions, la compilation au fur et ` a mesure de la frappe, la suggestion de la mani` ere de corriger les erreurs, etc. Vous pouvez librement t el echarger Eclipse ` a ladresse http://www.eclipse.org/ Dautres IDE extr emement bien faits, notamment pour programmer des interfaces graphiques rien quen jouant de la souris 3 4 , et gratuits : JBuilder Foundation, autrefois d evelopp e par Borland (http: //www.embarcadero.com/) ou, surtout, NetBeans, d evelopp e par Sun, puis Oracle (http://netbeans.org). Pour un tour dhorizon des IDE et RAD 5 Java, voyez http ://java.developpez.com/outils/edi/.

2. IDE : Integrated Development Environment 3. Si vous d ebutez en Java nous vous d econseillons de commencer par l` a. 4. Notez que, depuis sa version indigo (juin 2011), eclipse permet egalement la programmation dinterfaces graphiques ` a la souris 5. RAD : Rapid Application Development

c H. Garreta, 2000-2013

CONSIDERATIONS LEXICALES

2
2.1

Consid erations lexicales


Jeu de caract` eres

Java utilise le codage des caract` eres UTF-16, une impl ementation de la norme Unicode , dans laquelle chaque caract` ere est repr esent e par un entier de 16 bits, ce qui ore 65 536 possibilit es au lieu des 128 (ASCII) ou 256 (Latin-1) impos es par dautres langages de programmation. Il y a donc de la place pour la plupart des alphabets nationaux ; en particulier, tous les caract` eres fran cais y sont repr esent es sans cr eer de conit avec des caract` eres dautres langues. Cela vaut pour les donn ees manipul ees par les programmes (caract` eres et cha nes) et aussi pour les programmes eux-m emes. Il est donc possible en Java de donner aux variables et aux m ethodes des noms accentu es. Mais on ne vous conseille pas dutiliser cette possibilit e, car vous n etes jamais ` a labri de devoir un jour consulter ou modier votre programme ` a laide dun editeur de textes qui ne supporte pas les accents.

2.2

Commentaires
int nbLignes; // nombre de variables du syst` eme

Il y a trois sortes de commentaires. Dabord, un texte compris entre // et la n de la ligne :

Ensuite, un texte compris entre /* et */, qui peut s etendre sur plusieurs lignes : /* Recherche de lindice ik du "pivot maximum" c.-` a-d. tel que k <= ik < nl et a[ik][k] = max { |a[k][k]|, ... |a[nl - 1][k]| } */ Enn, cas particulier du pr ec edent, un texte compris entre /** et */ est appel e commentaire de documentation et est destin e` a loutil javadoc qui lexploite pour fabriquer la documentation dune classe ` a partir de son texte source 6 . Cela ressemble ` a ceci (un tel commentaire est associ e` a l el ement, ici une m ethode, quil pr ec` ede) : /** * R esolution dun syst` eme lin eaire * * @param a Matrice du syst` eme * @param x Vecteur solution du syst` eme * @return <tt>true</tt> si la matrice est inversible, <tt>false</tt> sinon. * @author Henri G. */ public boolean resolution(double a[][], double x[]) { ...

2.3

Identicateurs

Les r` egles de formation des identicateurs sont les m emes que dans le langage C, compte tenu des remarques du 2.1. La note Java Code Conventions 7 fait les recommandations suivantes ` a propos de la mani` ere de nommer les entit es des programmes : 1. Les di erents identicateurs, s epar es par des points, qui forment un nom de paquet sont ecrits principalement en minuscules, surtout le premier : java.awt.event, monprojet.mesoutils. 2. Le nom dune classe ou dune interface est fait dun mot ou de la concat enation de plusieurs mots. Chacun commence par une majuscule, y compris le premier : Point, AbstractListModel, ListeDeNombres, etc. 3. Les noms des m ethodes commencent par une minuscule. Lorsquils sont form es par concat enation de mots, chacun sauf le premier commence par une majuscule : toString(), vitesseDuVent(...), etc. 4. La m eme r` egle vaut pour les noms des variables, aussi bien les variables de classe et dinstance que les arguments et les variables locales des m ethodes : i, nombreDeMembres, etc. 5. Enn, les constantes de classe (cest-` a-dire les variables static final) sont ecrites de pr ef erence en majuscules : Integer.MAX_VALUE, TextField.LEFT_ALIGNMENT, etc.
6. Par exemple, la documentation en ligne de lAPI, ce gigantesque document hypertexte qui est le compagnon ins eparable de tout programmeur Java, est automatiquement produit au moyen de javadoc ` a partir des chiers sources de la biblioth` eque standard. 7. On peut t el echarger cette note depuis le site http://java.sun.com/docs/codeconv/

c H. Garreta, 2000-2013

2.4

Constantes litt erales

CONSIDERATIONS LEXICALES

2.4

Constantes litt erales

Les r` egles pour l ecriture des constantes sont les m emes quen C, avec les additions suivantes : 1. Caract` eres . Les caract` eres non imprimables peuvent etre repr esent es aussi par la s equence \uxxxx, o` u xxxx sont les quatre chires hexad ecimaux du code num erique du caract` ere. Par exemple, la cha ne suivante comporte les quatre caract` eres A, espace (code 32, ou 20 en hexad ecimal), B et ~ n (code 241, ou F1 en hexad ecimal) : "A\u0020B\u00F1" // la cha^ ne de quatre caract` eres "A B~ n"

2. Entiers . Une constante litt erale enti` ere est suppos ee etre du type int, cest-` a-dire cod ee sur 32 bits, sauf si elle est trop grande pour etre repr esent ee dans ce type ; elle appartient alors au type long. La lettre L ou l indique que la constante doit etre consid er ee comme appartenant au type long et cod ee sur 64 bits, m eme si sa valeur est petite. Exemple : 1234 1234L // une valeur du type int // une valeur du type long

Dans linitialisation dune variable de type long par une valeur de type int le compilateur ins` ere automatiquement la conversion n ecessaire. On peut alors se demander dans quelle circonstance on est g en e par le fait quune valeur enti` ere soit consid er ee int au lieu de long. Le probl` eme r eside le plus souvent dans lincapacit e de repr esenter les r esultats des op erations. Par exemple, laectation long u = 4000000 * 6000000; // ERREUR (d ebordement de la muliplication) est certainement incorrecte, car 4000000 et 6000000 seront consid er es de type int, et donc la multiplication et son r esultat aussi ; or ce r esultat ne peut pas etre repr esent e dans les 32 bits dun entier (voyez le tableau 1, page 11). Bien entendu, que ce r esultat soit ensuite aect e` a une variable de type long ne le rend pas juste. De plus, sagissant dun d ebordement en arithm etique enti` ere, aucune erreur ne sera signal ee ni ` a la compilation ni ` a lex ecution (mais le r esultat sera faux). Pour corriger ce probl` eme il sut placer lop eration et son r esultat dans le type long ; ` a cause de la r` egle du plus fort 8 , il sut pour cela quun des op erandes le soit : long u = 4000000L * 6000000; // OK

3. Flottants . Une constante ottante (cest-` a-dire un nombre comportant un point et/ou un exposant, comme 1.5, 2e-12 ou -0.54321E3) repr esente une valeur du type double. Les suxes f ou F peuvent etre utilis es pour pr eciser le type de ce qui est ecrit. Ainsi, une simple aectation telle que float x = 1.5; float x = 1.5f; On peut aussi laisser la constante etre du type float et en demander explicitement la conversion : float x = (float) 1.5; 4. Bool eens . Le type boolean comporte deux valeurs, repr esent ees par les constantes litt erales suivantes, qui sont aussi des mots r eserv es : false true // la valeur bool eenne faux // la valeur bool eenne vrai // ERREUR (discordance de types) est signal ee comme une erreur. Correction :

8. Grosso modo cette r` egle dit que si les deux op erandes dune op eration ne sont pas de m eme type alors le plus fort (c.-` a-d. le plus etendu, ou le plus pr ecis, ou un ottant face ` a un entier, etc.) provoque la conversion vers son type de lautre op erande et le placement dans ce type de lop eration et de son r esultat. Cette r` egle sapplique dans la grande majorit e des op erations binaires.

10

c H. Garreta, 2000-2013

TYPES

3
3.1

Types
Les types de donn ees de Java
Les types des donn ees manipul ees par les programmes Java se r epartissent en deux cat egories : les types primitifs, les objets, cest-` a-dire les tableaux et les classes. La table 1 r ecapitule ce quil faut savoir sur les huit types primitifs. Table 1 Les types primitifs de Java Type byte short int long description Octet Entier court Entier Entier long taille ensemble de valeurs Nombres entiers 8 bits de 128 ` a 127 16 bits de 32 768 ` a 32 767 32 bits de 2 147 483 648 ` a 2 147 483 647 64 bits de 263 ` a 263 1 Nombres ottants de 3, 402823510+38 ` a 1, 41045 , 32 bits 0 et de 1, 41045 ` a 3, 402823510+38 de 1, 797693134862315710+308 64 bits a 4, 910324 , 0 et de 4, 910324 ` a 1, 797693134862315710+308 ` Autres types 16 bits Tous les caract` eres Unicode 1 bit false, true val. init.

float

Flottant simple pr ecision

0.0

double

Flottant double pr ecision

char boolean

Caract` ere Valeur bool eenne

\u0000 false

On notera que : tous les types entiers sont sign es (cest-` a-dire repr esentent des ensembles contenant des nombres positifs et n egatifs), portabilit e oblige, on na pas reproduit en Java la bourde consistant ` a laisser la taille des int ` a lappr eciation de chaque compilateur.

3.2

Conversions entre types primitifs

La question de la compatibilit e et de la convertibilit e entre expressions de types primitifs est r egl ee en Java selon un petit nombre de principes simples : 1. Toute valeur dun type num erique est convertible vers tout autre type num erique, selon les modalit es expliqu ees ci-apr` es. 2. Les conversions entre types num eriques sans risque de perte dinformation (cest-` a-dire : entier ou caract` ere vers entier de taille sup erieure, ottant vers ottant de taille sup erieure, entier ou caract` ere vers ottant) sont faites, ` a la compilation et ` a lex ecution, sans requ erir aucune indication particuli` ere. Par exemple, si les variables qui y gurent ont les types que leurs noms sugg` erent, les aectations suivantes ne soul` event le moindre probl` eme, ni ` a la compilation ni ` a lex ecution : unInt = unChar; unDouble = unFloat; unFloat = unInt; 3. Les conversions avec risque de perte dinformation (cest-` a-dire : entier vers entier de taille inf erieure, ottant vers ottant de taille inf erieure, ottant vers entier) sont refus ees par le compilateur : unByte = unInt; // ERREUR

sauf si le programmeur a explicitement utilis e lop erateur de transtypage (ou cast operator ) : unByte = (byte) unInt; // Ok

Attention. Une expression comme la pr ec edente est plac ee sous la responsabilit e du programmeur, seul capable de garantir que la valeur de unInt pourra, au moment de laectation ci-dessus, etre repr esent ee dans une variable de type byte. Cette condition ne peut pas etre v eri ee ` a la compilation
c H. Garreta, 2000-2013

11

3.3

R ef erences

TYPES

et elle ne lest pas non plus ` a lex ecution. Cela peut conduire ` a des troncations inattendues, non signal ees, et donc ` a des r esultats absurdes. Par exemple, le programme suivant ache la valeur 1 : int unInt = 257; byte unByte = (byte) unInt; System.out.println(unByte); // DANGER

4. Puisque les caract` eres sont repr esent es par des nombres, le type char est consid er e comme num erique, pour ce qui nous occupe ici. Cependant, la conversion de nimporte quel type num erique vers le type char est consid er ee comme susceptible dentra ner une perte de pr ecision ; cela oblige le programmeur a utiliser lop ` erateur de transtypage. 5. La conversion dune expression bool eenne vers un type num erique, ou r eciproquement, est ill egale et rejet ee par le compilateur. Les expressions ` a la mode de C suivantes sont donc erron ees en Java : if (unInt) ... unInt = (x < y); // ERREUR (n ecessite une conversion int boolean) // ERREUR (n ecessite une conversion boolean int)

Bien entendu, ces conversions peuvent etre obtenues facilement : conversion bool een entier : (unBooleen ? 1 : 0) conversion nombre bool een : (unNombre != 0)

3.3
3.3.1

R ef erences
S emantique des valeurs et s emantique des r ef erences

Les expressions de types primitifs ont la s emantique des valeurs . Cela signie que si e est une expression dun type primitif T, alors ` a tout endroit 9 o` u elle gure e repr esente une valeur du type T. Par exemple, si unInt est une variable enti` ere contenant la valeur 12, alors les trois expressions 12, unInt et unInt/4 + 9 ont la m eme signication : la valeur enti` ere 12. Notez que des trois expressions 12, unInt et unInt/4 + 9, une seule est associ ee ` a un emplacement dans la m emoire (la seconde). Si une expression a la s emantique des valeurs elle nest pas forc ement un renvoi ` a un objet existant dans la m emoire. Tous les autres types de Java, cest-` a-dire les tableaux et les classes, ont la s emantique des r ef erences . Cela veut dire quune expression dun type tableau ou classe est, en toute circonstance, une r ef erence sur un objet existant dans la m emoire 10 .
unInt 12 unPoint 10 20

Figure 1 S emantique des valeurs et s emantique des r ef erences On peut voir une r ef erence comme un pointeur 11 g er e de mani` ere interne par Java. Par exemple, si Point est une classe form ee de deux entiers x et y (les coordonn ees dun point) : class Point { int x, y; ... } et si unPoint est une variable de type Point correctement initialis ee : Point unPoint = new Point(10, 20); alors il convient de se repr esenter la variable unPoint et sa valeur comme le montre la gure 1. Bien noter quen Java aucun signe ne rappelle, lors de lemploi dune expression de type r ef erence, quil sagit dune sorte de pointeur (cest-` a-dire, on nutilise pas les op erateurs * ou -> de C). Puisque les objets sont toujours acc ed es par r ef erence, une expression comme
9. Comme dans tous les langages qui ont la notion daectation, il y a une exception : plac ee au membre gauche dune aectation, une expression ne repr esente pas une valeur mais un emplacement de la m emoire. 10. Plus pr ecis ement, les r ef erences sont des renvois ` a la heap, cest-` a-dire la partie de la m emoire dans laquelle se font les allocations dynamiques (par new, le moyen de cr eer un tableau ou un objet). 11. Attention, abus de langage ! Imaginer un pointeur est sans doute une bonne mani` ere dappr ehender une r ef erence, mais il ne faut pas oublier quen Java on sinterdit de parler de pointeurs, car le programmeur nest pas cens e conna tre les d etails du proc ed e par lequel Java d esigne de mani` ere interne les objets quil cr ee dans la m emoire.

12

c H. Garreta, 2000-2013

TYPES

3.4

Tableaux

unPoint.x est sans ambigu t e ; elle signie : le champ x de lobjet r ef erenc e par unPoint. 3.3.2 R ef erence sur rien

La valeur particuli` ere null indique quune variable dun type r ef erence nest pas une r ef erence ` a un objet valide. Cest la valeur quil convient de donner ` a une telle variable lorsque lobjet r ef erenc e nexiste pas encore, ou bien lorsque la variable a cess e d etre utile en tant que r ef erence sur un objet : Point unPoint = null; // ... // unPoint = new Point(10, 20); ... // unPoint = null; ... // d eclaration et initialisation de unPoint ici, unPoint ne repr esente pas un objet valide ici on peut travailler avec lobjet unPoint a nouveau, unPoint nest pas un objet valide `

Le compilateur se charge dinitialiser ` a null les variables dinstance et de classe dun type objet qui nont pas dinitialisation explicite. Les variables locales ne sont pas initialis ees 12 . 3.3.3 Cas des param` etres des m ethodes

Les explications pr ec edentes sont valables pour toutes sortes dexpressions, quels que soient les contextes o` u elles apparaissent (sauf les membres gauches des aectations, qui echappent ` a cette discussion). Cela vaut en particulier pour les param` etres eectifs des appels des m ethodes ; par cons equent : un param` etre dun type est pass e par valeur : lors de lappel de la m ethode, la valeur du param` etre eectif est copi ee dans le param` etre formel correspondant, qui est une variable locale de la m ethode ; en particulier, si un tel param` etre eectif est une variable, lappel de la m ethode ne pourra pas en changer la valeur, quoi quelle fasse au param` etre formel correspondant ; un param` etre dun type tableau ou classe est pass e par r ef erence 13 : lors de lappel de la m ethode, le param` etre formel est initialis e avec une r ef erence sur le tableau ou lobjet que repr esente le param` etre eectif ; il en d ecoule que le tableau ou lobjet en question pourra etre r eellement modi e par les actions que la m ethode fera sur le param` etre formel.

3.4
3.4.1

Tableaux
D eclaration et initialisation

Tous les tableaux utilis es en Java sont des tableaux dynamiques. Cela veut dire que le nombre d el ements : nest pas un el ement constitutif du type du tableau et na pas besoin dappara tre dans sa d eclaration, nest pris en compte quau moment de lex ecution du programme, m eme sil est connu pendant la compilation. Il y a deux syntaxes rigoureusement equivalentes pour d eclarer un tableau tab dont les el ements sont, par exemple, des int : int tab[]; et int[] tab; // tab d esigne un tableau de int Dans lun et lautre cas, la variable tab ainsi d eclar ee est une r ef erence et, pour le moment, elle ne r ef erence rien. Si les expressions pr ec edentes sont la d eclaration dune variable dinstance ou de classe, tab aura et e initialis ee avec la valeur null. Sil sagit de la d eclaration dune variable locale, tab est ind etermin ee et il aurait probablement et e plus sage de la compl eter par une initialisation explicite, comme : int[] tab = null; // tab d esigne un tableau de int // tab d esigne un tableau de int

Le tableau lui-m eme commence eectivement ` a exister lors de lappel de lop erateur new : tab = new int[nombreDeComposantes ];
12. Les variables locales ne sont pas initialis ees mais toute utilisation dune variable locale susceptible de ne pas avoir et e initialis ee est d etect ee par le compilateur et signal ee comme une erreur. 13. En toute rigueur on peut dire que le passage dun objet ou dun tableau comme param` etre dune m ethode se traduit par le passage par valeur de la r ef erence ` a lobjet ou au tableau en question.

c H. Garreta, 2000-2013

13

3.4

Tableaux

TYPES

o` u nombreDeComposantes est une expression, dun type entier, qui d enit la taille du tableau. Note. On peut joindre dans la m eme expression la d eclaration de la variable et la cr eation du tableau correspondant : int[] tab = new int[nombreDeComposantes ]; cela est plus commode, car il y a moins de choses ` a ecrire, et plus able, car on elimine la p eriode pendant laquelle la variable existe sans r ef erencer un tableau. En g en eral cest faisable, car Java permet d ecrire les d eclarations l` a o` u on veut. 3.4.2 Acc` es aux el ements

Une fois le tableau cr e e, on acc` ede ` a ses composantes en utilisant la m eme notation quen C : tab[i ] o` u i est une expression de type entier 14 . Pour que lexpression ci-dessus soit l egitime il faut et il sut que 0 i < nombreDeComposantes. Autrement dit, les el ements du tableau pr ec edent sont t[0], t[1], ... t[nombreDeComposantes 1] Le sch ema de la gure 2 est la bonne mani` ere de se repr esenter lacc` es tab[i ] :

+i ... tab tab[0] tab[i] tab[N-1]

Figure 2 Un tableau de N el ements Taille effective dun tableau. Lexpression unTableau .length permet de conna tre le nombre d el ements dun tableau. Cela est bien utile pour ecrire des traitements de tableaux dont la taille est inaccessible lors de la compilation. Par exemple, le programme suivant ache les arguments ecrits sur la ligne de commande (` a la suite des deux mots java ArgumentsLigneCommande) quel que soit leur nombre : class ArgumentsLigneCommande { public static void main(String[] args) { for (int i = 0; i < args.length; i++) System.out.println(args[i]); } } le de lindice. Lors de lacc` Contro es ` a un el ement dun tableau, Java contr ole toujours la validit e de lindice. Autrement dit, lors de l evaluation dune expression comme tab[i] les deux erreurs possibles les plus fr equentes sont d etect ees et d eclenchent une exception : NullPointerException, pour indiquer que tab = null, cest-` a-dire que la variable tab nest pas une r ef erence valide (en clair, le plus souvent : la variable tab a bien et e d eclar ee, mais le tableau correspondant na pas encore et e cr e e), ArrayIndexOutOfBoundsException, pour indiquer que la condition 0 i < tab.length nest pas satisfaite. 3.4.3 Tableaux ` a plusieurs indices

Les tableaux ` a plusieurs indices sont dynamiques eux aussi. A titre dexemple, examinons le cas des matrices (tableaux ` a deux indices). Les d eclarations suivantes sont tout ` a fait equivalentes : int mat[][]; int[] mat[]; int[][] mat; // mat d esigne un tableau de int ` a deux indices // " " " " " " // " " " " " "

Ces trois expressions introduisent mat comme une variable de type tableau ` a deux indices de int. On peut les lire mat est un tableau-` a-un-indice de tableaux-` a-un-indice de int . Aucun tableau nexiste pour le moment ; selon le contexte, la valeur de mat est soit null, soit ind etermin ee. La matrice commence ` a exister lorsquon appelle lop erateur new. Par exemple, de la mani` ere suivante :
14. Ne pas oublier quune expression de type char est toujours spontan ement convertible dans le type int.

14

c H. Garreta, 2000-2013

TYPES

3.4

Tableaux

mat = new int[NL][NC]; o` u NL et NC sont des expressions enti` eres d enissant le nombre de lignes et de colonnes de la matrice souhait ee. Linstruction pr ec edente a le m eme eet que le code suivant : mat = new int[NL][]; for (int i = 0; i < NL; i++) mat[i] = new int[NC]; // un tableau de NL [r ef erences de] tableaux // un tableau de NC int

Lacc` es aux el ements dun tableau ` a deux indices se fait comme en C : mat[i][j] L evaluation de cette expression d eclenchera la v erication successive des conditions : 1 2 3 4 mat = null 0 i < mat.length mat[i] = null 0 j < mat[i].length

Ainsi, un tableau ` a deux indices dont les el ements sont par exemple des int est r ealis e en Java comme un tableau ` a un indice dont les el ements sont des [r ef erences sur des] tableaux ` a un indice dont les el ements sont des int. La gure 3 repr esente cette conguration.
m +i m[0] ... m[i] ... ... m[NL-1][NC-1] m[NL-1]

m[NL-1][0] +j ... m[i][0] ... m[0][0] m[0][NC-1] ... m[i][j]

m[i][NC-1]

Figure 3 Acc` es ` a m[i][j], m etant une matrice ` a NL lignes et NC colonnes Note. Java permet de manipuler, sous la m eme syntaxe, des tableaux rectangulaires et des tableaux qui ne le sont pas ; il sut pour cela de faire soi-m eme linitialisation des lignes. Par exemple, le code suivant cr ee une matrice triangulaire inf erieure de dimension N dans laquelle chaque ligne a la longueur requise par son rang : float[][] mt = new float[N][]; for (int i = 0; i < N; i++) mt[i] = new float[i + 1]; 3.4.4 Tableaux initialis es et tableaux anonymes.

Deux syntaxes permettent dindiquer un ensemble de valeurs devant remplir un tableau. Dans lune comme dans lautre, le nombre de valeurs fournies d etermine la taille du tableau. Dans la premi` ere forme, analogue ` a celle qui existe en C, on initialise le tableau au moment de sa d eclaration : int[] tab = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; La deuxi` eme forme permet de cr eer un tableau garni de valeurs, mais pas forc ement ` a lendroit de la d eclaration du tableau :
c H. Garreta, 2000-2013

15

3.5

Conversions entre types tableaux ou classes

TYPES

int[] tab; ... tab = new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; En fait, cette deuxi` eme syntaxe permet de cr eer des tableaux garnis anonymes, ce qui est bien utile lorsquun tableau ne sert quune seule fois. Par exemple, si la variable tab avait et e d eclar ee et construite dans lunique but de gurer dans lappel dune m ethode (cela arrive) comme dans : int tab[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; traiter(tab); alors il aurait et e plus simple de ne pas d eclarer de variable tab : traiter(new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }); Cas des matrices. Les m emes m ecanismes permettent de cr eer des tableaux multidimensionnels garnis, y compris lorsque leurs lignes ne sont pas de m eme longueur : int[][] mat = { { 11, 12, 13, 14, 15 }, { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 }, { }, null, { 51, 52, 53 } }; Notez la di erence entre la troisi` eme et la quatri` eme ligne du tableau pr ec edent : la troisi` eme existe mais est vide (cest un tableau de 0 el ements), tandis que la quatri` eme nexiste pas. Note. Contrairement ` a ce qui se passe dans dautres langages, en Java linitialisation des tableaux se fait pendant lex ecution du programme, non pendant la compilation. Premi` ere cons equence : initialiser un tableau par une liste de constantes est plus commode, mais pas notablement plus ecace, que la collection daectations qui aurait le m eme eet. Par exemple, la d eclaration int[] tab = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; a le m eme eet mais est plus agr eable ` a ecrire et ` a lire que la s equence int[] tab = new int[10]; tab[0] = 1; tab[1] = 2; ... tab[9] = 10; Deuxi` eme cons equence : les expressions avec lesquelles on initialise des tableaux nont pas ` a etre n ecessairement des constantes. Des expressions quelconques, evalu ees pendant lex ecution du programme, peuvent y gurer : int[] tab = { x + 1, 2 * x + 1, 4 * x + 1, (int) Math.atan(y) };

3.5

Conversions entre types tableaux ou classes

Attention, section indigeste ! Pour bien comprendre cette section il faut conna tre les notions de classe et dh eritage. Le type statique dune expression E est d etermin e par les d eclarations des variables apparaissant dans E , ainsi que par les constantes, op erateurs et m ethodes qui forment E . Par exemple, avec la d eclaration Object e = "Bonjour"; le type statique de e est Object. Le type dynamique dune expression E est celui qui r esulte des valeurs eectives des variables intervenant dans E , ainsi que des constantes, op erateurs et m ethodes constituant E . Par exemple, avec la m eme d eclaration ci-dessus, le type dynamique de e est String. Dans ces conditions, soit E une expression, Ts son type statique, Td son type dynamique ` a un instant donn e et Tf un deuxi` eme type. Nous nous int eressons ` a la conversion de la valeur de E vers le type Tf , lorsque Ts et Tf ne sont pas identiques et que ce ne sont pas deux types primitifs. Voici ce quil faut savoir a ce sujet : ` 1. Aucune conversion nest possible entre un type primitif et un type tableau ou classe, ou r eciproquement. Dans les points suivants on suppose donc que Ts et Tf sont tous les deux des types tableaux ou classes. 16
c H. Garreta, 2000-2013

TYPES

3.6

Copie et comparaison des objets

2. La conversion de la valeur de E vers le type Tf , lorsquelle est l egitime, est une conversion sans travail : elle se r eduit ` a consid erer lobjet d esign e par E comme ayant le type Tf , sans que cet objet subisse la moindre modication (ne pas oublier que E ne repr esente quune r ef erence sur un objet). 3. Sauf le cas particulier examin e au point 7, la conversion de E vers le type Tf nest accept ee ` a la compilation que si Ts et Tf sont des classes apparent ees, cest-` a-dire des classes dont lune est sousclasse, directe ou indirecte, de lautre (autrement dit, Ts et Tf sont sur une m eme branche de larbre dh eritage). 4. Si Tf est une super-classe, directe ou indirecte, de Ts la conversion de E vers le type Tf est correcte et ne requiert aucune indication particuli` ere. On peut appeler cela une g en eralisation du type de E . Par exemple, si la classe Article est une super-classe de la classe ArticleSportif, elle-m eme superclasse de Velo, qui est super-classe de VTT, alors laectation suivante est correcte : Article unArticle = new Velo( ...caract eristiques dun v elo... ); Lobjet Velo cr e e ci-dessus nest en rien modi e par son aectation ` a la variable unArticle mais, aussi longtemps quil est acc ed e` a travers cette variable, il est consid er e comme un Article, non comme une Velo (Article est un concept plus g en eral que Velo). 5. Si Tf est une sous-classe (directe ou indirecte) de Ts , la conversion de E vers le type Tf est une sorte de particularisation du type de E et : nest accept ee ` a la compilation que si on utilise explicitement lop erateur de transtypage. Exemple : Article unArticle; Velo unVelo; ... unVelo = unArticle; unVelo = (Velo) unArticle;

// ERREUR d` es la compilation // Ok, pour la compilation

nest correcte ` a lex ecution que si Td est une sous-classe, directe ou indirecte, de Tf . Exemple : unArticle = new VTT( ... caract eristiques dun VTT ... ); ... unVelo = (Velo) unArticle; // Ok, un VTT peut ^ etre vu comme une Velo d eclenche lorsquelle est incorrecte, ` a lex ecution, lexception ClassCastException. Exemple : unArticle = new BallonDeBasket( ... caract eristiques dun ballon ... ); ... unVelo = (Velo) unArticle; // d eclenche ClassCastException (un ballon // ne peut pas ^ etre vu comme un v elo) 6. Aucune conversion nest accept ee entre types tableaux di erents (mais noubliez pas que le nombre d el ements dun tableau ne fait pas partie de la d enition de son type : pour Java, un tableau de 10 entiers et un tableau de 20 entiers ont exactement le m eme type). 7. Enn, les seules conversions correctes entre une classe et un tableau concernent n ecessairement la classe Object, super-classe de toutes les classes et de tous les tableaux. Exemple : int[] uneTable = new int[nombre]; ... Object unObjet = uneTable; // Ok (Object super-classe de tous les objets) ... uneTable = (int[]) unObjet; // Ok (dapr` es le type dynamique de unObjet) sume . Lessentiel ` En re a retenir des r` egles pr ec edentes : ` a la compilation, la conversion dune expression de type objet ou tableau est accept ee sauf si on peut pr edire avec certitude quelle echouera ` a lex ecution ; elle requiert parfois lemploi explicite de lop erateur de transtypage ; ` a lex ecution, la conversion du type dun objet est toujours contr ol ee par Java ; elle nest accept ee que si elle correspond ` a une g en eralisation du type dynamique de lobjet.

3.6

Copie et comparaison des objets

Attention, section indigeste ! On mentionne ici des concepts, concernant notamment les superclasses et les interfaces, qui ne seront expliqu ees qu` a la section 7.
c H. Garreta, 2000-2013

17

3.6

Copie et comparaison des objets

TYPES

3.6.1

Copie

Une cons equence du fait que les objets et les tableaux sont toujours manipul es ` a travers des r ef erences est la suivante : laectation dune expression de type objet ou tableau ne fait pas une vraie duplication de la valeur de lexpression, mais uniquement une duplication de la r ef erence (on appelle parfois cela une copie supercielle ). Par exemple, consid erons : Point p = Point(10, 20); Point q = p; A la suite de laectation pr ec edente on peut penser quon a dans q un duplicata de p. Il nen est rien, il ny a pas deux objets Point, mais un seul objet Point r ef erenc e par deux variables distinctes, comme le montre la gure 4. Dans certaines situations cette mani` ere de copier est susante, mais elle pr esente un inconv enient evident : chaque modication de la valeur de p se r epercute automatiquement sur celle de q.

10 20

Figure 4 Copie de la r ef erence sans duplication de lobjet (copie supercielle )

Pour obtenir la duplication eective dun objet, il faut appeler sa m ethode clone. Tous les objets sont cens es poss eder une telle m ethode 15 car elle est d eclar ee dans la classe Object, la super-classe de toutes les classes. Il appartient ` a chaque classe de red enir la m ethode clone, pour en donner une version adapt ee au r ole et aux d etails internes de ses instances. La m ethode clone rend un r esultat de type Object 16 , il faut donc lutiliser comme suit (la d enition m eme de clone garantit que la conversion du r esultat de p.clone() vers le type Point est l egitime) : Point q = (Point) p.clone();

10 20

10 20

Figure 5 Duplication eective dun objet (copie profonde )

Si clone a et e correctement d enie (dans la classe Point) lexpression pr ec edente aecte ` a q une copie profonde de lobjet qui est la valeur de p, comme montr e sur la gure 5. Il appartient au programmeur dune classe de d enir ce quil entend par copie profonde, notamment lorsque les objets ont pour membres dautres objets. Sauf indication contraire on suppose que le clone dun objet est un deuxi` eme objet nayant avec le premier aucun bout de m emoire en commun (comme les points montr es ci-dessus), mais ce nest pas une obligation. Par exemple, on verra ` a la section suivante que le clone standard dun tableau dobjets nest pas disjoint du tableau original.
15. La m ethode clone existe dans tous les objets mais, si le programmeur na pas pris certaines pr ecautions (consistent soit ` a d enir explicitement la m ethode clone, soit ` a d eclarer que la classe impl emente linterface Cloneable), une exception CloneNotSupportedException sera lanc ee a ` lex ecution. 16. Cest regrettable mais n ecessaire, car la d enition initiale de clone, dans la classe Object, ne peut etre d eclar ee rendant autre chose quun Object ; ensuite les r ed enitions de clone dans les sous-classes doivent rendre strictement le m eme r esultat, cest une contrainte du m ecanisme de la red enition des m ethodes.

18

c H. Garreta, 2000-2013

TYPES

3.6

Copie et comparaison des objets

Cas des tableaux La m ethode clone fonctionne en particulier dans le cas des tableaux : si t est un tableau, le r esultat de t.clone() est un tableau de m eme type et m eme taille que t dont les el ements ont et e initialis es par aectation de ceux de t. Par exemple, les instructions suivantes cr eent deux tableaux distincts, lun r ef erenc e par les variables tab1 et tab2 et lautre r ef erenc e par tab3 : int[] tab1 = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; int[] tab2 = tab1; // ceci nest pas une duplication int[] tab3 = (int[]) tab1.clone(); // ceci est une duplication effective Attention. Le r esultat rendu par t.clone() est un tableau nouvellement cr e e, de m eme type et m eme taille que t, dont les el ements sont initialis es par aectation, non par clonage, de ceux de t. Autrement dit, la m ethode clone des tableaux neectue pas une duplication profonde, mais seulement une duplication ` a un niveau : si les el ements du tableau sont des objets 17 le tableau initial et son clone ne sont pas disjoints car ils partagent les m emes el ements. Il faut se demander si cest cela quon voulait obtenir. Cette question est reprise dans la section suivante. Note Java 5. La m ethode clone etant introduite au niveau de la classe Object, elle est d eclar ee comme rendant un r esultat de type Object ce qui, dans le cas des tableaux, obligeait jusqu` a Java 1.4 ` a lutiliser munie dun changement de type : Point[] t = new Point[n]; ... Point[] q = (Point[]) t.clone(); A partir de la version 5 du langage ce nest plus une obligation. Le compilateur r eserve un traitement sp ecial ` a lappel de clone sur un tableau de mani` ere ` a rendre correctes des expressions comme : Point[] t = new Point[n]; ... Point[] q = t.clone(); 3.6.2 D enir la m ethode clone

La m ethode clone doit etre red enie dans chaque classe o` u cela est utile ; elle doit etre public. Exemple : class Point { int x, y; public Point(int a, int b) { x = a; y = b; } public Object clone() { return new Point(x, y); } } On peut ecrire la m ethode clone ` a partir de rien, comme ci-dessus, mais on peut aussi all eger ce travail et utilisant la m ethode Object.clone() h erit ee de la classe Object. Pour cela, la classe quon ecrit doit comporter l enonc e implements Cloneable; 18 sans quoi lexception CloneNotSupportedException sera lanc ee ` a lex ecution. Exemple : class Rectangle implements Cloneable { Point coinNO, coinSE; public Rectangle(int x1, int y1, int x2, int y2) { coinNO = new Point(x1, y1); coinSE = new Point(x2, y2); } public Object clone() throws CloneNotSupportedException { return super.clone(); // notre version de clone se r eduit ` a } // la version h erit ee de la classe Object }
17. Cas particulier remarquable : les matrices, qui sont des tableaux de tableaux. Puisque les tableaux sont des objets, il en r esulte que la m ethode clone ne duplique pas les coecients des matrices, m eme lorsque ceux-ci sont dun type primitif. 18. Linterface Cloneable est enti` erement vide, l enonc e implements Cloneable nest quune marque par laquelle le programmeur saccorde le permis dutiliser la m ethode h erit ee Object.clone() .

c H. Garreta, 2000-2013

19

3.6

Copie et comparaison des objets

TYPES

Leet de la m ethode h erit ee Object.clone() est la cr eation dun objet de m eme type que celui quon clone, puis linitialisation de chacune des variables dinstance de lobjet cr e e par aectation de la variable dinstance correspondante de lobjet original. Cest donc une copie ` a un niveau , moins supercielle que la copie des r ef erences, mais ce nest pas la vraie copie en profondeur : si des membres sont ` a leur tour des objets cette sorte de copie ne sut pas pour faire que lobjet clon e soit enti` erement s epar e de lobjet original. Par exemple, la gure 6 montre ` a quoi ressemblerait le couple form e par un objet de la classe Rectangle, d enie ci-dessus, et son clone, cr e es par les instructions suivantes : Rectangle p = new Rectangle(10, 20, 30, 40); Rectangle q = (Rectangle) p.clone();
q

coinNO coinSE 10 20 30 40

coinNO coinSE

Figure 6 La copie ` a un niveau que fait Object.clone() Pour avoir une duplication compl` ete la m ethode clone aurait d u etre ecrite comme ceci : class Rectangle { Point coinNO, coinSE; ... public Object clone() { return new Rectangle(coinNO.x, coinNO.y, coinSE.x, coinSE.y); } } ou bien, en supposant que la classe Rectangle a un constructeur sans argument : class Rectangle { Point coinNO, coinSE; ... public Object clone() { Rectangle r = new Rectangle(); r.coinNO = (Point) coinNO.clone(); r.coinSE = (Point) coinSE.clone(); return r; } } Note. Il est regrettable que lutilisation de la m ethode clone h erit ee de la classe Object soit alourdie par la n ecessit e dattraper ou d eclarer CloneNotSupportedException, puisque cette exception est susceptible d etre lanc ee, m eme lorsque, comme ici, il est certain quelle ne sera pas lanc ee (puisque l enonc e implements Cloneable a bien et e ecrit dans la d eclaration de la classe). Dans lexemple ci-dessus, cette exception a et e d eclar ee. On aurait pu aussi bien lattraper et la faire dispara tre (puisque que de toute fa con elle ne sera pass lanc ee) en ecrivant clone de cette mani` ere : class Rectangle implements Cloneable { ... public Object clone() { try { // notre version de clone se r eduit ` a return super.clone(); // la version h erit ee de la classe Object } catch (CloneNotSupportedException e) { return null; } } ... } 20
c H. Garreta, 2000-2013

TYPES

3.6

Copie et comparaison des objets

3.6.3

Comparaison

Des remarques analogues aux pr ec edentes peuvent etre faites au sujet de lop erateur de comparaison. Si a et b sont dun type classe ou tableau, la condition a == b ne traduit pas l egalit e des valeurs de a et b, mais l egalit e des r ef erences. Autrement dit, cette condition est vraie non pas lorsque a et b sont des objets egaux, mais lorsque a et b sont le m eme objet. Dans beaucoup de situations une telle notion d egalit e est trop restrictive. Cest pourquoi tous les objets sont cens es poss eder la m ethode equals qui impl emente une notion d egalit e plus utile. Point p = new Point(10, 20); Point q = new Point(10, 20); ... System.out.println(p == q); System.out.println(p.equals(q)); ...

// ceci ache false // ceci ache true (si equals a et e bien d enie)

La m ethode equals est d enie une premi` ere fois au niveau de la classe Object, o` u elle nest rien de plus que l egalit e des r ef erences : class Object { ... public boolean equals(Object o) { return this == o; } } mais chaque classe peut la red enir pour en donner une version adapt ee au r ole et aux d etails internes de ses instances. Pour notre classe Point voici une premi` ere version, pas tr` es juste : class Point { ... public boolean equals(Point o) { return x == o.x && y == o.y; } }

// VERSION ERRON EE !!!

Bien que r epondant en partie aux besoins, cette version de Point.equals est erron ee car, ` a cause du type de largument, elle ne constitue pas une red enition de la m ethode Object.equals(Object o) 19 . Voici une version plus correcte : class Point { ... public boolean equals(Object o) { return o instanceof Point && x == ((Point) o).x && y == ((Point) o).y; } } Maintenant, la m ethode ci-dessus est une vraie red enition de Object.equals, mais elle nest pas encore parfaite. Il faut savoir, en eet, que x instanceof K ne signie pas forc ement que x est instance de K ( x est un K ), mais uniquement que x est instance dune sous-classe de K ( x est une sorte de K ). Ainsi, si on suppose que Pixel est une sous-classe de Point (un Pixel est un Point avec, en plus, lindication dune couleur), ` a la suite de Point cePoint = new Point(11, 22); Pixel cePixel = new Pixel(11, 22, "rouge"); la condition cePoint.equals(cePixel) sera vraie. Est-ce ce que lon souhaite ? Probablement non. Voici une nouvelle version de equals qui corrige ce probl` eme : class Point { ... public boolean equals(Object o) {
19. Il nest pas el ementaire de comprendre pourquoi cette version simple de equals nest pas correcte. Il faut imaginer la condition p.equals(q) lorsque les valeurs de p et q sont des objets Point alors que la variable q est d eclar ee de type Object (une telle situation se produit, par exemple, chaque fois quon consid` ere une Collection dont les el ements sont des objets Point). Si q est d eclar ee de type Object, p.equals(q) nutilisera pas notre m ethode Point.equals(Point p), mais Object.equals(Object o) qui nest pas red enie dans la classe Point.

c H. Garreta, 2000-2013

21

3.7

Cha nes de caract` eres

TYPES

return o != null && o.getClass() == Point.class && ((Point) o).x == x && ((Point) o).y == y; } } Toute surcharge de la m ethode Object.equals(Object o) doit etre une relation d equivalence (cest-` adire une relation binaire r eexive, sym etrique et transitive ) telle que si x = null alors x.equals(null) est faux. De plus, bien que ce ne soit pas une obligation, il semble naturel de faire en sorte que si y = x.clone() alors x == y soit certainement faux et x.equals(y) soit certainement vrai.

3.7
3.7.1

Cha nes de caract` eres


Les classes String et StringBuffer

Deux classes permettent de repr esenter les cha nes de caract` eres : les instances de la classe String sont invariables ; une fois cr e ees, les caract` eres dont elles sont form ees ne peuvent plus etre modi es, les instances de la classe StringBuffer, au contraire, sont destin ees ` a subir des op erations qui modient les caract` eres dont elles sont faites (remplacements, ajouts, suppressions, etc.). Les d etails de lutilisation de ces deux classes, extr emement utiles lune et lautre, sont d ecrits dans la documentation de lAPI Java. Limitons-nous ici ` a signaler certains privil` eges tout ` a fait originaux et int eressants de la classe String : 1. Il existe une notation sp ecique pour les constantes litt erales : toute suite de caract` eres encadr ee par des guillemets produit une instance de la classe String : String nom = "Gaston Lagaffe"; 2. Lop eration de concat enation (mise bout ` a bout) de deux cha nes se note par lop erateur 20 + : String formule = "Monsieur " + nom; // vaut "Monsieur Gaston Lagaffe" 3. Toutes les classes poss` edent la m ethode String toString(), qui renvoie une expression dun objet sous forme de cha ne de caract` eres. La classe Object fournit une version minimale de cette m ethode, chaque classe peut en donner une d enition plus adapt ee. Exemple : class Point { int x, y; ... public String toString() { return "(" + x + "," + y + ")"; } } 4. Lop erateur +, lorsquun de ses op erandes est une cha ne, provoque la conversion de lautre op erande vers le type cha ne. Cette conversion est eectu ee dans le cas dun type primitif, par lappel dune des m ethodes statiques valueOf de la classe String, dans le cas dun objet, par lappel de sa m ethode toString Par exemple, si p est un objet Point (voir ci-dessus), lexpression "r esultat: " + p equivaut ` a lexpression "r esultat: " + p.toString() dont la valeur est, par exemple, la cha ne "r esultat: (10,20)". 5. La conversion vers le type cha ne est pratiqu ee egalement par certaines m ethodes dint er et g en eral. Par exemple, les m ethodes print et println de la classe PrintStream (la classe de lobjet System.out) ont des d enitions sp eciques pour les cas o` u leur argument est dun type primitif ou String et r ecup` erent tous les autres cas ` a laide de la m ethode toString. Par exemple, on peut imaginer print(Object o) ainsi ecrite : public void print(Object o) { print(o.toString()); } // print(Object) est ramen ee ` a print(String)

20. Les programmeurs C++ noteront que cet emploi du + est le seul cas de surcharge dun op erateur en Java.

22

c H. Garreta, 2000-2013

TYPES

3.7

Cha nes de caract` eres

3.7.2

Copie et comparaison des cha nes

1. Clone. La classe String ne comporte pas de m ethode clone : puisque les instances de cette classe sont immuables, il nest jamais n ecessaire de les cloner. 2. Equals. La classe String ore une version de la m ethode equals dont il est facile dimaginer ce quelle fait : parcourir les deux cha nes en comparant les caract` eres correspondants. Deux cha nes construites s epar ement lune de lautre doivent etre compar ees ` a laide de cette m ethode. Par exemple, si reponse est de type String, lexpression reponse == "oui" vaut souvent false ind ependamment de la valeur de reponse et na donc aucun int er et. Il faut ecrire ` a la place reponse.equals("oui") ou bien "oui".equals(reponse).

3. Intern. La m ethode equals est utile mais relativement on ereuse, puisquelle doit examiner les deux cha nes en comparant les caract` ere homologues. Les programmes qui comportent des comparaisons fr equentes entre des cha nes (en nombre raisonnable) peuvent tirer avantage de la m ethode intern() qui renvoie une cha ne ayant les m emes caract` eres que la cha ne donn ee, mais appartenant ` a un ensemble de cha nes sans r ep etition, au sein duquel deux cha nes egales sont forc ement la m eme cha ne. Lorsquune cha ne appartient a cet ensemble on dira quelle a ` et e internalis ee. Ainsi, par exemple, etant donn ees deux variables s1 et s2 de type String, quelles que soient les valeurs des cha nes t1 et t2, ` a la suite de s1 = t1.intern(); s2 = t2.intern(); les conditions s1.equals(s2) et s1 == s2 sont equivalents (mais l evaluation de la deuxi` eme est evidemment plus rapide). Note. Les cha nes de caract` eres constantes ecrites dans le programme source sont garanties internalis ees, contrairement aux cha nes construites pendant lex ecution (chaque appel de new doit produire la cr eation dun nouvel objet). Ainsi, le code suivant ache certainement true false true : ... String a = "bonjour"; ... String b = "bonjour"; ... String c = new String("bonjour"); ... String d = c.intern(); ... System.out.println((a == b) + " " + (a == c) + " " + (a == d));

c H. Garreta, 2000-2013

23

EXPRESSIONS ET INSTRUCTIONS

Expressions et instructions

Cette section ridiculement courte est consacr ee aux di erences notables existant entre les expressions 21 et instructions de Java et celles de C. Bonne nouvelle : pour lessentiel, ce sont les m emes. Les expressions sont form ees avec les m emes op erateurs, les instructions emploient les m emes mots-cl es, les unes et les autres sont soumises aux m emes r` egles de syntaxe, renvoient les m emes valeurs et ont les m emes eets. Exceptions : deux m ecanismes sont r ealis ees de mani` ere originale en Java et m eritent d etre expliqu ees, m eme dans un polycopi e succinct comme celui-ci : linstruction de rupture etiquet ee, expliqu ee ci-dessous, la boucle for am elior ee expliqu ee ` a la section 12.3.2.

4.1

Rupture etiquet ee

Linstruction goto de certains langages nexiste pas ici. Cependant, an de b en ecier dun service important que cette instruction rend parfois, la ma trise de labandon des boucles imbriqu ees, on a ajout e ceci ` a Java : les instructions, et notamment les boucles (for, while, do...while, etc.), peuvent etre etiquet ees, linstruction break peut etre suivie dune etiquette an de provoquer labandon de plusieurs boucles imbriqu ees au lieu dune seule. Une etiquette est un identicateur quil nest pas n ecessaire de d eclarer ; il sut de l ecrire, suivi de : , devant une instruction, pour quil soit connu ` a lint erieur de celle-ci et inconnu ` a lext erieur. Par exemple, le code purement d emonstratif suivant ache les dates comprises entre le 1er janvier 2000 et le 30 d ecembre 2005, en supposant que tous les mois ont 30 jours. A chaque achage, un entier pseudo-al eatoire de lintervalle [ 0, 100 [ est tir e : si cest un multiple de 3, le mois en cours est abandonn e (on passe au 1er du mois suivant) ; si cest un multiple de 13, lann ee en cours est abandonn ee (on passe au 1er janvier de lann ee suivante) ; si le nombre est 0, le travail est abandonn e: ... grandeBoucle: for (int a = 2000; a <= 2005; a++) moyenneBoucle: for (int m = 1; m <= 12; m++) petiteBoucle: for (int j = 1; j <= 30; j++) { System.out.println(j + "/" + m + "/" + a); int x = (int) (Math.random() * 100); if (x == 0) break grandeBoucle; else if (x % 13 == 0) break moyenneBoucle; else if (x % 3 == 0) break petiteBoucle; } ... Ce qui vient d etre dit ` a propos de linstruction break etiquet ee sapplique mutatis mutandis ` a linstruction continue qui peut, elle aussi, etre etiquet ee. Par exemple, voici une r edaction equivalente du bout de programme pr ec edent : ... grandeBoucle: for (int a = 2000; a <= 2005; a++) moyenneBoucle: for (int m = 1; m <= 12; m++) for (int j = 1; j <= 30; j++) { System.out.println(j + "/" + m + "/" + a); int x = (int) (Math.random() * 100); if (x == 0) break grandeBoucle; else if (x % 13 == 0) continue grandeBoucle; else if (x % 3 == 0) continue moyenneBoucle; } ...
21. Nous voulons parler ici des expressions ne mettant en jeu que des types primitifs

24

c H. Garreta, 2000-2013

CLASSES, PAQUETS, FICHIERS ET REPERTOIRES

Classes, paquets, chiers et r epertoires

Lunit e de compilation en Java est la classe. Un chier source se compose n ecessairement de quelques classes compl` etes, souvent une seule, et le compilateur produit un chier compil e (chier dextension .class) pour chaque classe rencontr ee dans le chier source, f ut-elle une classe interne ou anonyme. La syntaxe de la d enition des classes est expliqu ee ` a partir de la section 6.2. Ici nous nous int eressons au regroupement des classes en paquets, et au rangement des classes et des paquets dans les chiers et les r epertoires.

5.1

Paquets et classes

Voici la quintessence de la notion de paquet (package ) : deux classes peuvent avoir le m eme nom si elles appartiennent ` a des paquets distincts. 5.1.1 Les noms des paquets et linstruction package

Quon le veuille on non, chaque classe appartient ` a un paquet. Si on ne sest occup e de rien, il sagit du paquet sans nom (unnamed package ), qui contient toutes les classes pour lesquelles on na pas donn e un nom de paquet explicite. On peut changer cela ` a laide de linstruction package , qui doit etre la premi` ere instruction utile (i.e. autre quun commentaire) du chier source : package nomDuPaquet ; Toutes les classes d enies dans un chier commen cant par la ligne pr ec edente appartiennent ipso facto au paquet nomm e nomDuPaquet. Dautres chiers peuvent comporter cette m eme instruction ; les classes quils d enissent appartiennent alors ` a ce m eme paquet. Un nom de paquet est un identicateur ou une suite didenticateurs, chacun s epar e du suivant par un point. Trois exemples : monprojet, java.awt.event et fr.univ_mrs.dil.henri.outils. Les noms commen cant par java. sont r eserv es aux paquets contenant les classes de la biblioth` eque standard. Seul Sun Microsystems a le droit de les utiliser. Si vous ecrivez des programmes dun int er et vraiment g en eral, vous devez pouvoir garantir que les noms de vos paquets sont uniques dans le monde entier. Le syst` eme propos e par Sun pour nommer ces paquets ` a vocation plan etaire consiste ` a utiliser les el ements de votre nom de domaine Internet, plac es ` a lenvers. Par exemple, si votre domaine est dil.univ-mrs.fr alors vos paquets pourront etre nomm es comme ceci 22 : package fr.univ_mrs.dil.unProjet.outils; 5.1.2 Les noms des classes et linstruction import

Chaque classe poss` ede un nom court, qui est un identicateur, et un nom long form e en pr exant le nom court par le nom du paquet. Par exemple, java.awt.List est le nom long dune classe du paquet java.awt dont le nom court est List. Une classe peut toujours etre d esign ee 23 par son nom long. Elle peut en outre etre d esign ee par son nom court : depuis [toute m ethode de] toute classe du m eme paquet ; depuis [toute m ethode de] toute classe ecrite dans un chier qui comporte linstruction : import nomDuPaquet .nomDeLaClasse ; ou bien linstruction (dans cette forme on importe dun coup toutes les classes du paquet indiqu e) : import nomDuPaquet .*; Note 1. Il ne faut pas donner ` a la formule pr ec edente plus deet quelle nen a : unPaquet .* signie les classes du paquet unPaquet, cela ninclut pas les classes des eventuels sous-paquets (les paquets dont les noms commencent par unPaquet ). Ainsi, les deux directives suivantes, dun usage fr equent, ne sont pas redondantes, la premi` ere nimplique pas la deuxi` eme : import java.awt.*; import java.awt.event.*; // les classes du paquet java.awt // les classes du paquet java.awt.event

22. Les el ements dun nom de paquet doivent etre des identicateurs. Cest la raison pour laquelle les eventuels tirets - doivent etre remplac es, comme ici, par des blancs soulign es _. 23. Quune classe puisse ou doive etre d esign ee par tel ou tel nom ne pr ejuge en rien du fait quon ait on non le droit dacc eder ` a ses membres ; cela d epend du contexte et de r` egles expliqu ees ` a la section 6.4.

c H. Garreta, 2000-2013

25

5.2

Classes, chiers et r epertoires

CLASSES, PAQUETS, FICHIERS ET REPERTOIRES

Note 2. Dans certains cas lutilisation des noms longs des classes reste n ecessaire pour eviter des ambigu t es. Par exemple, List est une classe du paquet java.awt et une interface du paquet java.util. Dans un chier o` u les deux sont employ ees (ce nest pas rare), on ne peut pas utiliser le nom court dans les deux cas. Note 3. On entend parfois : il faut ecrire telle instruction import pour avoir le droit dutiliser telle classe . Cela nest jamais vrai : linstruction import ne sert pas ` a rendre visibles des classes (toutes les classes qui se trouvent dans des chiers et r epertoires que la machine Java peut atteindre sont visibles 24 ) ni a vous donner le droit dacc` ` es ` a des classes (cela se pilote ` a travers les qualications public, private, etc., voir la section 6.4). Le seul droit que linstruction import vous donne est celui dutiliser un nom court pour nommer une classe que vous auriez pu, sans cela, d esigner par son nom long. Note 4. Le paquet java.lang est sp ecial : ses classes peuvent etre d esign ees par leur nom court sans quil soit n ecessaire d ecrire import java.lang.* en t ete du chier. Ce paquet est fait de classes fondamentales, qui font partie de la d enition du langage Java lui-m eme : Object, String, Math, System, Integer, etc. Sil fallait ecrire import java.lang.* pour les utiliser, alors il faudrait l ecrire dans tous les chiers.

5.2
5.2.1

Classes, chiers et r epertoires


Classes publiques et non publiques

La d eclaration dune classe peut etre pr ec ed ee ou non du qualieur public. Si ce nest pas le cas, la classe est dite non publique et elle nest accessible que depuis les [m ethodes des] autres classes du m eme paquet 25 . Si la d eclaration dune classe est pr ec ed ee du qualieur public alors la classe est dite publique ; elle est accessible depuis [les m ethodes de] toutes les classes de tous les paquets. Si un chier source contient une classe publique, le nom du chier doit etre le nom de cette classe, compl et e par lextension .java . Par exemple, un chier contenant le texte public class Point { ... d enition de la classe Point ... } doit se nommer Point.java. Il en d ecoule quun chier source ne peut pas contenir plus dune classe publique. En r esum e, mis ` a part les commentaires, un chier source est donc compos e des el ements suivants, dans lordre indiqu e: eventuellement, une instruction package ; eventuellement, une ou plusieurs instructions import ; une ou plusieurs classes, dont au plus une est publique ; elle impose alors son nom au chier. 5.2.2 Point dentr ee dun programme.

Une classe est dite ex ecutable si, et seulement si elle comporte une m ethode de signature public static void main(String[] args) (chaque mot de lexpression pr ec edente est impos e strictement, sauf args). Le lancement de lex ecution dune application Java equivaut ` a lappel de la m ethode main dune classe ex ecutable ; si on travaille ` a une console, cela se fait par la commande java NomDeLaClasse argum1 . . . argumk Largument args de main est un tableau dont les el ements sont les cha nes argum1 . . . argumk qui gurent dans la commande qui a lanc e le programme. Par exemple, voici un programme qui ache n fois un certain mot m, n et m etant donn es lors du lancement. Fichier Radotage.java :
24. Linstruction import nest donc pas lhomologue en Java de la directive #include du langage C 25. Les classes non publiques repr esentent donc des services oerts aux autres classes du m eme paquet, non des fonctionnalit es universelles dont nimporte quel utilisateur peut avoir besoin (cela est le r ole des classes publiques).

26

c H. Garreta, 2000-2013

CLASSES, PAQUETS, FICHIERS ET REPERTOIRES

5.2

Classes, chiers et r epertoires

public class Radotage { public static void main(String[] args) { int n = Integer.parseInt(args[0]); for (int i = 0; i < n; i++) System.out.print(args[1] + " "); } } Compilation et ex ecution de ce programme (dans le cas dex ecution pr esent e ici, args[0] est la cha ne "5" et args[1] la cha ne "bonsoir") : > javac Radotage.java > java Radotage 5 bonsoir bonsoir bonsoir bonsoir bonsoir bonsoir > 5.2.3 O` u placer les chiers des classes ?

Un proc ed e, qui d epend plus ou moins du syst` eme dexploitation sous-jacent, associe ` a chaque paquet un r epertoire dans lequel doivent se trouver les chiers compil es (chiers dextension .class) des classes du paquet ; il consiste ` a utiliser la structure hi erarchique du syst` eme de chiers pour reproduire la structure hi erarchique des noms des paquets. Ainsi, par exemple, les chiers des classes des paquets java.awt.event et monprojet.outils doivent etre plac es, respectivement, dans des r epertoires nomm es, sur Unix, java/awt/event/ et monprojet/mesoutils/. Sur Windows, ces r epertoires seraient java\awt\event\ et monprojet\mesoutils\. Ces chemins sont relatifs 26 aux r epertoires suivants : par d efaut, le r epertoire courant (nomm e g en eralement . ), chacun des r epertoires de la liste d enie par la valeur de la variable denvironnement CLASSPATH, lorsque cette variable est d enie 27 (le cas par d efaut nest alors pas consid er e), chacun des r epertoires de la liste d enie par la valeur de largument -cp ou -classpath, si cet argument a et e sp eci e lors du lancement de la machine java (l eventuelle valeur de la variable CLASSPATH et le cas par d efaut sont alors ignor es). Note. Parfois les classes intervenant dans une compilation ou une ex ecution sont prises dans un chier .jar. Il faut savoir que, fondamentalement, un tel chier nest que la forme zipp ee dune arborescence de r epertoires et les indications pr ec edentes sappliquent pratiquement telles quelles, le chier .jar jouant le r ole de r epertoire de base. Pour obtenir que le compilateur place les chiers compil es dans un certain r epertoires, en le cr eant sil nexiste pas, il faut lancer la compilation avec loption -d r epertoireDeBase . Par exemple, si on souhaite que les noms des paquets correspondent ` a des chemins relatifs au r epertoire courant (d esign e par . ) il faut activer le compilateur par la commande : javac -d . MaClasse.java Ainsi, si le chier MaClasse.java contient une classe nomm ee MaClasse et commence par linstruction package monPaquet la commande pr ec edente produira un chier appel e MaClasse.class plac e dans un sous-r epertoire monPaquet du r epertoire courant . Si MaClasse est une classe ex ecutable, on la lancera alors depuis le r epertoire courant par lune ou lautre des commandes : java monPaquet/MaClasse (sur UNIX) ou java monPaquet\MaClasse (sur Windows) ou java monPaquet.MaClasse (ind ependamment du syst` eme) ` placer les fichiers sources ? Il est conseill Ou e de suivre la m eme r` egle pour le placement des chiers sources (chiers .java). Si on veut que la compilation dune classe C produise la compilation des
26. Si r est un r epertoire d eni par un chemin absolu (i.e. partant de la racine du syst` eme de chiers) A, on dit quun chemin B est relatif a ` r pour indiquer que B repr esente le chemin absolu obtenu en concat enant A et B. Par exemple, si le chemin monProjet/mesOutils/ est relatif au r epertoire /home/henri/ alors il d enit le chemin absolu /home/henri/monProjet/mesOutils/. 27. Dans les versions r ecentes du SDK, sauf besoin sp ecique il vaut mieux ne pas jouer avec la variable CLASSPATH. Sils ont et e bien install es, le compilateur et la machine Java acc` edent normalement a ` toutes les biblioth` eques de classes dont ils ont besoin dans le cadre dune utilisation normale de Java.

c H. Garreta, 2000-2013

27

5.2

Classes, chiers et r epertoires

CLASSES, PAQUETS, FICHIERS ET REPERTOIRES

classes dont C d epend 28 , ces derni` eres doivent se trouver dans les r epertoires qui correspondent ` a leurs paquets. Par exemple, si le chier MaClasse.java commence par linstruction package monPaquet; alors il vaut mieux placer ce chier dans le r epertoire monPaquet. Sa compilation sera alors provoqu ee soit par la compilation dune classe qui mentionne la classe monPaquet.MaClasse, soit par la commande javac -d . monPaquet/MaClasse.java 5.2.4 Comment distribuer une application Java ?

Dans la section pr ec edente on a expliqu e o` u placer les classes pour que lex ecution dun programme se passe bien, du moins lorsquelle a lieu sur la machine sur laquelle on a fait le d eveloppement. Mais que se passe-t-il lorsquun programme d evelopp e sur une machine doit etre ex ecut e sur une autre ? Dans le cas g en eral, la compilation dune application produit de nombreux chiers classes, eventuellement rang es dans di erents r epertoires (autant de r epertoires que de paquetages en jeu). Il en r esulte que, alors que pour dautres langages une application correspond ` a un chier executable, en Java une application se pr esente comme une pluralit e de chiers et de r epertoires ; une telle organisation rend complexe et risqu ee la distribution des applications. Cest pourquoi les ex ecutables Java sont distribu es sous la forme darchives zip ou, plut ot, jar 29 , quil faut savoir fabriquer. Expliquons cela sur un exemple : Imaginons quune application se compose des classes Principale, Moteur, Fenetres, etc., le point dentr ee cest-` a-dire la m ethode par laquelle lex ecution doit commencer 30 etant dans la classe Principale. La compilation de ces classes a produit les chiers Principale.class, Moteur.class, Fenetres.class, etc. Avec un editeur de textes quelconque, composez un chier nomm e MANIFEST.MF comportant lunique ligne Main-Class: Principale et tapez la commande : jar -cvfm Appli.jar MANIFEST.MF Principale.class Moteur.class Donnees.class etc. Notez que, si les classes constituant lapplication sont les seuls chiers .class du r epertoire de travail, vous pouvez taper la commande pr ec edente sous la forme jar -cvfm Appli.jar MANIFEST.MF *.class Cela produit un chier nomm e Appli.jar que, si vous etes curieux, vous pouvez examiner avec nimporte quel outil comprenant le format zip : vous y trouverez tous vos chiers .class et un r epertoire nomm e META-INF contenant le chier MANIFEST.MF un peu augment e: Manifest-Version: 1.0 Created-By: 1.5.0_05 (Sun Microsystems Inc.) Main-Class: Principale Cest ce chier Appli.jar que vos distribuerez. Quiconque souhaitera ex ecuter votre application pourra le faire en tapant la commande 31 java -jar Appli.jar ou bien java -classpath Appli.jar Principale Dans ce dernier cas, lapplication sex ecuterait correctement m eme si larchive ne contenait pas de chier manifeste, voire si au lieu de Appli.jar on avait utilis e une archive Appli.zip tout ` a fait ordinaire.

28. En principe, la compilation dune classe C produit la compilation des classes que C mentionne, pour lesquelles cela est utile, cest-` a-dire celles qui ont et e modi ees depuis leur derni` ere compilation. Cest un m ecanisme proche de la commande make de Unix mais lexp erience montre quil y a parfois des rat es (des classes qui le devraient ne sont pas recompil ees). 29. En r ealit e une archive jar est la m eme chose quune archive zip, sauf quune archive jar est cens ee contenir sans que la chose soit r edhibitoire un chier manifest. 30. Le point dentr ee est la premi` ere instruction dune m ethode qui doit avoir le prototype public static void main(String[] args), mais que rien nemp eche que des m ethodes ayant ce prototype existent aussi dans plusieurs autres classes de lapplication. 31. Sur un syst` eme Windows correctement congur e, on pourra m eme ex ecuter lapplication en double-cliquant sur lic one du chier jar. Dans ce cas, il y a int er et ` a ce quil sagisse dune application qui cr ee sa propre interface-utilisateur (par exemple, graphique) car autrement les entr ees-sorties seront perdues, faute de console.

28

c H. Garreta, 2000-2013

LES OBJETS

6
6.1

Les objets
Introduction : les langages orient es objets

Java est un langage orient e objets. Pour xer les id ees, voici une pr esentation tr` es sommaire dune partie du jargon et des concepts de base de cette famille de langages 32 . Objet. Les entit es el ementaires qui composent les programmes sont les objets. Un objet est constitu e par lassociation dune certaine quantit e de m emoire, organis ee en champs quon appelle des variables dinstance, et dun ensemble dop erations (fonctions, proc edures...) quon appelle des m ethodes. Contr ole de laccessibilit e. Les variables et les m ethodes peuvent etre quali ees publiques, cest-` a-dire accessibles depuis nimporte quel point du programme, ou priv ees, cest-` a-dire accessibles uniquement depuis les m ethodes de lobjet en question. Encapsulation. Un objet est vu par le reste du programme comme une entit e opaque : on ne peut modier son etat, cest-` a-dire les valeurs de ses variables, autrement quen faisant faire la modication par une de ses m ethodes publiques 33 . Lensemble des m ethodes publiques dun objet sappelle son interface 34 . Limportante propri et e suivante est ainsi garantie : un objet ne d epend pas des impl ementations (cesta-dire les d ` etails internes) dautres objets, mais uniquement de leurs interfaces. Message. Un message est une requ ete quon soumet ` a un objet pour quil eectue une de ses op erations. En pratique, cela se traduit par lappel dune m ethode de lobjet. Le message sp ecie quelle op eration doit etre eectu ee, mais non comment elle doit l etre : il incombe ` a lobjet r ecepteur du message de conna tre les modalit es eectives que prend pour lui lex ecution de lop eration en question. Appellation orient e objets . Du point de vue du concepteur, toute proc edure ou fonction appartient ` a un objet ; elle sp ecie comment un objet donn e r eagit ` a un message donn e. Dans la programmation orient ee objets les entit es les plus ext erieures sont les objets, les actions sont d enies ` a lint erieur des objets, comme attributs de ces derniers. Cela soppose ` a la programmation traditionnelle, ou orient ee actions , o` u les entit es les plus ext erieures sont les actions (proc edures, fonctions, routines, etc.) les objets se d enissant de mani` ere subordonn ee aux actions (ils en sont les donn ees, les r esultats, etc.). Classe. Une classe est la description des caract eristiques communes ` a tous les objets qui repr esentent la m eme sorte de chose. Vue de lext erieur, elle d enit donc leur interface commune, seul aspect public des objets. Vue de lint erieur, cest-` a-dire comme son concepteur la voit, la classe d enit la structure de la m emoire priv ee de ces objets (les variables dinstance) et les r eponses aux messages de leurs interfaces (les corps des m ethodes). Instance 35 . Les objets individuels d ecrits par une classe sont ses instances. Chaque objet est instance dune classe. Il ny a pas dinconv enient ` a identier la notion de classe avec celle de type, les instances sidentient alors avec les valeurs du type : la classe est le type de ses instances. Linstanciation est lop eration par laquelle les objets sont cr e es. Cest une notion dynamique (m eme dans les langages ` a types statiques) : tout objet est cr e e (a) enti` erement garni et (b) ` a un moment bien d etermin e de lex ecution dun programme.

6.2
6.2.1

Classes, variables et m ethodes


D eclaration des classes et des objets, instanciation des classes

Fondamentalement, une classe est constitu ee par un ensemble de membres, qui repr esentent des donn ees, on les appelle alors variables, champs, ou encore donn ees membres, des traitements, on les appelle alors m ethodes ou fonctions membres. La syntaxe de la d eclaration dune classe est la suivante :
32. Nous traitons ici de laspect encapsulation des langages orient es objets. On introduira plus loin les concepts li es ` a lh eritage. 33. En Java, la possibilit e davoir des variables dinstance publiques temp` ere cette armation. 34. Attention, en Java le mot interface a un sens technique bien pr ecis, voir la section 7.7.3 35. Le mot instance est tr` es souvent employ e en programmation orient ee objets, avec le sens expliqu e ici (qui se r esume tout entier dans lincantation chaque objet est une instance de sa classe ). Si ce mot vous pose un probl` eme, ne cherchez pas de laide parmi les sens quil a dans la langue fran caise, aucun ne convient. Il a et e emprunt e par les p` eres fondateurs de la POO ` a la langue anglaise, o` u entre autres choses, instance signie cas, comme dans cas particulier.

c H. Garreta, 2000-2013

29

6.2

Classes, variables et m ethodes

LES OBJETS

visibilit e class identicateur { d eclaration dun membre ... d eclaration dun membre } ou visibilit e est soit rien, soit le mot public (la classe est alors dite publique, voyez la section 5.2.1). Les membres des classes se d eclarent comme les variables et les fonctions en C, sauf quon peut les pr exer par certains qualieurs, private, public, etc., expliqu es plus loin. Exemple : class Point { int x, y; // coordonn ees cart esiennes void montre() { System.out.println("(" + x + "," + y + ")"); } double distance(Point p) { int dx = x - p.x; int dy = y - p.y; return Math.sqrt(dx * dx + dy * dy); } } Une classe est un type de donn ees : ` a la suite dune d eclaration comme la pr ec edente, on pourra d eclarer des variables de type Point, cest-` a-dire des variables dont les valeurs sont des instances de la classe Point et ont la structure d enie par cette derni` ere. Exemple : Point p; // d eclaration dune variable Point

Notez bien que la d eclaration pr ec edente introduit une variable p qui pourra r ef erencer des instances de la classe Point, mais qui, pour le moment, ne r ef erence rien. Selon son contexte, une d eclaration comme la pr ec edente donnera ` ap: soit la valeur null, dans le cas de la d eclaration dune variable membre, soit une valeur conventionnelle variable non initialis ee , dans le cas de la d eclaration dune variable locale dune m ethode. On obtient que p soit une r ef erence valide sur un objet soit en lui aectant une instance existante, soit en lui aectant une instance nouvellement cr e ee, ce qui s ecrit : p = new Point(); // cr eation dune nouvelle instance de la classe Point

La justication des parenth` eses ci-dessus, et dautres informations importantes sur linstanciation et linitialisation des objets, sont donn ees ` a la section 6.5.1. Note. Etant donn ee une classe C, on dit indi eremment instance de la classe C ou objet C. 6.2.2 Instances et membres dinstance

La d eclaration donn ee en exemple ` a la section pr ec edente introduit une classe Point, comportant pour le moment deux variables dinstance, x et y, et deux m ethodes dinstance, montre et distance. En disant que ces el ements sont des variables et des m ethodes dinstance de la classe Point on veut dire que chaque instance en a sa propre version , cest-` a-dire : pour les variables, quil en existe un jeu di erent dans chaque instance, disjoint de ceux des autres instances : chaque objet Point a sa propre valeur de x et sa propre valeur de y, pour les m ethodes, quelles sont li ees ` a un objet particulier : un appel de la m ethode montre na de sens que sil est adress e` a un objet Point (celui quil sagit de montrer). Ainsi, sauf dans quelques situations particuli` eres que nous expliciterons plus loin, pour acc eder ` a un membre dinstance il faut indiquer linstance concern ee. Cela se fait par la m eme notation que lacc` es aux champs des structures en C : p.x p.montre() : un acc` es ` a la variable dinstance x de lobjet p : un appel de la m ethode montre sur lobjet p

Lexpression p.montre() est la version Java de la notion, fondamentale en programmation orient ee objets, envoyer le message montre ` a lobjet p . A priori, le m eme message pourrait etre envoy e ` a des objets di erents. Il incombe ` a chaque destinataire, ici p, de conna tre les d etails pr ecis que prend pour lui la r eaction au message montre. 30
c H. Garreta, 2000-2013

LES OBJETS

6.2

Classes, variables et m ethodes

`s a ` ses propres membres. Ainsi, une m Acce ethode dinstance est n ecessairement appel ee ` a travers un objet, le destinataire du message que la m ethode repr esente. Dans le corps de la m ethode, cet objet est implicitement r ef erenc e par toutes les expressions qui mentionnent des membres dinstance sans les associer a un objet explicite. ` Par exemple, dans la m ethode distance de la classe Point : ... double distance(Point p) { int dx = x - p.x; int dy = y - p.y; return Math.sqrt(dx * dx + dy * dy); } ... les variables x et y qui apparaissent seules d esignent les coordonn ees de lobjet ` a travers lequel on aura appel e la m ethode distance. Dautre part, les expressions p.x et p.y d esignent les coordonn ees de lobjet qui aura et e mis comme argument de cet appel. Ainsi, ` a loccasion dun appel de la forme (a et b sont des variables de type Point) : a.distance(b); le corps de la m ethode distance equivaut ` a la suite dinstructions : { int dx = a.x - b.x; int dy = a.y - b.y; return Math.sqrt(dx * dx + dy * dy); } `s a ` soi-me me. A lint Acce erieur dune m ethode dinstance, lidenticateur this d esigne lobjet ` a travers lequel la m ethode a et e appel ee. Par exemple, la m ethode distance pr ec edente peut aussi s ecrire, mais ici cela na gu` ere davantages 36 , comme ceci : ... double distance(Point p) { int dx = this.x - p.x; int dy = this.y - p.y; return Math.sqrt(dx * dx + dy * dy); } ... Pour voir un exemple o` u lemploi de this est n ecessaire, imaginez quon nous oblige ` a ecrire la m ethode dinstance distance en la ramenant ` a un appel dune m ethode de classe : static int distanceSymetrique(Point a, Point b); cest-` a-dire une m ethode qui, comme une fonction en C, nest pas attach ee ` a une instance particuli` ere et calcule la distance entre les deux points donn es comme arguments. Cela donnerait : ... int distance(Point p) { return distanceSymetrique(this, p); } ... 6.2.3 Membres de classe (membres statiques)

Les membres de classe sont ceux dont la d eclaration est quali ee par le mot r eserv e static 37 : class Point { int x, y; static int nombre; void montre() { System.out.println("(" + x + "," + y + ")"); } static int distanceSymetrique(Point p, Point q) { // variables dinstance // variable de classe // m ethode dinstance

// m ethode de classe

36. Notez cependant que certains stylistes de la programmation en Java recommandent demployer syst ematiquement la notation this.variabledInstance ou this.methodedInstance (...) pour les membres dinstance, et proscrivent cette notation pour les membres statiques (cf. section 6.2.3) ; cela permet ` a un lecteur du programme de distinguer plus facilement ces deux sortes de membres lors de leur utilisation. 37. Par la suite on dira indi eremment membre de classe ou membre statique et membre dinstance ou membre non statique.

c H. Garreta, 2000-2013

31

6.2

Classes, variables et m ethodes

LES OBJETS

return Math.abs(p.x - q.x) + Math.abs(p.y - q.y); } } Contrairement aux membres dinstance, les membres de classe ne sont pas attach es aux instances. Ce qui signie : pour une variable, quil ny en a quune. Alors que de chaque variable dinstance il y a un exemplaire pour chaque objet eectivement cr e e par lex ecution du programme, de chaque variable de classe il est cr e e la premi` ere fois que la classe intervient dans lex ecution du programme un unique exemplaire auquel toutes les instances acc` edent, pour une m ethode, quon peut lappeler sans devoir passer par un objet. Lappel dune m ethode de classe ne se fait pas en faisant r ef erence explicitement ou implicitement ` a une instance particuli` ere (autre que celles qui gurent eventuellement ` a titre de param` etres) ; un tel appel ne peut dont pas etre vu comme un message adress e` a un objet. Cons equence importante : ` a lint erieur dune m ethode de classe, lobjet this (objet implicite ` a travers lequel une m ethode dinstance est n ecessairement appel ee) nest pas d eni. Ainsi lexpression suivante, par exemple ecrite dans une m ethode etrang` ere ` a la classe Point : Point.nombre est un acc` es bien ecrit ` a la variable de classe nombre et, p et q etant des objets Point, lexpression Point.distanceSymetrique(p, q) est un appel correct de la m ethode de classe distanceSymetrique. Remarque 1. On notera que les deux expressions pr ec edentes peuvent s ecrire aussi p.nombre p.distanceSymetrique(p, q) (le pr exe p. ne sert ici qu` a indiquer quil sagit des membres nombre et distance de la classe Point ; ces expressions ne font aucun usage implicite de lobjet p) mais ces notations sont trompeuses et d econseill ees car elles donnent aux acc` es ` a des membres de classe lapparence dacc` es ` a des membres dinstance. Remarque 2. On aura compris que les m ethodes de classe sont ce qui se rapproche le plus, en Java, des fonctions autonomes , comme celles du langage C. Par exemple, la m ethode Math.sqrt, mentionn ee plus haut, nest rien dautre que la fonction racine carr ee qui existe dans toutes les biblioth` eques math ematiques. Lobligation denfermer de telles fonctions dans des classes nest pas une contrainte mais une richesse, puisque cela permet davoir, dans des classes di erentes, des fonctions qui ont le m eme nom. De m eme, la notion de variable de classe est voisine de celle de variable globale du langage C. De telles variables existent d` es que la classe est charg ee, cest-` a-dire la premi` ere fois quelle intervient dans le programme, jusqu` a la terminaison de celui-ci. Remarque 3. Pour bien mettre en evidence les di erences entre les membres de classe et les membres dinstance, examinons une erreur quon peut faire quand on d ebute : public class Essai { void test() { ... } public static void main(String[] args) { test(); // *** ERREUR *** } } Sur lappel de test on obtient une erreur Cannot make a static reference to the non-static method test . Cela signie que la m ethode test ne peut etre appel ee quen se r ef erant, explicitement ou implicitement, ` a un objet, alors que main etant static, elle nest li ee ` a aucun objet (en fait, dans ce programme on ne cr ee aucune instance de la classe Essai). Deux solutions. La premi` ere consiste ` a cr eer une instance, eventuellement un peu articielle, permettant dappeler test en passant par un objet : 32
c H. Garreta, 2000-2013

LES OBJETS

6.3

Surcharge des noms

public class Essai { void test() { ... } public static void main(String[] args) { Essai unEssai = new Essai(); unEssai.test(); // OK } } La deuxi` eme, plus simple, consiste ` a rendre test statique : public class Essai { static void test() { ... } public static void main(String[] args) { test(); // OK } }

6.3

Surcharge des noms

En Java les noms peuvent etre surcharg es : un m eme nom peut d esigner plusieurs entit es distinctes, ` a la condition que lors de chaque utilisation du nom le compilateur puisse d eterminer sans erreur quelle est lentit e d esign ee. En pratique, cela signie quon peut donner le m eme nom ` a des entit es dont les r oles syntaxiques sont di erents, comme une classe et un membre, ou bien une variable et une m ethode, ` a des membres de classes distinctes, ` a des m ethodes de la m eme classe ayant des signatures 38 di erentes. Par exemple, dans la classe Math on trouve, parmi dautres, les m ethodes int abs(int x) (valeur absolue dun entier), float abs(float x) (valeur absolue dun ottant), double abs(double x), etc. Lorsque le compilateur rencontre une expression comme u = Math.abs(v); la m ethode eectivement appel ee est celle qui correspond au type eectif de v. Lint er et de ce m ecanisme est facile ` a voir : il dispense le programmeur davoir ` a conna tre toute une s erie de noms di erents (un pour chaque type dargument) pour nommer les diverses impl ementations dun m eme concept, la valeur absolue dun nombre. On notera que le type du r esultat dune m ethode ne fait pas partie de sa signature : deux m ethodes dune m eme classe, ayant les m emes types darguments mais di erant par le type du r esultat quelles rendent ne peuvent pas avoir le m eme nom. Remarque. Il ne faut pas confondre la surcharge avec la red enition des m ethodes, que nous expliquerons a la section 7.3 : ` 1. La surcharge des m ethodes consiste dans le fait que deux m ethodes, souvent membres de la m eme classe, ont le m eme nom mais des signatures di erentes. Sur un appel de m ethode faisant appara tre ce nom, la d etermination de la m ethode quil faut eectivement appeler est faite dapr` es les arguments de lappel. Cest un probl` eme statique, cest-` a-dire r esolu pendant la compilation du programme. 2. La red enition des m ethodes consiste dans le fait que deux m ethodes ayant le m eme nom et la m eme signature sont d enies dans deux classes dont lune est sous-classe, directe ou indirecte, de lautre. Nous verrons que, sur lappel dune m ethode ayant ce nom, la d etermination de la m ethode quil faut eectivement appeler est faite dapr` es le type eectif de lobjet destinataire du message. Cest un m ecanisme dynamique, qui intervient au moment de lex ecution du programme.
38. La signature dune m ethode est la liste des types des ses arguments.

c H. Garreta, 2000-2013

33

6.4

Contr ole de laccessibilit e

LES OBJETS

6.4
6.4.1

Contr ole de laccessibilit e


Membres priv es, prot eg es, publics

La d eclaration dun membre dune classe (variable ou m ethode, dinstance ou de classe) peut etre quali ee par un des mots r eserv es private, protected ou public, ou bien ne comporter aucun de ces qualieurs. Cela fonctionne de la mani` ere suivante : membres priv es : un membre dune classe C dont la d eclaration commence par le qualieur private nest accessible que depuis [les m ethodes de] la classe C ; cest le contr ole dacc` es le plus restrictif, un membre dune classe C dont la d eclaration ne commence pas par un des mots private, protected ou public est dit avoir laccessibilit e par d efaut ; il nest accessible que depuis [les m ethodes de] la classe C et les autres classes du paquet auquel C appartient, membres prot eg es : un membre dune classe C dont la d eclaration commence par le qualieur protected nest accessible que depuis [les m ethodes de] la classe C , les autres classes du paquet auquel C appartient et les sous-classes, directes ou indirectes, de C , membres publics : un membre de la classe C dont la d eclaration commence par le qualieur public est accessible partout o` u C est accessible ; cest le contr ole dacc` es le plus permissif. Le concept de membre prot eg e est li e` a la notion dh eritage. Pour cette raison, ces membres sont expliqu es plus en d etail ` a la section 7.5 (page 46). 6.4.2 Lencapsulation

Quand on d ebute dans la programmation orient ee objets on peut trouver que le contr ole de laccessibilit e est une chinoiserie peu utile. Il faut comprendre, au contraire, que cette question est un el ement fondamental de la m ethodologie. En eet, nous cherchons ` a ecrire des programmes les plus modulaires possibles, or lencapsulation est lexpression ultime de la modularit e : faire en sorte que chaque objet du syst` eme que nous d eveloppons ne puisse pas d ependre de d etails internes des autres objets. Ou, dit autrement, garantir que chaque objet sappuie sur les sp ecications des autres, non sur leurs impl ementations. Il en d ecoule une r` egle de programmation simple : tout membre qui peut etre rendu priv e doit l etre 39 . Pour illustrer cette question, consid erons notre classe Point, et supposons que nous souhaitions permettre ` ses utilisateurs dacc a eder ` a labscisse et ` a lordonn ee des points. Premi` ere solution, rendre les membres x et y publics : class Point { public int x, y; ... } Exemple dutilisation : si p est un objet Point, pour transformer un point en son sym etrique par rapport ` a laxe des abscisses il sura d ecrire : p.y = - p.y; Voici une autre d enition possible de la classe Point : class Point { private int x, y; public int getX() { return x; } public int getY() { return y; } public void setPos(int a, int b) { validation de a et b x = a; y = b; } ... } avec cette d enition, pour transformer un point p en son sym etrique par rapport ` a laxe des abscisses il faut ecrire : p.setPos(p.getX(), - p.getY());
39. Certains langages vont plus loin, et font que toutes les variables sont doce priv ees. Java permet de d eclarer des variables dinstance et de classe publiques ; notre propos ici est de d econseiller de telles pratiques.

34

c H. Garreta, 2000-2013

LES OBJETS

6.5

Initialisation des objets

Malgr e les apparences, la deuxi` eme mani` ere est la meilleure, car elle respecte le principe dencapsulation, ce que ne fait pas la premi` ere. Dabord, cette deuxi` eme d enition permet de garantir la coh erence interne des objets cr e es par les utilisateurs de la classe Point, y compris les plus etourdis, puisque le seul moyen de modier les valeurs des variables dinstance x et y est dappeler la m ethode setPos, dans laquelle le concepteur de la classe a ecrit le code qui valide ces valeurs (partie validation de a et b ). Ensuite, la deuxi` eme d enition garantit quaucun d eveloppement utilisant les objets Point ne fera intervenir des d etails de limpl ementation de cette classe, puisque les variables dinstance x et y sont priv ees, cest-` a-dire inaccessibles. Par exemple, si un jour il devenait n ecessaire de repr esenter les points par leurs coordonn ees polaires au lieu des coordonn ees cart esiennes, cela pourrait etre fait sans rendre invalide aucun programme utilisant la classe Point puisque, vu de lext erieur, le comportement de la classe Point serait maintenu : class Point { private double rho, theta; public int getX() { return (int) (rho * Math.cos(theta)); } public int getY() { return (int) (rho * Math.sin(theta)); } public void setPos(int a, int b) { rho = Math.sqrt(a * a + b * b); theta = Math.atan2(b, a); } ... }

6.5

Initialisation des objets

En Java la cr eation dun objet est toujours dynamique : elle consiste en un appel de lop erateur new, et peut se produire ` a nimporte quel endroit dun programme. Il faut savoir que les variables dinstance des objets ne restent jamais ind etermin ees, elles ont des valeurs initiales pr ecises. Un el ement de la m ethodologie objet, tr` es important pour la qualit e des programmes, est que le concepteur dune classe ma trise compl` etement les actions ` a faire et les valeurs initiales ` a donner lors de la cr eation des instances ; il peut ainsi garantir que les objets sont, d` es leur cr eation, toujours coh erents. Notons pour commencer que, sil ny a pas dautres indications, Java donne une valeur initiale ` a chaque membre dune classe. Pour les membres de types primitifs, la valeur initiale correspondant ` a chaque type est celle quindique le tableau 1 (page 11). Pour les membres dautres types, cest-` a-dire les tableaux et les objets, la valeur initiale est null. Ainsi, sans que le programmeur nait ` a prendre de pr ecaution particuli` ere, les instances dune classe d eclar ee comme ceci class Point { int x, y; ... } sont des points ayant (0, 0) pour coordonn ees. Lorsque linitialisation souhait ee est plus complexe que linitialisation par d efaut, mais assez simple pour s ecrire comme un ensemble daectations ind ependantes de linstance particuli` ere cr e ee, on peut employer une notation analogue ` a celle de C. Par exemple, voici une classe Point dont les instances sont des points al eatoirement dispos es dans le rectangle [0, 600[[0, 400[ : class Point { int x = (int) (Math.random() * 600); int y = (int) (Math.random() * 400); ... } Lorsque linitialisation requise est plus complexe quune suite daectations, ou lorsquelle d epend d el ements li es au contexte dans lequel lobjet est cr e ee, la notation pr ec edente est insusante. Il faut alors d enir un ou plusieurs constructeurs, comme expliqu e` a la section suivante.
c H. Garreta, 2000-2013

35

6.5

Initialisation des objets

LES OBJETS

6.5.1

Constructeurs

Un constructeur dune classe est une m ethode qui a le m eme nom que la classe et pas de type du r esultat 40 . Exemple : class Point { private int x, y; public Point(int a, int b) { validation de a et b x = a; y = b; } ... } Un constructeur est toujours appel e de la m eme mani` ere : lors de la cr eation dun objet, cest-` a-dire comme op erande de lop erateur new : Point p = new Point(200, 150); Dans un constructeur on ne doit pas trouver dinstruction de la forme return expression ; : un constructeur ne rend rien (cest lop erateur new qui rend quelque chose, ` a savoir une r ef erence sur lobjet nouveau), son r ole est dinitialiser les variables dinstance de lobjet en cours de cr eation, et plus g en eralement deectuer toutes les op erations requises par la cr eation de lobjet. Comme les autres m ethodes, les constructeurs peuvent etre quali es public, protected ou private, ou avoir laccessibilit e par d efaut. Une situation utile et fr equente est celle montr ee ci-dessus : un ou plusieurs constructeurs publics servant surtout ` a initialiser un ensemble de variables dinstance priv ees. La surcharge des m ethodes vaut pour les constructeurs : une classe peut avoir plusieurs constructeurs, qui devront alors di erer par leurs signatures : class Point { private int x, y; public Point(int a, int b) { validation de a et b x = a; y = b; } public Point(int a) { validation de a x = a; y = 0; } ... } A lint erieur dun constructeur lidenticateur this utilis e comme un nom de variable d esigne (comme dans les autres m ethodes dinstance) lobjet en cours de construction. Cela permet parfois de lever certaines ambigu t es ; par exemple, le constructeur ` a deux arguments donn e plus haut peut s ecrire aussi 41 : class Point { private int x, y; public Point(int x, int y) { validation de x et y this.x = x; this.y = y; } ... }
40. Nous lavons d ej` a dit, le type du r esultat dune m ethode ne fait pas partie de sa signature. N eanmoins, le fait davoir ou non un type du r esultat est un el ement de la signature. Il en d ecoule que, par exemple, dans une certaine classe Point peuvent coexister un constructeur Point() et une m ethode void Point() distincts. 41. Parfois les noms des arguments des m ethodes ne sont pas indi erents, ne serait-ce quen vue de la documentation (ne pas oublier que loutil javadoc fabrique la documentation ` a partir du code source).

36

c H. Garreta, 2000-2013

LES OBJETS

6.5

Initialisation des objets

A lint erieur dun constructeur, lidenticateur this, utilis e comme un nom de m ethode, d esigne un autre constructeur de la m eme classe (celui qui correspond aux arguments de lappel). Par exemple, voici une autre mani` ere d ecrire le second constructeur de la classe Point montr ee plus haut : class Point { private int x, y; public Point(int x, int y) { validation de x et y this.x = x; this.y = y; ... } public Point(int x) { this(x, 0); ... } ... } Note 1. Lorsquun tel appel de this(...) appara t, il doit etre la premi` ere instruction du constructeur. Note 2. Lexpression qui cr ee un objet, new UneClasse() , se pr esente toujours comme lappel dun constructeur, m eme lorsque le programmeur na ecrit aucun constructeur pour la classe en question. Tout se passe comme si Java avait dans ce cas ajout e` a la classe un constructeur implicite, r eduit ` a ceci : UneClasse() { super(); } (la signication de lexpression super() est explique ` a la section 7.4) 6.5.2 Membres constants (final)

La d eclaration dun membre dune classe peut commencer par le qualieur final. Nous verrons ` a la section 7.6.3 ce que cela veut dire pour une m ethode ; pour une variable, cela signie quune fois initialis ee, elle ne pourra plus changer de valeur ; en particulier, toute apparition de cette variable ` a gauche dune aectation sera refus ee par le compilateur. Une telle variable est donc plut ot une constante. Par exemple, voici comment d eclarer une classe dont les instances sont des points immuables : class Point { final int x, y; Point(int a, int b) { validation de a et b x = a; y = b; } ... } N.B. Les aectations de x et y qui apparaissent dans le constructeur sont accept ees par le compilateur, car il les reconna t comme des initialisations ; toute autre aectation de ces variables sera refus ee. Le programmeur a donc deux mani` eres dassurer que des variables dinstance ne seront jamais modi ees une fois les instances cr ees : qualier ces variables final ou bien les qualier private et ne pas d enir de m ethode qui permettrait de les modier. La premi` ere mani` ere est pr ef erable, car la qualication private nemp eche pas quune variable soit modi ee depuis une m ethode de la m eme classe, la qualication final informe le compilateur du caract` ere constant de la variable en question, celui-ci peut donc eectuer les optimisations que ce caract` ere constant permet. Constantes de classe. Les variables de classe peuvent elles aussi etre quali ees final ; elles sont alors tr` es proches des pseudo-constantes quon d enit en C par la directive #define. La coutume est de nommer ces variables par des identicateurs tout en majuscules :
c H. Garreta, 2000-2013

37

6.5

Initialisation des objets

LES OBJETS

public class Point { public static final int XMAX = 600; public static final int YMAX = 400; private int x, y; public Point(int x, int y) throws Exception { if (x < 0 || x >= XMAX || y < 0 || y > YMAX) throw new Exception("Coordonn ees invalides pour un Point"); this.x = x; this.y = y; } ... } 6.5.3 Blocs dinitialisation statiques

Les constructeurs des classes sont appel es lors de la cr eation des objets, ce qui est tout ` a fait adapt e` a linitialisation des variables dinstance. Mais comment obtenir linitialisation dune variable de classe, lorsque cette initialisation est plus complexe quune simple aectation ? Un bloc dinitialisation statique est une suite dinstructions, encadr ee par une paire daccolades, pr ec ed ee du mot static. Ces blocs (et les autres aectations servant ` a initialiser des variables de classe) sont ex ecut es, dans lordre o` u ils sont ecrits, lors du chargement de la classe, cest-` a-dire avant toute cr eation dune instance et avant tout acc` es ` a une variable ou ` a une m ethode de classe. Exemple : public class Point { public static int xMax; public static int yMax; static { Dimension taillEcran = Toolkit.getDefaultToolkit().getScreenSize(); xMax = taillEcran.width; yMax = taillEcran.height; } ... } 6.5.4 Destruction des objets

Dans beaucoup de langages, comme C et C++, lop eration de cr eation des objets (malloc, new, etc.) est coupl ee ` a une op eration sym etrique de lib eration de la m emoire (free, delete, etc.) que le programmeur doit explicitement appeler lorsquun objet cesse d etre utile. Dans ces langages, loubli de la restitution de la m emoire allou ee est une cause derreurs sournoises dans les programmes. Or, lorsque les objets sont complexes, la lib eration compl` ete et correcte de la m emoire quils occupent, eectu ee par des m ethodes appel ees destructeurs, est un probl` eme souvent dicile. Voici une bonne nouvelle : en Java il ny a pas dop eration de lib eration de la m emoire ; en particulier, on na pas besoin de munir les classes de destructeurs qui seraient le pendant des constructeurs 42 . Quand un objet cesse d etre utile on loublie, tout simplement. Exemple : Point p = new Point(a, b); ... p = new Point(u, v); ici, le point P(a,b) a et e oubli e ... p = null; maintenant, le point P(u,v) a et e oubli e egalement ... Si un programme peut tourner longtemps sans jamais soccuper de la destruction des objets devenus caducs cest que la machine Java int` egre un m ecanisme, appel e garbage collector, qui r ecup` ere la m emoire
42. Attention, ne prenez pas pour un destructeur la m ethode finalize, une notion dicile ` a cerner et ` a utiliser que nous nexpliquerons pas dans ce cours.

38

c H. Garreta, 2000-2013

LES OBJETS

6.6

Classes internes et anonymes

inutilis ee. A cet eet Java maintient dans chaque objet le d ecompte des r ef erences que lobjet supporte, et r ecup` ere lespace occup e par tout objet dont le nombre de r ef erences devient nul 43 . Ce m ecanisme, qui implique le parcours de structures eventuellement tr` es complexes, se met en marche automatiquement lorsque la m emoire libre vient ` a manquer, et aussi en tache de fond lorsque la machine est oisive ou eectue des op erations lentes, comme des acc` es r eseau ou des lectures au clavier.

6.6

Classes internes et anonymes

Cette section pointue peut etre ignor ee en premi` ere lecture. 6.6.1 Classes internes

Si la seule utilit e dune classe I est de satisfaire les besoins dune autre classe E alors on peut d enir I ` lint a erieur de E . On dit que I est une classe interne, et que E est la classe englobante de I . Cela a deux cons equences majeures : une cons equence statique, facile ` a comprendre : ` a lint erieur de la classe englobante le nom de la classe interne peut etre employ e tel quel, mais ` a lext erieur de la classe englobante le nom de la classe interne nest utilisable que sil est pr ex e par le nom de la classe englobante ou par celui dune instance de cette classe ; il en r esulte une diminution, toujours bienvenue, du risque de collisions de noms, une cons equence dynamique, bien plus subtile : si elle nest pas d eclar ee static, la classe interne est li ee ` a une instance particuli` ere de la classe englobante, ` a laquelle elle fait implicitement r ef erence. Exemple. La classe Automobile est destin ee ` a repr esenter les divers mod` eles au catalogue dun constructeur. Un m eme mod` ele est fabriqu e avec di erents moteurs. Il a et e d ecid e que la classe Moteur na dint er et qu` a lint erieur de la classe Automobile 44 : class Automobile { String modele; Moteur moteur; Automobile(String m, int c) { modele = m; moteur = new Moteur(c); } class Moteur { int cylindree; Moteur(int c) { cylindree = c; } public String toString() { return "Moteur de " + cylindree + " cc du " + modele; } } public static void main(String[] args) { Automobile auto = new Automobile("coup e", 2400); System.out.println(auto.moteur); } } Regardez bien la m ethode toString ci-dessus : les deux variables cylindree et modele qui y apparaissent ont des statuts di erents, puisque cylindree appartient ` a une instance de Moteur, tandis que modele est li ee ` a une instance dAutomobile.
43. On peut expliquer le fonctionnement du garbage collector de la mani` ere suivante : un objet est vivant sil est (a) la valeur dune variable de classe dune classe charg ee, (b) la valeur dune variable dinstance dun objet vivant ou (c) la valeur dune variable locale dune m ethode active. Le travail du garbage collector se compose, au moins logiquement, de trois phases : (1) parcourir tous les objets vivants et marquer les cellules m emoire quils occupent, (2) noter comme etant r eutilisables toutes les cellules non marqu ees pendant la phase pr ec edente et (3) de temps en temps, r earranger la m emoire pour regrouper les cellules r eutilisables, de mani` ere ` a lutter contre l emiettement de lespace disponible. 44. Il y l` a un choix de conception tr` es discutable (m eme sil para t normal que le moteur soit ` a lint erieur de lautomobile !) car cela interdit que deux mod` eles dautomobile distincts aient le m eme moteur.

c H. Garreta, 2000-2013

39

6.6

Classes internes et anonymes

LES OBJETS

Puisque la classe Moteur toute enti` ere est un membre non statique de la classe Automobile, la premi` ere ne peut etre acc ed ee qu` a travers une instance particuli` ere de la seconde. Ainsi, par exemple, le constructeur de Moteur est une m ethode dinstance de Automobile. Il en r esulte que dans les m ethodes dinstance de Moteur deux variables this sont d enies : celle qui identie un objet Moteur particulier et celle qui identie lobjet Automobile dans lequel cet objet Moteur a et e cr e e. On peut dire que ce deuxi` eme this se comporte comme une variable de classe de la classe Moteur, a la condition de comprendre quil y en aura un di ` erent pour chaque instance de la classe Automobile. A lint erieur dune instance de Moteur, ces deux variables peuvent etre atteintes par les appellations respectives this et Automobile.this. 6.6.2 Classes anonymes

Les classes anonymes sont des classes internes cr e ees ` a la vol ee au moment de leur instanciation, comme les tableaux anonymes (cf. section 3.4.4). Cela est particuli` erement utile lorsquil faut d enir une sous-classe dune classe donn ee, ou une classe impl ementant une interface donn ee, alors quon na besoin que dune seule instance de la nouvelle classe. Par exemple, linstruction suivante cr ee dans la foul ee une classe anonyme, sous-classe de la classe Point, dans laquelle la m ethode toString est red enie, et une instance (qui restera unique) de la classe anonyme ainsi d enie : Point o = new Point(0, 0) { public String toString() { return "[0rigine]"; } };

// lobjet o est un Point ordinaire, sauf // pour ce qui concerne la m ethode toString

Si, apr` es la compilation de la classe Point ci-dessus, on examine la liste des chiers produits par le compilateur on trouvera les deux chiers Point.class et Point$1.class. Le second traduit la cr eation dune classe anonyme ` a loccasion de linstanciation pr ec edente. Autre exemple, tir e de la gestion des ev enements dans AWT : pour attacher un auditeur d ev enements action ` a un composant produisant de tels ev enements, comme un bouton ou un menu, il faut ex ecuter linstruction : composant .addActionListener(auditeur ); o` u auditeur est un objet dune classe impl ementant linterface ActionListener. Or cette interface se compose dune unique m ethode, actionPerformed. On sen sort donc ` a moindres frais avec une classe anonyme : composant .addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { traitement de l ev enement } });

40

c H. Garreta, 2000-2013

HERITAGE

7
7.1

H eritage
Introduction : raner, abstraire

Pour approcher la notion dh eritage, examinons deux sortes de besoins quil satisfait, l eg` erement di erents. Le premier, que nous appellerons ranement, correspond ` a la situation suivante : on dispose dune classe A achev ee, op erationnelle, d enissant des objets satisfaisants, et il nous faut d enir une classe B qui en est une extension : les objets B ont tout ce quont les objets A plus quelques variables et m ethodes ajout ees et/ou quelques m ethodes am elior ees (on dira red enies ). Imaginez, par exemple, quon dispose dune classe RectangleGeometrique pour repr esenter des rectangles en tant quentit es math ematiques, avec des variables dinstance (x, y, largeur, hauteur, etc.) et des m ethodes (translation, rotation, etc.) et quil nous faille une classe RectangleGraphique dont les instances sont des entit es rectangulaires capables de sacher sur un ecran. Elles comportent donc tout ce qui fait un RectangleGeometrique et, en plus, quelques variables (couleurFond, couleurBord, epaisseurBord, etc.) et m ethodes suppl ementaires (affichage, transformationCouleur, etc.).

Rectangle Gomtrique

membres d'un Rectangle Geometrique

Rectangle Graphique

membres d'un Rectangle Geometrique membres additionnels

Rectangle Gomtrique

membres d'un Rectangle Geometrique

extends

Rectangle Graphique

membres additionnels

Figure 7 Raner Si nous ne disposions que des outils expliqu es dans les chapitres pr ec edents, nous devrions d enir la classe RectangleGraphique en y dupliquant (cf. gure 7, ` a gauche) les informations qui se trouvent dans la d enition de RectangleGeometrique. Le m ecanisme de lh eritage permet d eviter cette duplication, en nous laissant d eclarer d` es le commencement que la classe RectangleGraphique etend la classe RectangleGeometrique et en poss` ede donc tous les attributs (cf. gure 7, ` a droite). De cette mani` ere, il ne nous reste ` a d enir que les membres sp eciques que la deuxi` eme classe (que nous appellerons la sous-classe ) ajoute ` a la premi` ere (la super-classe ). Une deuxi` eme sorte de besoins auxquels lh eritage sattaque sont ceux qui se manifestent lorsquon a ` d a evelopper plusieurs classes poss edant un ensemble de membres communs. Sans lh eritage, ces derniers devraient etre d eclar es en autant dexemplaires quil y a de classes qui en ont besoin. Lh eritage va nous permettre de les d eclarer une seule fois, dans une classe distincte, invent ee pour loccasion, dont la seule justication sera de contenir ces membres communs ` a plusieurs autres.

RectangleGraphique membres communs membres spcifiques d'un rectangle

EllipseGraphique membres communs

Objet graphique

membres communs

extends

extends

membres spcifiques d'une ellipse

membres spcifiques d'un rectangle RectangleGraphique

membres spcifiques d'une ellipse EllipseGraphique

Figure 8 Abstraire

c H. Garreta, 2000-2013

41

7.2

Sous-classes et super-classes

HERITAGE

Imaginons par exemple une application manipulant plusieurs sortes dobjets susceptibles de sacher sur un ecran : des rectangles, des ellipses, des polygones, etc. Il faudra d enir plusieurs classes distinctes, comportant des el ements sp eciques on ne dessine pas un rectangle comme on dessine une ellipse mais aussi des el ements communs, aussi bien des variables (la couleur du fond, la couleur et l epaisseur du bord, etc.) que des m ethodes (positionnement, translation, etc.) Voyez la gure 8 (droite) : lh eritage permet de d enir des classes RectangleGraphique, EllipseGraphique, etc., dans lesquelles seuls les el ements sp eciques sont sp eci es, car elles sont d eclar ees comme des extensions dune classe ObjetGraphique o` u sont d enis les el ements communs ` a toutes ces autres classes. Il y a une di erence tr` es pr ecise entre cette situation et la pr ec edente : la classe ObjetGraphique ne doit pas avoir des instances. Un objet qui serait un ObjetGraphique sans etre quelque chose de plus concret (un RectangleGraphique, une EllipseGraphique, etc.) naurait pas de sens. Pour exprimer cette propri et e on dit que ObjetGraphique est une classe abstraite. Elle est un moyen commode et puissant pour d esigner collectivement les diverses sortes dobjets destin es ` a lachage, mais pour la cr eation dune tel objet il faut toujours utiliser une classe concr` ete. Remarque pointue. Voyant les deux exemples pr ec edents on peut se demander sil est possible de d enir la classe RectangleGraphique comme sous-classe en m eme temps de RectangleGeometrique et dObjetGraphique. La r eponse est non, en Java lh eritage est simple : pour des raisons aussi bien decacit e que de simplicit e conceptuelle, une classe ne peut etre un ranement que dune seule autre. Cependant nous introduirons, le moment venu, la notion dinterface (une interface est une classe tr` es abstraite) et on verra quune classe peut etre sous-classe de plusieurs interfaces, la relation dh eritage se nommant alors impl ementation. Ainsi, si notre classe ObjetGraphique peut etre ecrite sous-forme dinterface, on pourra nalement exprimer en Java que la classe RectangleGraphique est une extension de la classe RectangleGeometrique et une impl ementation de linterface ObjetGraphique ; cela nous apportera une grande partie des avantages quon aurait pu esp erer de lh eritage multiple, sil avait et e possible.

7.2
7.2.1

Sous-classes et super-classes
D enition de sous-classe

Lh eritage est le m ecanisme qui consiste ` a d enir une classe nouvelle, dite classe d eriv ee ou sous-classe, par extension dune classe existante, appel ee sa classe de base ou super-classe. La sous-classe poss` ede doce tous les membres de la super-classe, auxquels elle ajoute ses membres sp eciques. Lh eritage est indiqu e par lexpression extends SuperClasse ecrite au d ebut de la d enition dune classe. Par exemple, d enissons la classe Pixel comme sous-classe de la classe Point qui nous a d ej` a servi dexemple. Un pixel est un point, etendu par lajout dune variable dinstance qui repr esente une couleur (Color est une classe d enie dans le paquet java.awt) : class Point { int x, y; ... } class Pixel extends Point { Color couleur; ... } Avec la d enition pr ec edente, un Pixel se compose de trois variables dinstance : x et y, h erit ees de la classe Point, et couleur, une variable dinstance sp ecique. Ces trois variables sont membres de plein droit de la classe Pixel et, si pix est un objet de cette classe, on peut ecrire sous r eserve quon ait le droit dacc` es pix.x et pix.y exactement comme on peut ecrire pix.couleur. Note. En toute rigueur, si la d enition dune classe D commence par class D extends B ... on devrait dire que D est une sous-classe directe de B ou que B est une super-classe directe de D. Par ailleurs, on dit que D est une sous-classe de B si D est sous-classe directe de B ou dune sous-classe de B . Dans ce cas, on dit aussi que B est super-classe de D. Une super-classe [resp. une sous-classe] qui nest pas directe est dite indirecte. Cela etant, nous dirons sous-classe [resp. super-classe] pour sous-classe directe [resp. super-classe directe], sauf dans les (rares) situations o` u cela cr eerait une confusion. 42
c H. Garreta, 2000-2013

HERITAGE

7.3

Red enition des m ethodes

7.2.2

Larbre de toutes les classes

En Java lh eritage est simple : chaque classe poss` ede au plus une super-classe directe. En fait, il y a une classe particuli` ere, nomm ee Object, qui na pas de super-classe, et toutes les autres classes ont exactement une super-classe directe. Par cons equent, lensemble de toutes les classes, muni de la relation est sous-classe directe de , constitue une unique arborescence dont la racine est la classe Object. Ainsi, les variables et m ethodes qui composent un objet ne sont pas toutes d enies dans la classe de celui-ci : il y en a une partie dans cette classe, une partie dans sa super-classe, une autre partie dans la super-classe de la super-classe, etc. Cela introduit la question de la recherche des m ethodes : un message ayant et e envoy e` a un objet, la r eponse pertinente doit etre recherch ee dans la classe de celui-ci ou, en cas d echec, dans la super-classe de celle-l` a, puis dans la super-classe de la super-classe, et ainsi de suite, en remontant le long de la branche de larbre dh eritage, jusqu` a trouver une classe dans laquelle on a pr evu de r epondre au message en question. Le proc ed e de recherche des m ethodes est un probl` eme important, dans tous les langages qui pratiquent lh eritage 45 . Il peut etre trait e` a la compilation, on parle alors de liaison statique, ou bien ` a lex ecution, on dit quon pratique alors la liaison dynamique. La liaison statique est plus ecace, puisque les incertitudes sont lev ees avant que lex ecution ne commence, mais la liaison dynamique est beaucoup plus souple et puissante. Comme la suite le montrera, Java met en uvre un savant m elange de liaison statique et dynamique.

7.3
7.3.1

Red enition des m ethodes


Surcharge et masquage

Que se passe-t-il lorsque des membres sp eciques de la sous-classe ont le m eme nom que des membres h erit es ? Deux cas : 1. Si les entit es qui ont le m eme nom ont des r oles ou des signatures di erentes, alors cest un cas de surcharge et il est trait e comme sil sagissait de deux membres de la m eme classe. Par exemple, rien ne soppose ` a ce que cohabitent sans conit dans la sous-classe une variable dinstance propre f et une m ethode h erit ee f, ou deux m ethodes de signatures di erentes dont une est h erit ee et lautre non. 2. Sil sagit au contraire de deux entit es ayant le m eme r ole et, dans le cas des m ethodes, la m eme signature alors il y a masquage : dans la sous-classe, le membre sp ecique masque le membre h erit e. Il y a plusieurs mani` eres dacc eder ` a un membre masqu e. Imaginons par exemple quon a introduit une mesure de qualit e dans les points, et aussi une notion de qualit e dans les pixels, ces deux notions nayant pas de rapport entre elles 46 : class Point { int x, y; int qualite; ... } class Pixel extends Point { Color couleur; int qualite; ... } Dans ces conditions, ` a lint erieur dune m ethode de la classe Pixel, les expressions qualite et this.qualite d esignent le membre qualite sp ecique de la classe Pixel. Mais les expressions super.qualite et ((Point) this).qualite d esignent toutes deux le membre qualite h erit e de la classe Point.
45. Notez que ce probl` eme est partiellement simpli e et optimis e en Java par le fait quon ny pratique que lh eritage simple. Dans les langages ` a h eritage multiple, o` u une classe peut avoir plusieurs super-classes directes, le graphe dh eritage nest plus un arbre. Dans ces langages, la recherche des m ethodes devient une op eration litigieuse et complexe. 46. Si la qualit e dun pixel (en tant que pixel) na pas de rapport avec la qualit e dun point, cest une maladresse que de donner le m eme nom ` a ces variables dinstance ; il vaudrait certainement mieux que le membre Pixel.qualite ait un autre nom.

c H. Garreta, 2000-2013

43

7.3

Red enition des m ethodes

HERITAGE

7.3.2

Red enition des m ethodes

Si la d enition dans une sous-classe dune variable ayant le m eme nom quune variable de la super-classe appara t souvent comme une maladresse de conception, la d enition dune m ethode ayant le m eme nom et la m eme signature quune m ethode de la super-classe est au contraire une technique justi ee et tr` es utile. En eet, la sous-classe etant une extension, cest-` a-dire une am elioration , de la super-classe, les objets de la sous-classe doivent r epondre ` a tous les messages auxquels r epondent les objets de la super-classe, mais il est normal quil y r epondent de mani` ere am elior ee : beaucoup de m ethodes de la sous-classe font les m emes choses que des m ethodes correspondantes de la super-classe, mais elles le font mieux , cest-` a-dire en prenant en compte ce que les objets de la sous-classe ont de plus que ceux de la super-classe. Exemple, courant mais fondamental : la m ethode toString 47 : class Point { int x, y; ... public String toString() { return "(" + x + "," + y + ")"; } } class Pixel extends Point { Color couleur; ... public String toString() { return "[(" + x + "," + y + ");" + couleur + "]"; } } Il est facile de comprendre pourquoi la r eponse ` a un appel comme unPixel.toString() peut etre vue comme une am elioration de la r eponse ` a unPoint.toString() : si unPoint repr esente un point et unPixel un pixel, les expressions System.out.println(unPoint); System.out.println(unPixel); achent, par exemple (10,20) [(30,40);java.awt.Color.red] Note. Ecrite comme elle lest, la m ethode Pixel.toString pr ec edente a deux d efauts : le m eme code (le traitement de x et y ) est ecrit dans Point.toString et dans Pixel.toString, ce qui constitue une redondance, toujours regrettable, plus grave, la classe Pixel sappuie ainsi sur des d etails internes de la classe Point. Une mani` ere bien pr ef erable d ecrire les m ethodes red enies de la sous-classe consiste ` a laisser les m ethodes de la super-classe se charger du traitement de la partie h erit ee : class Pixel extends Point { Color couleur; ... public String toString() { return "[" + super.toString() + ";" + couleur + "]"; } } Contraintes de la red enition des m ethodes 1. On ne peut pas proter de la red enition dune m ethode pour en restreindre laccessibilit e : la red enition dune m ethode doit etre au moins aussi publique que la d enition originale. En particulier, la red enition dune m ethode publique 48 doit etre quali ee public. 2. La signature de la red enition dune m ethode doit etre identique ` a celle de la m ethode h erit ee. La signature dune m ethode se compose de trois el ements :
47. La m ethode toString appartient a ` tous les objets, puisquelle est d enie dans la classe Object. 48. On notera que cela concerne en particulier la red enition obligatoire, dans ce cas des m ethodes des interfaces (cf. section 7.7.3) qui, par d enition, sont toutes implicitement publiques.

44

c H. Garreta, 2000-2013

HERITAGE

7.4

H eritage et constructeurs

le nom de la m ethode, la suite des types de ses arguments, le fait que la m ethode soit ordinaire (dinstance) ou static. Par exemple, si la d enition dune m ethode commence par la ligne public double moyenne(double[] tableau, int nombre, String titre) { alors sa signature est le triplet : < moyenne, (double[], int, java.lang.String), non statique > 3. Il faut faire tr` es attention ` a la contrainte evoqu ee au point pr ec edent, car les di erences de signature ne sont pas en tant que telles signal ees par le compilateur. En eet, imaginons que la m ethode ci-dessus soit d enie dans une classe A, et que dans une sous-classe B de A on ecrive une m ethode (que lon pense etre une red enition de la pr ec edente) commen cant par public double moyenne(double[] tableau, short nombre, String titre) { Les signatures de ces deux m ethodes n etant pas identiques, la deuxi` eme nest pas une red enition de la premi` ere. H elas pour le programmeur, cela ne constitue pas une erreur que le compilateur pourrait diagnostiquer, mais un simple cas de surcharge : la classe B poss` ede deux m ethodes nomm ees moyenne : la premi` ere prend un int pour second argument tandis que la deuxi` eme prend un short 49 . 4. On notera bien que le type du r esultat renvoy e par une m ethode ne fait pas partie de la signature de celle-ci. Dans ces conditions : une d enition de m ethode est une red enition si et seulement si la signature est identique ` a celle dune m ethode h erit ee, ind ependamment du type du r esultat, si une d enition est une red enition, alors le type du r esultat de la red enition doit etre identique au type du r esultat de la m ethode h erit ee. Note Java 5. La pratique montre que la contrainte exprim ee ci-dessus est trop forte. Dans la mesure o` u on peut voir la red enition dune m ethode comme un ranement de celle-ci, on souhaiterait parfois que la m ethode ran ee puisse rendre un r esultat qui est lui-m eme un ranement du r esultat renvoy e par la m ethode originale. Cest pourquoi en Java 5 la r` egle pr ec edente est devenue : une d enition de m ethode est une red enition si et seulement si la signature est identique ` a celle dune m ethode h erit ee, ind ependamment du type du r esultat, si une d enition est une red enition, alors le type du r esultat de la red enition doit etre soit identique, soit une sous-classe du type du r esultat de la m ethode h erit ee.

7.4

H eritage et constructeurs

Linitialisation dun objet dune sous-classe implique son initialisation en tant quobjet de la super-classe. Autrement dit, tout constructeur de la sous-classe commence n ecessairement par lappel dun constructeur de la super-classe. Si le programmeur na rien pr evu, ce sera le constructeur sans arguments de la super-classe, qui doit donc exister. Mais on peut expliciter lappel dun constructeur de la super-classe par linstruction : super(arguments ); Si elle est pr esente, cette instruction doit etre la premi` ere du constructeur de la sous-classe. Par exemple, si la classe Point na quun constructeur, ` a deux arguments : class Point { int x, y; Point(int x, validation this.x = this.y = } ... }

int y) { de x et y x; y;

alors le programmeur est oblig e d ecrire un constructeur pour la classe Pixel, comme ceci :
49. La di erence entre un int et un short etant minime (la valeur 10 est-elle de type int ou de type short ?), on montre l` a une situation qui, si elle etait voulue, serait certainement une maladresse source de confusion et derreurs ult erieures.

c H. Garreta, 2000-2013

45

7.5

Membres prot eg es

HERITAGE

class Pixel extends Point { Color couleur; Pixel(int x, int y, Color couleur) { super(x, y); this.couleur = couleur; } ... }

7.5

Membres prot eg es

Comme il a et e dit (cf. 6.4) un membre dune classe C dont la d eclaration commence par le qualieur protected est accessible depuis les m ethodes de la classe C, celles des autres classes du paquet auquel C appartient, ainsi que celles des sous-classes, directes ou indirectes, de C. En r ealit e la r` egle qui gouverne lacc` es aux membres prot eg es est plus complexe que cela. Consid erons un acc` es tel que : unObjet .unMembre ou unObjet .unMembre (arguments ) dans lequel unMembre (une variable dans le premier cas, une m ethode dans le second) est un membre prot eg e dune certaine classe C. Pour etre l egitime, cette expression doit etre ecrite dans une m ethode de C ou dune classe du m eme paquet que C en cela les membres prot eg es sont trait es comme les membres ayant laccessibilit e par d efaut , ou bien doit etre ecrite dans une m ethode dune classe S qui est sous-classe de C, mais alors unObjet doit etre instance de S ou dune sous-classe de S (en pratique, unObjet sera souvent this). Il est dicile de produire des applications simples et probantes illustrant lemploi de tels membres 50 . Pour comprendre lint er et dune m ethode prot eg ee il faut imaginer un traitement qui doit etre d eni dans une classe A alors quil ne peut etre appel e que depuis les instances dune sous-classe de A. Cest le cas, par exemple, du constructeur dune classe qui ne doit pas avoir dinstances 51 , mais uniquement des sous-classes qui, elles, auront des instances. Voici une version tr` es na ve de quelques classes pour g erer le stock dune entreprise de location de choses. Il existe une classe Article, la plus g en erale, dont toutes les sortes de choses en location sont sous-classes :

package generalites; public class Article { private long reference; private double prixParJour; protected Article(long reference, double prixParJour) { this.reference = reference; this.prixParJour = prixParJour; } }

Il existe egalement un certain nombre de sous-classes de la pr ec edente, repr esentant des cat egories pr ecises dobjets ` a louer, comme les v ehicules :

50. Certains th eoriciens de la programmation orient ee objets estiment m eme que le concept de membre prot eg e est injusti e et contreproductif. 51. Plus loin, de telles classes seront appel ees classes abstraites, voir 7.7.2.

46

c H. Garreta, 2000-2013

HERITAGE

7.6

Le polymorphisme

package applications; public class Vehicule extends generalites.Article { private String immatriculation; private String carburant; public Vehicule(long reference, double prixParJour, String immatriculation, String carburant) { super(reference, prixParJour); this.immatriculation = immatriculation; this.carburant = carburant; } } Tous les objets lou es sont manipul es dans le programme ` a travers des variables d eclar ees de type Article : Article unArticle; Il ne faut pas que la valeur dune telle variable puisse etre une instance directe de la classe Article, car un objet qui serait un Article sans etre quelque chose de plus pr ecis (un v ehicule, un outil, un meuble, etc.) na pas de sens. Le constructeur de la classe Article doit donc etre rendu moins accessible que public an de garantir que cette classe ne sera jamais directement instanci ee : unArticle = new Article(111222333, 120.0); // *** ERREUR ***

Or, en m eme temps, ce constructeur de Article doit etre rendu plus accessible que private an quil puisse etre appel e (` a travers lexpression super(reference, prixParJour); ) depuis le constructeur dune sous-classe telle que Vehicule : unArticle = new Vehicule(111222333, 120.0, "1234 ABC 13", "G-O"); // OK Note 1. Si les classes de notre exemple avaient et e dans le m eme paquetage, la qualication protected naurait rien ajout e` a la qualication par d efaut. Comme on le voit, lint er et de la qualication protected est assez limit e, surtout en Java. Note 2. Lexemple ci-dessus tire son int er et de la pr esence dune classe qui ne doit pas avoir dinstances. De telles classes sont dites abstraites ; nous rencontrerons plus loin (cf. 7.7.2) de bien meilleures mani` eres de les prendre en consid eration.

7.6

Le polymorphisme

Le polymorphisme est un concept particuli` erement riche pr esent dans beaucoup de langages orient es objets. Laspect que nous en etudions ici tourne autour des notions de g en eralisation et particularisation. La g en eralisation est la possibilit e de tenir un objet pour plus g en eral quil nest, le temps dun traitement. Par exemple, pour appliquer une transformation g eom etrique ` a un Pixel il sut de savoir quil est une sorte de Point. Par particularisation nous entendons la possibilit e de retrouver le type particulier dun objet alors que ce dernier est acc ed e` a travers une variable dun type plus g en eral. Par exemple, retrouver le fait que la valeur dune variable de type Point est en r ealit e un Pixel. 7.6.1 G en eralisation et particularisation

ne ralisation (conversion sous-classe super-classe). Si B est une super-classe dune classe D, la Ge conversion dun objet D vers le type B est une op eration naturelle et justi ee. En eet, ` a cause de lh eritage, toutes les variables et m ethodes de la classe B sont dans la classe D ; autrement dit, tout ce quun B sait faire, un D sait le faire aussi bien (et peut- etre mieux, ` a cause de la red enition possible des m ethodes h erit ees). Par cons equent, en toute circonstance, l` a o` u un B est attendu on peut mettre un D. De telles conversions sont implicites et toujours accept ee par le compilateur. Nous les rencontrerons dans de tr` es nombreuses situations. Par exemple, avec nos classes Point et Pixel : class Point { int x, y; ... int distance(Point p) { return Math.abs(x - p.x) + Math.abs(y - p.y); }
c H. Garreta, 2000-2013

47

7.6

Le polymorphisme

HERITAGE

... } class Pixel extends Point { Color couleur; ... } si les variables unPoint et unPixel ont les types que leurs noms sugg` erent, lexpression r = unPoint.distance(unPixel); illustre la g en eralisation : lors de lappel de la m ethode distance, la valeur de la variable unPixel est aect ee a largument p (de type Point) ; ainsi, durant le calcul de sa distance au point donn ` e, le pixel est vu comme un Point, ce qui est susant car, dans le calcul dune distance, seuls interviennent les membres que le pixel h erite de la classe Point. Notez que cest le m eme genre de consid erations qui donnent un sens ` a lexpression : r = unPixel.distance(unPoint); Particularisation (conversion super-classe sous-classe). Une cons equence du fait que les objets sont d esign es par r ef erence (cf. section 3.3) est quils ne sont pas alt er e par leur g en eralisation : lorsquun objet dune classe D est acc ed e` a travers une variable dun type plus g en eral B on ne peut pas atteindre les membres de la classe D qui ne sont pas dans B , mais ces membres ne cessent pas pour autant dexister dans lobjet en question. Cela donne un sens ` a lop eration r eciproque de la g en eralisation : donner ` a un objet O un type T plus particulier que celui ` a travers lequel il est connu ` a un instant donn e. Bien entendu, cela nest l egitime que si T est soit le type eectif de O, soit une g en eralisation de ce type. Une telle conversion doit toujours etre explicit ee par le programmeur, elle nest jamais implicite : Point unPoint; Pixel unPixel = new Pixel(a, b, c); ... unPoint = unPixel; // OK. G en eralisation ... unPixel = unPoint; ... unPixel = (Pixel) unPoint; // ERREUR // OK. Particularisation

Les contraintes que doit v erier une expression de la forme (T ) E , o` u T est une classe et E une expression dun type classe, ne sont pas les m emes ` a la compilation et ` a lex ecution du programme : ` a la compilation, il faut que T soit sous-classe ou super-classe, directe ou indirecte, du type eectif de E (cest-` a-dire que les conversions ne sont accept ees ` a la compilation quentre deux classes qui se trouvent sur la m eme branche de larbre dh eritage), ` a lex ecution, il faut que la conversion repr esente une g en eralisation du type eectif de E , sinon, une exception ClassCastException sera lanc ee. Ces contraintes sont faciles ` a comprendre : il sut de se rappeler que la g en eralisation et la particularisation sont des transformations sans travail (des jeux de pointeurs ), qui ne peuvent en aucun cas ajouter a un objet des membres quil na pas. ` Exemple. Une situation dans laquelle la g en eralisation et la particularisation apparaissent tr` es naturellement est lemploi doutils g en eraux de la biblioth` eque Java, comme les collections. Par exemple, une mani` ere de repr esenter une ligne polygonale consiste a ` se donner une liste (ici, une liste cha n ee, LinkedList) de points (ici, tir es au hasard) : ... Point unPoint; List lignePolygonale = new LinkedList(); for (int i = 0; i < nbr; i++) { unPoint = new Point((int)(XMAX * Math.random()), (int)(YMAX * Math.random())); lignePolygonale.add(unPoint); } ... 48
c H. Garreta, 2000-2013

HERITAGE

7.6

Le polymorphisme

Consid erons lexpression lignePolygonale.add(unPoint) . Les LinkedList etant d enies ` a un niveau de g en eralit e maximal, lobjet unPoint ne peut etre trait e, dans les m ethodes de la liste, que comme un simple Object, la classe la plus g en erale. Du coup, lorsque ces points sont extraits de la liste, il faut explicitement leur redonner le type qui est le leur. Par exemple, cherchons ` a acher les sommets dune telle ligne polygonale : ... Iterator iter = lignePolygonale.iterator(); while (iter.hasNext()) { unPoint = (Point) iter.next(); application ` a unPoint dun traitement n ecessitant un Point } ... La conversion (Point) iter.next() est n ecessaire, car le r esultat rendu par next est un Object. Elle est certainement correcte, car dans la collection que iter parcourt nous navons mis que des objets Point. Lorsquune liste nest pas homog` ene comme ci-dessus, il faut saider de lop erateur instanceof pour retrouver le type eectif des objets. Par exemple, supposons que figure soit une collection contenant des points et des objets dautres types, voici comment en traiter uniquement les points : ... Iterator iter = figure.iterator(); while (iter.hasNext()) { Object unObjet = iter.next(); if (unObjet instanceof Point) { Point unPoint = (Point) unObjet; traitement de unPoint } } ... N.B. Le programme pr ec edent traitera les points, mais aussi les pixels et les objets de toutes les sousclasses, directes et indirectes, de la classe Point. Telle est la s emantique de lop erateur instanceof (cest le comportement g en eralement souhait e). 7.6.2 Les m ethodes red enies sont virtuelles

Soit v une variable dun type classe B et m une m ethode de B ; un appel tel que v.m(arguments ) est l egitime. Imaginons quau moment dun tel appel, la valeur eective de v est instance de D, une sous-classe de B , dans laquelle m a et e red enie. La question est : quelle version de m sera appel ee ? Celle de B , la classe de la variable v, ou bien celle de D, la classe de la valeur eective de v ? En Java, la r eponse est : la seconde. Quel que soit le type sous lequel un objet est vu ` a la compilation, lorsqu` a lex ecution la machine appelle sur cet objet une m ethode qui a et e red enie, la d enition eectivement employ ee est la plus particuli` ere, cest ` a dire la plus proche du type eectif de lobjet. Exemple, trivial mais r ev elateur, avec la m ethode toStringtoString : Object unObjet = new Point(1, 2); ... String str = unObjet.toString(); La cha ne aect ee ` a str par lexpression ci-dessus est "(1,2)", cest-` a-dire lexpression textuelle dun objet Point (et non "Point@12cf71", qui serait le r esultat de la version de toString d enie dans Object). Noter que cest bien parce que toString est d enie dans la classe Object que lexpression unObjet.toString() est accept ee ` a la compilation, mais ` a lex ecution cest la version d enie dans la classe Point, la classe de la valeur eective de unObjet, qui est employ ee. Dans certains langages, comme C++, on appelle cela des m ethodes virtuelles ; en Java, toutes les m ethodes sont donc virtuelles. Cela a dimportantes cons equences m ethodologiques, et rend le polymorphisme extr emement int eressant et puissant. Autre exemple (plus instructif). Consid erons une application manipulant des classes dobjets devant etre dessin es dans des fen etres graphiques : des segments, des rectangles, des cercles, etc. Dans toutes ces classes il y a une m ethode seDessiner prenant en charge la pr esentation graphique des objets en question.
c H. Garreta, 2000-2013

49

7.6

Le polymorphisme

HERITAGE

La question est : comment manipuler ensemble ces objets di erents, tout en ayant le droit dutiliser ce quils ont en commun ? Par exemple, comment avoir une collection de tels objets graphiques di erents, et pouvoir appeler la m ethode seDessiner de chacun ? On laura compris, la solution consiste ` a d enir une super-classe de toutes ces classes, dans laquelle la m ethode seDessiner est introduite : class ObjetGraphique { ... void seDessiner(Graphics g) { } ... } class Segment extends ObjetGraphique { int x0, y0, x1, y1; // extr emit es void seDessiner(Graphics g) { g.drawLine(x0, y0, x1, y1); } ... } class Triangle extends ObjetGraphique { int x0, y0, x1, y1, x2, y2; // sommets void seDessiner(Graphics g) { g.drawLine(x0, y0, x1, y1); g.drawLine(x1, y1, x2, y2); g.drawLine(x2, y2, x0, y0); } ... } class Cercle extends ObjetGraphique { int x, y; // centre int r; // rayon void seDessiner(Graphics g) { g.drawOval(x - r, y - r, x + r, y + r); } ... } Exemple dutilisation de ces classes : une figure est un tableau dobjets graphiques : ObjetGraphique[] figure = new ObjetGraphique[nombre ]; ... figure[i ] = new Segment(arguments ); ... figure[j ] = new Triangle(arguments ); ... figure[k ] = new Cercle(arguments ); ... Les divers objets graphiques subissent une g en eralisation lors de leur introduction dans le tableau figure. Puisque seDessiner est d enie dans la classe ObjetGraphique, on peut appeler cette m ethode ` a travers les el ements de figure. Lint er et de tout cela r eside dans le fait que cest la m ethode propre ` a chaque objet graphique particulier qui sera appel ee, non celle de la classe ObjetGraphique : for (int i = 0; i < figure.length; i++) figure[i].seDessiner(g); // ceci d epend de la valeur effective de figure[i] Les m ethodes red enies sont n ecessairement virtuelles La virtualit e des m ethodes peut donc se r esumer ainsi : la m ethode eectivement appel ee par une expression comme unObjet .uneMethode () d epend de la valeur eective de unObjet au moment de cet appel, non de la d eclaration de unObjet ou de propri et es statiques d ecoulant du texte du programme. Bien que la plupart du temps cette propri et e soit extr emement utile, on voudrait quelquefois pouvoir choisir la m ethode a appeler parmi les diverses red enitions faites dans les super-classes. Il faut comprendre que cela ne se peut pas : le m ecanisme des m ethodes virtuelles en Java nest pas d ebrayable. 50
c H. Garreta, 2000-2013

HERITAGE

7.6

Le polymorphisme

Seule exception : si uneMethode est red enie dans une classe, lexpression super.uneMethode () permet dappeler, depuis une m ethode de la m eme classe, la version de uneMethode qui est en vigueur dans la superclasse. Mais il ny a aucun autre moyen pour contourner une ou plusieurs red enitions dune m ethode. On notera que les variables ne sont pas trait ees comme les m ethodes (mais la red enition des variables na pas dint er et, ce nest quun masquage g en eralement maladroit). Lexemple suivant illustre la situation : class A { String v = "variable A"; String m() { return "m ethode A"; } } class B extends A { String v = "variable B"; String m() { return "m ethode B"; } } class C extends B { String v = "variable C"; String m() { return "m ethode C"; } void test() { System.out.println( v ); System.out.println( super.v ); System.out.println( ((A) this).v ); System.out.println( m() ); System.out.println( super.m() ); System.out.println( ((A) this).m() ); } public static void main(String[] args) { new C().test(); } } Achage obtenu : variable C variable B variable A m ethode C m ethode B m ethode C

pour une variable, cela marche

pour une m ethode non

7.6.3

M ethodes et classes nales

Les m ethodes virtuelles sont extr emement utiles, mais elles ont un co ut : de linformation cach ee doit etre ajout ee aux instances de la classe ObjetGraphique pour permettre ` a la machine Java de rechercher la m ethode qui doit etre eectivement appel ee ` a loccasion dune expression comme unObjetGraphique.seDessiner(g); cette recherche prenant dailleurs du temps ` a lex ecution. Cest la raison pour laquelle le programmeur peut optimiser son programme en d eclarant quune m ethode ne sera pas red enie dans les eventuelles sous-classes, ce qui permet au compilateur de lier statiquement les appels de cette m ethode, au lieu de les lier dynamiquement comme le veut la r` egle g en erale. Cela se fait par lemploi du qualieur final. Par exemple, sil y a lieu de penser que le dessin dun cercle sera le m eme dans la classe Cercle et dans les sous-classes de celle-ci, on peut d eclarer cette m ethode comme ceci : class Cercle extends ObjetGraphique { int x, y; // centre int r; // rayon
c H. Garreta, 2000-2013

51

7.7

Abstraction

HERITAGE

final void seDessiner(Graphics g) { g.drawOval(x - r, y - r, x + r, y + r); } ... }

// cette m ethode ne sera // pas red efinie dans les // sous-classes de Cercle

Classes finales. Si une classe ne doit pas avoir de sous-classes, on peut eectuer dun seul coup le travail doptimisation pr ec edent sur toutes ses m ethodes en d eclarant final la classe tout enti` ere. Par exemple, si la classe Triangle nest pas destin ee ` a avoir des sous-classes, on peut l ecrire : final class Triangle extends ObjetGraphique { int x0, y0, x1, y1, x2, y2; // sommets void seDessiner(Graphics g) { g.drawLine(x0, y0, x1, y1); g.drawLine(x1, y1, x2, y2); g.drawLine(x2, y2, x0, y0); } ... }

7.7
7.7.1

Abstraction
M ethodes abstraites

Revenons sur lexemple de la section pr ec edente : class ObjetGraphique { ... void seDessiner(Graphics g) { } ... } Nous observons ceci : la m ethode seDessiner doit etre d enie dans la classe ObjetGraphique, car le r ole de cette classe est de rassembler les el ements communs aux divers objets graphiques consid er es, or la capacit e de se repr esenter graphiquement est bien un de ces el ements, sans doute le principal. En m eme temps il nous est impossible, au niveau de la classe ObjetGraphique, d ecrire quoi que ce soit dans la m ethode seDessiner, car nous nen savons pas assez sur ce quil sagit de dessiner. On exprime cette situation en disant que seDessiner est une m ethode abstraite . Sa d eclaration dans la classe ObjetGraphique est une promesse : on annonce que tout objet graphique devra avoir une m ethode seDessiner, quil nest pas possible de fournir pour le moment. En Java on peut d eclarer quune m ethode est abstraite ` a laide du qualieur abstract. Le corps de la m ethode doit alors etre remplac e par un point virgule (et, comme on le verra ` a la section suivante, la classe contenant une telle m ethode doit elle aussi etre d eclar ee abstraite) : abstract class ObjetGraphique { ... abstract void seDessiner(Graphics g); ... } Les m ethodes abstraites dune classe restent abstraites dans ses sous-classes, sauf si elles y ont une red enition qui leur donne un corps. La magie des fonctions virtuelles, lexemple canonique. Ce nest pas parce quune m ethode est abstraite quon ne peut pas lappeler, y compris dans des classes o` u elle nest pas encore d enie. Par exemple, une mani` ere (na ve) deacer un objet graphique consiste ` a le dessiner avec une plume qui a pour couleur la couleur du fond : abstract class ObjetGraphique { ... abstract void seDessiner(Graphics g); ... 52
c H. Garreta, 2000-2013

HERITAGE

7.7

Abstraction

void sEffacer(Graphics g) { g.setColor(getBackground()); seDessiner(g); } ...

// on prend la couleur du fond

} Une instance de la classe ObjetGraphique (mais nous verrons quil ne peut pas en exister) ne serait pas plus capable de seacer quelle ne le serait de se dessiner, mais toute sous-classe qui d enit une version eective de seDessiner dispose aussit ot dune version op erationnelle de sEffacer. 7.7.2 Classes abstraites

Une classe abstraite est une classe qui ne doit pas avoir dinstances ; elle nest destin ee qu` a avoir des sous-classes qui, elles, auront des instances. Cela peut provenir dune impossibilit e technique ; par exemple, une classe qui poss` ede des m ethodes abstraites (en propre ou h erit ees) ne peut pas avoir des instances, car ce seraient des objets dont une partie du comportement requis naurait pas et e ecrit, dune impossibilit e conceptuelle, cest-` a-dire un choix du concepteur. Par exemple, les classes XxxAdapter du paquet java.awt.event sont des classes enti` erement faites de m ethodes vides, dont d eventuelles instances nauraient aucun int er et. On indique quune classe est abstraite par le qualieur abstract : abstract class ObjetGraphique { ... abstract void seDessiner(Graphics g); ... } Il est obligatoire demployer le qualieur abstract devant toute classe qui poss` ede des m ethodes abstraites, propres ou h erit ees. 7.7.3 Interfaces

Parlant na vement, on peut dire que les m ethodes non abstraites dune classe sont des services que celle-ci rend aux concepteurs de ses eventuelles sous-classes, tandis que les m ethodes abstraites sont des corv ees que la classe transmet aux concepteurs des sous-classes, qui devront en donner des d enitions. Une interface est une classe enti` erement faite de membres publics qui sont des m ethodes abstraites, variables statiques nales (cest-` a-dire des constantes de classe). Une interface se d eclare avec le mot-cl e interface au lieu de class. Il ny a alors pas besoin d ecrire les qualieurs public et abstract devant les m ethodes, ni public, static et final devant les variables. Par exemple, si elle est enti` erement faite de m ethodes abstraites, notre classe ObjetGraphique peut etre d eclar e comme une interface : interface ObjetGraphique { void seDessiner(Graphics g); ... } Autre exemple, extrait de la biblioth` eque Java (plus pr ecis ement du paquet java.util) : interface Collection { boolean isEmpty(); int size(); boolean contains(Object o); boolean add(Object o); Iterator iterator(); ... } Une interface est une sp ecication : elle xe la liste des m ethodes quon est certain de trouver dans toute classe qui d eclare etre conforme ` a cette sp ecication. Cela sappelle une impl ementation de linterface, et sindique avec le qualieur implements :
c H. Garreta, 2000-2013

53

7.7

Abstraction

HERITAGE

class Tas implements Collection { public boolean isEmpty() { impl ementation de la m ethode isEmpty } public int size() { impl ementation de la m ethode size } ... } Notez que les m ethodes des interfaces sont toujours publiques (implicitement) ; par cons equent, leurs d enitions dans des sous-classes doivent etre explicitement quali ees public, sinon une erreur sera signal ee. Deux interfaces peuvent h eriter lune de lautre. Par exemple, toujours dans le paquet java.util on trouve linterface SortedSet (ensemble tri e) qui est une sous-interface de Set, elle-m eme une sous-interface de Collection, etc. Dautre part, la relation implements entre une classe et une interface est aussi une sorte dh eritage. Cet h eritage est multiple : une classe peut impl ementer plusieurs interfaces distincts. Par exemple, on pourrait d enir une classe Figure qui serait une sorte de Collection (dobjets graphiques) et en m eme temps une sorte d0bjetGraphique (puisque capable de se dessiner) : class Figure implements Collection, ObjetGraphique { ... public void seDessiner(Graphics g) { appeler seDessiner sur chaque membre de la gure } public boolean add(Object o) { ajouter o (un objet graphique) ` a la gure } public boolean isEmpty() { la gure est-elle vide ? } ... } Lint er et de cette sorte dh eritage multiple appara t clairement : une instance de notre classe Figure pourra etre mise ` a tout endroit o` u une Collection est attendue, et aussi ` a tout endroit o` u un ObjetGraphique est attendu.

Interface pour transmettre une fonction Java ne comportant pas la notion de pointeur, encore moins de pointeur sur une fonction, comment fait-on dans ce langage pour quune m ethode soit argument dune autre ? La solution consiste ` a d eclarer la m ethode comme membre dune interface d enie ` a cet eet, et ` a mettre linterface comme type de largument en question. Voici par exemple comment d enir, dans une classe CalculNumerique, une m ethode zero qui recherche par dichotomie une solution approch ee ` a -pr` es de l equation f (x) = 0, x [ a, b ] : class MonCalculNumerique { ... static double zero(double a, double b, double epsilon, Fonction f) { double c; if (f.val(a) > f.val(b)) { c = a; a = b; b = c; } 54
c H. Garreta, 2000-2013

HERITAGE

7.7

Abstraction

while (Math.abs(b - a) > epsilon) { c = (a + b) / 2; if (f.val(c) < 0) a = c; else b = c; } return (a + b) / 2; } ... } Fonction est une interface d enie pour cette occasion. Elle se r eduit ` a une m ethode val, qui repr esente la fonction en question : interface Fonction { double val(double x); } Notez ` a quel point Fonction et zero illustrent la notion dinterface et son utilit e : etre un objet Fonction ce nest rien dautre que poss eder une m ethode nomm ee val qui prend un double et rend un double . Il ny a pas besoin den savoir plus pour ecrire la m ethode zero ! ee ` a 108 A titre dexemple proposons-nous dutiliser cette m ethode pour calculer la valeur de 2 approch 2 pr` es. Il sagit de r esoudre l equation x 2 = 0 sur, par exemple, lintervalle [ 0, 2 ]. La fonction ` a consid erer est donc f (x) = x2 2. Premi` ere m ethode, lourde, d enir une classe expr` es : class X2moins2 implements Fonction { public double val(double x) { return x * x - 2; } } class Essai { public static void main(String[] args) { Fonction f = new X2moins2(); double z = CalculNumerique.zero(0, 2, 1e-8, f); System.out.println(z); } }

Remarquant que la classe X2moins2 na quune instance, on peut all eger notre programme en utilisant ` a sa place une classe anonyme : class Essai { public static void main(String[] args) { Fonction f = new Fonction() { public double val(double x) { return x * x - 2; } }; double z = CalculNumerique.zero(0, 2, 1e-8, f); System.out.println(z); } } On peut m eme faire l economie de f (mais le programme obtenu est-il plus lisible ?) :
c H. Garreta, 2000-2013

55

7.7

Abstraction

HERITAGE

public class Courant { public static void main(String[] args) { double z = CalculNumerique.zero(0, 2, 1e-8, new Fonction() { public double val(double x) { return x * x - 2; } }); System.out.println(z); } }

56

c H. Garreta, 2000-2013

EXCEPTIONS

Exceptions

On dit quune exception se produit lorsque les conditions dex ecution sont telles que la poursuite du programme devient impossible ou incorrecte. Exemple : lindice dun tableau se trouve en dehors des bornes, la m emoire manque lors de la cr eation dun objet, etc. Les exceptions sont g en eralement d etect ees par les fonctions de bas niveau, voire par la machine Java elle-m eme, mais la plupart du temps ce nest que dans les fonctions de haut niveau quon peut programmer la r eaction ad equate ` a de telles situations non pr evues. Le m ecanisme des exceptions de Java est un moyen de communication permettant aux el ements des couches basses des programmes de notier aux couches hautes la survenue dune condition anormale. Par exemple, nous avons d ej` a vu une classe Point dont les instances etaient soumises ` a validation. Une bonne mani` ere de traiter linvalidit e des arguments de la construction dun point consiste ` a lancer une exception : class Point { static final int XMAX = 1024, YMAX = 768; int x, y; Point(int a, int b) throws Exception { if (a < 0 || a >= XMAX || b < 0 || b >= YMAX) throw new Exception("Coordonn ees ill egales"); x = a; y = b; } ... } Les exceptions ont diverses sortes de causes : des causes synchrones 52 , cest-` a-dire provoqu ees par lex ecution dune instruction, comme la division par z ero, limpossibilit e dallouer de la m emoire, limpossibilit e de charger une classe, etc., cas particulier du pr ec edent, lex ecution de linstruction throw, des causes asynchrones ; en Java il ny en a que deux : lex ecution, depuis un autre thread, de la m ethode Thread.stop et la survenue dune erreur interne de la machine Java. Une fois lanc ee, une exception remonte , cest-` a-dire : lex ecution du bloc de code dans lequel lexception a et e lanc ee est abandonn e, si ce bloc nest ni un bloc try ni le corps dune m ethode, alors il est lui-m eme vu comme une instruction ayant lanc e lexception, si ce bloc est le corps dune m ethode, alors lappel de cette derni` ere, dans la m ethode appelante, est vu comme une instruction ayant lanc e lexception, si ce bloc est un bloc try comportant une clause catch compatible avec lexception, alors cette derni` ere est attrap ee : le code associ e` a cette clause catch est ex ecut e, et lexception ne va pas plus loin.

8.1

Interception des exceptions

Syntaxe : try { bloc0 } catch(type exception1 arg1 ) { bloc1 } catch(type exception2 arg2 ) { bloc2 } ... finally { block }
52. Ces causes synchrones montrent quil nest pas correct de se limiter ` a dire quune exception est une situation impr evisible. Une division par z ero ou lutilisation dune r ef erence nulle ne sont quapparemment impr evisibles, si on avait mieux analys e le programme et ses donn ees on aurait pu les pr evoir avec certitude. Mais, comme on le verra, il est tr` es commode de ranger parmi les exceptions ces ev enements, malgr e tout diciles ` a pr evoir et g en eralement aux cons equences graves.

c H. Garreta, 2000-2013

57

8.2

Lancement des exceptions

EXCEPTIONS

Les blocs catch sont en nombre quelconque, le bloc finally est optionnel. Cela fonctionne de la mani` ere suivante : les instructions qui composent bloc0 sont ex ecut ees. Plusieurs cas sont possibles : 1. Si lex ecution de bloc0 ne provoque le lancement daucune exception, les bouts de code composant bloc1 ... block1 sont ignor es. 2. Si une exception E est lanc ee par une des instructions de bloc0 , ce bloc est imm ediatement abandonn e et on recherche le premier i tel que E soit instance, directe ou indirecte, de type exceptioni . Alors, E est aect e` a largument argi et le bloc correspondant, bloci , est ex ecut e (dune certaine mani` ere, cette partie ressemble donc ` a un appel de fonction). 3. Si le type de E ne correspond ` a aucun des type exceptioni alors lexception continue sa trajectoire : lensemble try...catch... est consid er e comme une instruction ayant lanc e E. L eventuel code composant le bloc finally est ex ecut e quelle que soit la mani` ere dont le bloc try a et e quitt e, y compris le cas n 3. Autrement dit, ce bloc finally est le moyen dassurer quun code sera ex ecut e a la suite de bloc0 m ` eme si ce bloc se termine en catastrophe.

8.2

Lancement des exceptions


throw exception ;

Une exception se lance par linstruction

o` u exception est une expression dont la valeur doit etre un objet dune des classes de la hi erarchie expliqu ee a ` la section suivante. 8.2.1 Hi erarchie des exceptions

Toutes les classes dexceptions appartiennent ` a un sous-arbre de larbre des classes dont la racine est la classe Throwable : Object Throwable Error Exception RuntimeException

IOException

Classe de base de toutes les exceptions. Erreurs graves (en particulier, exceptions asynchrones) quil nest pas raisonnable de chercher ` a r ecup erer. Exceptions m eritant d etre d etect ees et trait ees. Exceptions pouvant survenir durant le fonctionnement normal de la machine Java : - indice de tableau hors des bornes - acc` es ` a un membre dune r ef erence null - erreur arithm etique (division par z ero, etc.) Exceptions pouvant survenir pendant les op erations dentr ee/sortie

Vos propres classes exceptions viennent ici Autres classes 8.2.2 D eclaration des exceptions lanc ees par une m ethode

Une m ethode contenant une instruction pouvant lancer une exception dun certain type E doit n ecessairement soit attraper lexception, au moyen dun bloc try...catch... ad equat, soit d eclarer quelle est susceptible de lancer, ou plut ot de laisser echapper, des exceptions du type E . Cette d eclaration se fait par un enonc e de la forme throws listeDExceptions plac e` a la n de len-t ete de la m ethode. Par exemple, le constructeur de la classe Point etant ecrit ainsi Point(int a, int b) throws Exception { if (a < 0 || a >= XMAX || b < 0 || b >= YMAX) throw new Exception("Coordonn ees ill egales"); x = a; 58
c H. Garreta, 2000-2013

EXCEPTIONS

8.2

Lancement des exceptions

y = b; } (notez que l enonc e throws Exception est obligatoire) pour lessayer, nous devrons ecrire une m ethode main soit de la forme : public static void main(String[] args) { ... try { Point p = new Point(u, v); ... } catch (Exception e) { System.out.println("Probl` eme: " + e.getMessage()); } ... } soit de la forme : public static void main(String[] args) throws Exception { ... Point p = new Point(u, v); ... } Note. Dans cet exemple nous nous contentons dun travail assez sommaire, en ne d enissant pas de classe sp ecique pour les exceptions qui int eressent notre programme. En r` egle g en erale on d enit de telles classes, car cela permet une r ecup eration des erreurs plus s elective : class ExceptionCoordonnesIllegales extends Exception { ExceptionCoordonnesIllegales() { super("Coordonn ees ill egales"); } } class Point { Point(int a, int b) throws Exception { if (a < 0 || a >= XMAX || b < 0 || b >= YMAX) throw new ExceptionCoordonnesIllegales(); x = a; y = b; } ... public static void main(String[] args) { ... try { Point p = new Point(u, v); } catch (ExceptionCoordonnesIllegales e) { System.out.println("Probl` eme avec les coordonn ees du point"); } ... } } le es et non contro le es. Les exceptions contr Exceptions contro ol ees sont celles quon est oblig e de d eclarer dans len-t ete de toute m ethode susceptible de les lancer ; les autres exceptions sont dites non contr ol ees. Toutes les exceptions sont contr ol ees, sauf : les instances de Error, car elles expriment des ev enements irrattrapable, les instances de RuntimeException, car sil fallait d eclarer ces exceptions, cela concernerait toutes les m ethodes.
c H. Garreta, 2000-2013

59

8.3

Assert

EXCEPTIONS

8.3

Assert

Le service rendu par linstruction assert 53 est double : assert est un m ecanisme simple et concis permettant de v erier, ` a lex ecution, qu` a certains endroits dun programme des conditions qui doivent etre remplies le sont eectivement, assert comporte un dispositif global et imm ediat dactivation ou d esactivation qui permet, au moment de lex ecution, de choisir entre plusieurs modes, allant dun mode atelier muni de nombreuses v erications (qui consomment du temps) ` a un mode utilisateur nal , plus rapide puisque les occurrences de assert y sont neutralis ees. Linstruction assert se pr esente sous deux formes : assert expression 1 ; et assert expression 1 : expression 2 ; expression 1 est une expression bool eenne, expression 2 une expression dun type quelconque. Dans les deux cas, lex ecution de linstruction assert commence par evaluer expression 1 . Si cette expression est vraie, lex ecution continue sans que rien ne se passe. En revanche, si expression 1 se r ev` ele fausse alors une erreur 54 de type java.lang.AssertionError est lanc ee. Si cest la deuxi` eme forme de assert qui a et e utilis ee, la valeur dexpression 2 gure dans le message associ e` a lerreur. Exemple : void uneMethode(int x) { ... assert MIN < x && x < MAX; ... } Lors dune ex ecution dans laquelle uneMethode est appel ee avec un argument inf erieur ` a MIN ou sup erieur ` a MAX on obtiendra larr et du programme sauf si lerreur est attrap ee avec un message du style : java.lang.AssertionError at Tests.uneMethode(Tests.java:187) at Tests.main(Tests.java:12) Exception in thread "main" Si linstruction assert avait et e ecrite sous la forme : ... assert MIN < x && x < MAX : "MIN < x && x < MAX, x = " + x; ... alors le message aurait et e java.lang.AssertionError: MIN < x && x < MAX, x = -25 at Tests.uneMethode(Tests.java:187) at Tests.main(Tests.java:12) Exception in thread "main" Note. Linstruction assert est un puissant outil pour d ecouvrir des erreurs de conception et on ne saurait trop insister sur lint er et de son utilisation. Mais elle nest pas la bonne mani` ere de sauver des situations que le programmeur ne peut pas emp echer, comme des erreurs dans les donn ees : saborder le programme nest en g en eral pas la bonne r eaction ` a une faute de frappe commise par lutilisateur ! De m eme, assert nest pas la bonne mani` ere denvoyer des messages ` a lutilisateur nal : en principe non-informaticien, celui-ci nest pas cens e comprendre un diagnostic abscons mentionnant des classes dont il ignore lexistence et des num eros de ligne dont il na que faire. Linformation que assert produit ne sadresse qu` a lauteur du programme. En r esum e, assert est tr` es pratique mais il faut le remplacer par une autre construction (comme une instruction if qui produit un dialogue avec lutilisateur sans tuer le programme) lorsque
53. Notez que, contrairement ` a ce qui se pase en C, le m ecanisme assert nest pas r ealis e en Java par une biblioth` eque s epar ee, mais par une vraie instruction, cest-` a-dire une extension de la syntaxe du langage. 54. Rappelons que les erreurs (classe java.lang.Error, sous-classe de java.lang.Throwable) sont une sorte dexceptions non contr ol ees. Elles sont destin ees principalement mais non exclusivement ` a repr esenter des probl` emes s erieux que les applications ne doivent pas chercher ` a rattraper.

60

c H. Garreta, 2000-2013

EXCEPTIONS

8.3

Assert

il sagit de d etecter des erreurs autres que de conception ou de programmation, il sagit de produire des messages adress es ` a lutilisateur nal, il sagit de v erications qui doivent etre faites m eme lorsque le m ecanisme assert nest pas actif (voir ci-dessous). Activation et d esactivation de assert Par d efaut, assert est d esactiv e : quand une application Java est ex ecut ee, cela se passe comme si ces instructions avaient et e enlev ees du code. Pour rendre le m ecanisme actif, il faut lancer la machine Java avec loption -enableassertions ou -ea, qui peut prendre un argument, de la mani` ere suivante : -ea -ea:unPackage ... -ea:... -ea:uneClasse -esa activation activation activation activation activation de de de de de assert assert assert assert assert partout dans lapplication, dans le paquetage indiqu e et tous ses sous-paquetages, dans le paquetage sans nom, dans la classe indiqu ee, dans toutes les classes du syst` eme.

Exemple. Ex ecution dune application dont la m ethode principale est dans la classe MaClasse en activant assert dans toutes les classes du paquetage courant : java -ea ... MaClasse

c H. Garreta, 2000-2013

61

QUELQUES CLASSES UTILES

9
9.1
9.1.1

Quelques classes utiles


Nombres et outils math ematiques
Classes-enveloppes des types primitifs

Java comporte une unique arborescence de classes, de racine Object, dans laquelle se trouvent les classes de toutes les donn ees manipul ees par les programmes... sauf les valeurs de types primitifs qui, pour d evidentes raisons decacit e, gardent leur statut de donn ees el ementaires, utilisables par les op erations basiques c abl ees dans les ordinateurs. An que ces donn ees simples puissent etre trait ees comme des objets lorsque cela est n ecessaire, Java fournit huit classes-enveloppes, une pour chaque type primitif : Byte, Short, Integer, Long, Float, Double, Boolean et Character. Le r ole principal de chaque instance dune de ces classes est dencapsuler une valeur du type primitif correspondant. Ces classes ont ` a peu pr` es les m emes m ethodes ; parmi les principales : un constructeur prenant pour argument la valeur du type primitif quil sagit denvelopper, la r eciproque : une m ethode xxx Value (xxx vaut byte, short, etc.) pour obtenir la valeur de type primitif envelopp ee, une m ethode nomm ee toString pour obtenir cette valeur sous forme de cha ne de caract` eres, eventuellement, une m ethode statique, appel ee parseXxx, permettant dobtenir une valeur dun type primitif ` a partir de sa repr esentation textuelle (cela sappelle parse car former une valeur ` a partir dun texte cest faire une analyse lexicale), eventuellement, une m ethode statique valueOf pour construire un tel objet ` a partir de sa repr esentation sous forme de texte. Par exemple, IntegerValueOf(uneChaine ) donne le m eme r esultat que new Integer(Integer.parseInt(uneChaine )) ; Pour chacune des huit classes, ces m ethodes sont 55 : Classe Byte : Byte(byte b) byte byteValue() String toString() static Byte valueOf(String s) static byte parseByte(String s) Classe Short : Short(short s) short shortValue() String toString() static Short valueOf(String s) static short parseShort(String s) Classe Integer : Integer(int i) int intValue() String toString() static Integer valueOf(String s) static int parseInt(String s) Classe Long : Long(long l) long longValue() String toString() static Long valueOf(String s) static long parseLong(String s) Classe Float : Float(float f) float floatValue() String toString() static Float valueOf(String s) static float parseFloat(String s) conversion conversion conversion conversion conversion float Float Float float Float String String Float String float conversion conversion conversion conversion conversion long Long Long long Long String String Long String long conversion conversion conversion conversion conversion int Integer Integer int Integer String String Integer String int conversion conversion conversion conversion conversion short Short Short short Short String String Short String short conversion conversion conversion conversion conversion byte Byte Byte byte Byte String String Byte String byte

55. Les deux premi` eres m ethodes list ees ici pour chacune de ces huit classes (le constructeur et la m ethode xxx Value()) assurent deux op erations quon appelle famili` erement lemballage et le d eballage dune valeur primitive. On notera qu` a partir de Java 5 ces op erations deviennent implicites (cf. section 12.2) : le compilateur se charge de les ins erer l` a o` u elles sont n ecessaires.

62

c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.1

Nombres et outils math ematiques

Classe Double : Double(double d) double doubleValue() String toString() static Double valueOf(String s) static double parseDouble(String s) Classe Boolean : Boolean(boolean b) boolean booleanValue() String toString() static Boolean valueOf(String s) Classe Character : Character(char c) char charValue() String toString() conversion char Character conversion Character char conversion Character String conversion conversion conversion conversion boolean Boolean Boolean boolean Boolean String String Boolean conversion conversion conversion conversion conversion double Double Double String String Double double String Double double

A propos de conversions, signalons egalement lexistence dans la classe String des m ethodes suivantes : static static static static static static static 9.1.2 String String String String String String String valueOf(int i) valueOf(long l) valueOf(float f) valueOf(double d) valueOf(boolean b) valueOf(char c) valueOf(Object o) conversion conversion conversion conversion conversion conversion conversion int String long String float String double String boolean String char String Object String

Fonctions math ematiques

La classe Math repr esente la biblioth` eque math ematique. Elle nest pas destin ee ` a avoir des instances : toutes ses m ethodes sont statiques. On y trouve : static double E, static double PI Les constantes e (2.718281828459045) et (3.141592653589793) type abs(type v) Valeur absolue ; type est un des types int, long, float ou double type max(type a, type b) Le plus grand de a et b ; type est un des types int, long, float ou double type min(type a, type b) Le plus petit de a et b ; type est un des types int, long, float ou double double floor(double v) Le plus grand entier inf erieur ou egal ` a v. double ceil(double v) Le plus petit entier sup erieur ou egal ` a v. double rint(double v) Lentier le plus proche de v ; sil y en a deux, celui qui est pair. int round(int v) Lentier le plus proche de v. La valeur de round(v) est la m eme que celle de (int) floor(v + 0,5). double random() Un nombre pseudo-al eatoire dans [0, 1[. (Sagissant de nombres pseudo-al eatoires, la classe java.util.Random permet de faire des choses plus savantes.) double exp(double x), double log(double x)
c H. Garreta, 2000-2013

63

9.1

Nombres et outils math ematiques

QUELQUES CLASSES UTILES

Exponentielle et logarithme nep erien. double pow(double a, double b) Elevation de a ` a la puissance b. La documentation ne donne pas dindication sur lalgorithme employ e ni sur son ecacit e, mais il est raisonnable de penser que si b est entier (cest-` a-dire si b = Math.ceil(b), alors ab est calcul e en faisant des multiplications, aussi peu nombreuses que possible. Dans le cas g en eral, ab b log a est calcul e par la formule e . double sin(double x), double cos(double x), double tan(double x), double asin(double x), double acos(double x), double atan(double x) Fonctions trigonom etriques habituelles. double atan2(double b, double a) Rend une valeur de lintervalle ] , ] qui est largument du complexe a + ib (pour a = 0 cest b ). donc la m eme chose que tan a 9.1.3 Nombres en pr ecision innie

Le paquet java.math (` a ne pas confondre avec la classe Math du paquet java.lang) ore des classes permettant de manipuler des nombres avec autant de chires que n ecessaire. Nombres entiers. Les instances de la classe BigInteger repr esentent des nombres entiers. Parmi les principaux membres de cette classe : BigInteger ZERO : la constante 0 BigInteger ONE : la constante 1 BigInteger(String s) : conversion String BigInteger BigInteger(byte[] t) : conversion byte[] BigInteger BigInteger add(BigInteger b) : addition BigInteger subtract(BigInteger b) : soustraction BigInteger multiply(BigInteger b) : multiplication BigInteger divide(BigInteger b) : quotient BigInteger remainder(BigInteger b) : reste BigInteger[] divideAndRemainder(BigInteger b) : quotient et reste BigInteger gcd(BigInteger b) : P.G.C.D. BigInteger compareTo(BigInteger b) : comparaison BigInteger max(BigInteger b) : max BigInteger min(BigInteger b) : min int intValue() : conversion BigInteger int long longValue() : conversion BigInteger long static BigInteger valueOf(long v) : conversion long BigInteger Exemple. Le programme suivant calcule la factorielle dun entier donn e en argument : class Factorielle { public static void main(String[] args) { if (args.length <= 0) System.out.println("Emploi: java Factorielle <nombre>"); else { int n = Integer.parseInt(args[0]); BigInteger k = BigInteger.ONE; BigInteger f = BigInteger.ONE; for (int i = 0; i < n; i++) { f = f.multiply(k); k = k.add(BigInteger.ONE); } System.out.println(f); } } } 64
c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.2

Collections et algorithmes

exemple dutilisation : >java Factorielle 500 122013682599111006870123878542304692625357434280319284219241358838584537 315388199760549644750220328186301361647714820358416337872207817720048078 etc. 00000000000000000000000000000000000000000000000000000000000000000000000 > cimaux. Les objets BigDecimal sont des nombres d Nombres de ecimaux en grande pr ecision. Plus pr ecis ement, un BigDecimal nombre est repr esent e par un couple form e dun BigInteger mantisse et dun int (32 bits) echelle tels que nombre = Parmi les principaux membres de cette classe : BigDecimal abs() : valeur absolue BigDecimal add(BigDecimal val) : addition BigDecimal subtract(BigDecimal val) : soustraction BigDecimal multiply(BigDecimal val) : multiplication BigDecimal divide(BigDecimal val, int roundingMode) : division int compareTo(BigDecimal val) : comparaison BigDecimal max(BigDecimal val) : max BigDecimal min(BigDecimal val) : min float floatValue() : conversion BigDecimal float double doubleValue() : conversion BigDecimal double int intValue() : conversion BigDecimal int long longValue() : conversion BigDecimal long BigInteger unscaledValue() : obtention de la partie mantisse int scale() : obtention de la partie echelle BigDecimal setScale(int scale) : d enition de la partie echelle BigDecimal movePointLeft(int n), BigDecimal movePointRight(int n) : d eplacement de la virgule mantisse 10echelle

9.2

Collections et algorithmes

Note Java 5. Les classes et interfaces de la biblioth` eque des collections et algorithmes ont et e consid erablement modi ees par lintroduction de la g en ericit e en Java 5. Notez bien que les collections sont expliqu ees ici comme en Java 1.4 ; pour les nouveaut es apparues en Java 5 consultez la section 12.5. Les programmes que nous r ealisons couramment manipulent trois sortes de donn ees : les valeurs de types primitifs, les objets et les collections dobjets. Dans les sections pr ec edentes nous avons vu ce que Java propose pour les types primitifs et les objets. Pour repr esenter les pluralit es dobjets nous ne connaissons pour linstant que les tableaux. Ceux-ci ont un avantage consid erable, la possibilit e dacc eder directement (i.e. en temps constant ) ` a un el ement ` a partir de son indice. Mais ils ont aussi un important inconv enient, le manque de souplesse dans la gestion de leur espace, puisquil faut conna tre le nombre maximum de leurs el ements au moment de leur cr eation (do` u un risque du d ebordement). Cette section montre qu` a c ot e des tableaux, la biblioth` eque Java propose une grande vari et e de collections, qui sont des structures de donn ees beaucoup plus souples et riches. 9.2.1 Collections et tables associatives

Le paquet java.util contient les interfaces et les classes pour la manipulation des collections dobjets. Nous donnons ici la liste exhaustive de ces interfaces et classes, avec une explication du principe de chacune 56 .
56. Il nest pas ais e dexpliquer les collections et, encore moins, les algorithmes qui leur sont associ es, car on ne peut pas se limiter aux sp ecication de ces classes. Par exemple, pour faire comprendre les di erences quil y a entre une ArrayList et un Vector il faut se pencher sur les impl ementations de ces classes, ce qui va contre le principe dencapsulation. Tout au long de cette section on gardera ` a lesprit que les indications sur limpl ementation restent des recommandations et que, m eme si cela semble bizarre, une r ealisation particuli` ere de la biblioth` eque pourrait ne pas les suivre, ` a condition de respecter les sp ecications.

c H. Garreta, 2000-2013

65

9.2

Collections et algorithmes

QUELQUES CLASSES UTILES

Pour les d etails pr ecis, on se r ef erera avec prot aux pages concernant le paquetage java.util dans la documentation de lAPI (http://java.sun.com/javase/6/docs/api/) et dans le tutoriel Java (http:// java.sun.com/tutorial/). Dans les descriptions suivantes la relation dh eritage entre les classes est indiqu ee par la marge laiss ee ` a gauche : Interfaces Collection. Cette interface repr esente la notion de collection dobjets la plus g en erale. A ce niveau dabstraction, les op erations garanties sont : obtenir le nombre d el ements de la collection, savoir si un objet donn e sy trouve, ajouter (sans contrainte sur la position) et enlever un objet, etc. On notera que les el ements des collections sont d eclar es avec le type Object. Cela a deux cons equences principales 57 : 1. Tout objet particulier peut devenir membre dune collection, et il ne perd rien en le devenant, mais la vue quon en a en tant que membre de la collection est la plus g en erale qui soit. Par cons equent, quand un objet est extrait dune collection il faut lui redonner explicitement le type particulier qui est le sien. Au besoin, relisez la section 7.6.1. 2. Les valeurs de types primitifs (boolean, int, float, etc.) ne peuvent pas etre directement ajout ees aux collections, il faut auparavant les emballer dans des instances des classes enveloppes correspondantes (Boolean, Integer, Float, etc.). Point important, toutes les collections peuvent etre parcourues. Cela se fait ` a laide dun it erateur (interfaces Iterator ou Enumeration, voyez la section 9.2.2), un objet qui assure que tous les el ements de la collection sont atteints, chacun ` a son tour, et qui encapsule les d etails pratiques du parcours, d ependant de limpl ementation de la collection. List. Il sagit de la notion de s equence 58 , cest-` a-dire une collection o` u chaque el ement a un rang. On trouve ici des op erations li ees ` a lacc` es direct aux el ements (insertion dun el ement ` a un rang donn e, obtention de l el ement qui se trouve ` a un rang donn e, etc.) m eme si, ` a ce niveau de g en eralit e, on ne peut pas donner dindication sur le co ut de tels acc` es. Set. Comme cest souvent le cas, la notion densemble est celle de collection sans r ep etition : un Set ne peut pas contenir deux el ements e1 et e2 v eriant e1 .equals(e2 ). Pour lessentiel, linterface Set najoute pas des m ethodes ` a linterface Collection, mais uniquement la garantie de lunicit e des el ements lors de la construction dun ensemble ou de lajout dun el ement. Aucune indication nest donn ee a priori sur lordre dans lequel les el ements dun Set sont visit es lors dun parcours de lensemble. SortedSet. Un ensemble tri e garantit que, lors dun parcours, les el ements sont successivement atteints en ordre croissant soit selon un ordre propre aux el ements (qui doivent alors impl ementer linterface Comparable), soit selon une relation dordre (un objet Comparator) donn ee explicitement lors de la cr eation de lensemble. Map. Cette interface formalise la notion de liste associative ou dictionnaire, cest-` a-dire une collection de couples (cl e, valeur ) appel es associations. Les op erations fondamentales des dictionnaires sont lajout et la suppression dune association et la recherche dune association ` a partir de la valeur dune cl e.
57. Ces deux r` egles sont importantes et il faut sassurer de bien les comprendre. Nous devons cependant signaler que dans Java 5 elles sont consid erablement adoucies par deux el ements nouveaux : les types param etr es (cf. section 12.5.1) permettent de travailler avec des collections dont les el ements sont plus pr ecis que de simples Object, lemballage et d eballage automatique (cf. section 12.2) simplient notablement lintroduction et lextraction des el ements des collections. 58. Pour exprimer que les el ements dune s equence ont un rang, la documentation ocielle parle de collections ordonn ees. Attention, lexpression est trompeuse, cela na rien ` a voir avec une quelconque relation dordre sur les el ements (les collections respectant une relation dordre sont appel ees collections tri ees ).

66

c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.2

Collections et algorithmes

Sont fournies egalement des m ethodes pour obtenir diverses vues du dictionnaire : lensemble des cl es, la collection des valeurs, lensemble des associations. Lunicit e des cl es est garantie : un objet Map ne peut pas contenir deux associations (c1 , v1 ) et (c2 , v2 ) telles que c1 .equals(c2 ). SortedMap. Un dictionnaire dans lequel les associations sont plac ees dans lordre croissant des cl es, ce qui se manifeste lors des parcours des trois collections associ ees au dictionnaire : lensemble des cl es, la collection des valeurs et lensemble des associations. Classes AbstractCollection. Cette classe abstraite ore un d ebut dimpl ementation de linterface Collection, destin ee ` a all eger leort ` a fournir pour disposer dune impl ementation compl` ete. Pour avoir une collection immuable il sut de d enir une sous-classe de AbstractCollection, dans laquelle seules les m ethodes iterator() et size() sont ` a ecrire. Pour avoir une collection modiable il faut en outre surcharger la m ethode add(Object o). AbstractList. Classe abstraite qui est un d ebut dimpl ementation de linterface List. Attention, on suppose ici quil sagit de r ealiser une collection bas ee sur une structure de donn ees, comme un tableau, dans laquelle lacc` es direct est optimis e. Si la liste nest pas bas ee sur une structure de donn ees ` a acc` es direct il vaut mieux etendre la classe AbstractSequentialList au lieu de celle-ci. Pour disposer dune liste immuable, les m ethodes get(int index) et size() sont ` a ecrire. Si on souhaite une liste modiable, il faut en outre surcharger la m ethode set(int index, Object element). AbstractSequentialList. Cette classe abstraite est un d ebut dimpl ementation de linterface List, quil faut utiliser de pr ef erence ` a AbstractList lorsque la collection ` a d enir est bas ee sur une structure de donn ees ` a acc` es (uniquement) s equentiel. Pour disposer dune liste il faut etendre cette classe en d enissant les m ethodes listIterator() et size(). Lit erateur renvoy e par la m ethode listIterator est utilis e par les m ethodes qui impl ementent lacc` es direct 59 get(int index), set(int index, Object element), etc. LinkedList. Une impl ementation compl` ete de linterface List. Une LinkedList est r eput ee etre impl ement ee par une liste cha n ee bidirectionnelle. En tout cas, toutes les op erations qui ont un sens pour de telles listes existent et ont, en principe, le co ut quelles auraient dans ce cas. Il en d ecoule que les LinkedList sont particuli` erement bien adapt ees ` a la r ealisation de piles (LIFO ), de les dattente (FIFO ) et de queues ` a deux extr emit es. ArrayList. La m eme chose quun Vector, sauf que ce nest pas synchronis e (` a propos de synchronisation, voyez la section 10.2). Vector. Un Vector est une liste impl ement ee par un tableau qui prend soin de sa propre taille. Lorsquon a besoin dun tableau qui grandit au fur et ` a mesure du d eroulement dun programme, les Vector sont une alternative int eressante aux tableaux ordinaires : lacc` es direct aux el ements y est r ealis e avec autant decacit e et, en plus, le programmeur na pas besoin destimer a priori la taille maximale de la structure, qui se charge de grandir selon les besoins, du moins si les insertions se font ` a la n du tableau. Deux propri et es, dont on peut eventuellement xer la valeur lors de la construction du Vector, en commandent la croissance : capacity : la taille courante du tableau sous-jacent au Vector, capacityIncrement : le nombre dunit es dont la capacit e est augment ee chaque fois que cela est n ecessaire.
59. Par cons equent, lacc` es au ieme el ement a un co ut proportionnel ` a i. Cest la raison pour laquelle on doit prendre AbstractSequentialList pour super-classe uniquement lorsque la structure de donn ees sous-jacente ne dispose pas dacc` es direct.

c H. Garreta, 2000-2013

67

9.2

Collections et algorithmes

QUELQUES CLASSES UTILES

De plus, un objet Vector est synchronis e 60 . Stack. Un objet Stack est une pile impl ement ee par un Vector. Cela se manifeste par des op erations sp eciques : push(Object o) : empiler un objet au sommet de la pile, Object pop() : d epiler lobjet au sommet de la pile, Object peek() : obtenir la valeur de lobjet au sommet de la pile sans le d epiler, boolean empty() : la pile est-elle vide ? int search(Object o) : rechercher un objet en partant du sommet de la pile. AbstractSet. Cette classe abstraite est un d ebut dimpl ementation de linterface Set. Le proc ed e est le m eme que pour AbstractCollection (voir ci-dessus) sauf que le programmeur doit prendre soin, en d enissant les m ethodes manquantes, dob eir aux contraintes suppl ementaires des ensembles, surtout pour ce qui est de lunicit e des el ements. HashSet. Une impl ementation (compl` ete) de linterface Set r ealis ee ` a laide dune table dadressage dispers e, ou hashcode (cest-` a-dire une instance de la classe HashMap). Cest tr` es ecace, car les op erations de base (add, remove, contains et size) se font en temps constant. Le seul inconv enient 61 est que lors des parcours de la structure les el ements apparaissent dans un ordre impr evisible. LinkedHashSet. Une impl ementation de linterface Set qui utilise une table de hascode et, de mani` ere redondante, une liste doublement cha n ee. Cela fonctionne comme un HashSet, et avec pratiquement la m eme ecacit e, mais de plus, lors des parcours de la structure ses el ements sont retrouv es dans lordre dans lequel ils ont et e ins er es (cest la premi` ere insertion qui d etermine lordre). Un LinkedHashSet est une bonne solution lorsquon ne peut pas supporter lordre g en eralement chaotique dans lequel sont parcourus les el ements dun HashSet et que, en m eme temps, on ne peut pas payer le co ut additionnel dun TreeSet, voir ci-apr` es. TreeSet. Une impl ementation de linterface Set r ealis ee ` a laide dun arbre binaire de recherche (cest-` a-dire une instance de la classe TreeMap). Lors des parcours, les el ements de lensemble apparaissent en ordre croissant soit relativement ` a un ordre qui leur est propre, et dans ce cas ils doivent impl ementer linterface Comparable, soit relativement ` a une relation dordre, un objet Comparator, fournie lors de la cr eation de la structure. Les op erations de base (add, remove et contains) sont garanties prendre un temps O(log n) (n est le nombre d el ements). AbstractMap. Cette classe abstraite ore un d ebut dimpl ementation de linterface Map, destin ee a all ` eger leort ` a fournir pour disposer dune impl ementation compl` ete. Pour avoir un dictionnaire immuable il sut de d enir une sous classe de AbstractMap et dy red enir la m ethode entrySet. Pour un dictionnaire modiable il faut en outre red enir la m ethode put. HashMap. Impl ementation de linterface Map ` a laide dune table dadressage dispers e ou hashcode. Cest tr` es ecace, car les op erations de base (get et put) se font en temps constant, du moins si on suppose que la fonction de dispersion r epartir uniform ement les valeurs des cl es. La table de hashcode est r ealis ee par un tableau qui, ` a la mani` ere dun Vector, prend soin de grandir lorsque la table atteint un certain facteur de remplissage. Le seul inconv enient est que lors des parcours de la structure les el ements apparaissent avec les cl es dans un ordre impr evisible.
60. Cela veut dire que des dispositions sont prises pour interdire que deux threads acc` edent de mani` ere concurrente ` a un m eme Vector, ce qui donnerait des r esultats impr evisibles si lun des deux modiait le vecteur. A ce propos voyez la section 10.2. 61. Ce nest quun inconv enient pratique. En th eorie, la notion de ordre dans lequel les el ements appartiennent ` a un ensemble na m eme pas de sens.

68

c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.2

Collections et algorithmes

LinkedHashMap. Impl ementation de linterface Map ` a laide dune table de hashcode et dune liste doublement cha n ee redondante. Gr ace ` a cette liste, lors des parcours de la structure les associations (cl e,valeur ) apparaissent de mani` ere ordonn ee, en principe dans lordre dans lequel elles ont et e ajout ees ` a la table (dit ordre dinsertion ). Un argument du constructeur permet de sp ecier que lon souhaite, au lieu de lordre dinsertion, un ordre d eni par les acc` es faits aux el ements une fois quils ont et e ajout es : cela consiste ` a ordonner les el ements en allant du moins r ecemment acc ed e vers le plus r ecemment acc ed e (cela permet dutiliser des objets LinkedHashMap pour r ealiser des structures LRU ). IdentityHashMap. Cette classe impl emente linterface Map comme HashMap, sauf quelle utilise la relation d equivalence d enie par lop erateur == ( egalit e des r ef erences ) au lieu de celle d enie par le pr edicat equals ( egalit e des valeurs ). Cest donc une classe tr` es technique, ` a utiliser avec une extr eme prudence. WeakHashMap. Cette classe impl emente linterface Map comme HashMap, sauf que les associations (cl e,valeur ) sont consid er ees comme etant faiblement li ees ` a la table. Cela veut dire que si la table est le seul objet qui r ef erence une association donn ee, alors cette derni` ere pourra etre d etruite par le garbage collector (cf. section 6.5.4) la prochaine fois que la m emoire viendra ` a manquer. Lint er et pratique est facile ` a voir : lorsquun objet devient sans utilit e le programmeur na pas ` a se pr eoccuper de lenlever des tables WeakHashMap dans lesquelles il a pu etre enregistr e et qui, sans cela, le feraient passer pour utile et le maintiendraient en vie. Cela etant, cest encore une classe tr` es technique, ` a utiliser avec prudence. TreeMap. Cette classe impl emente linterface SortedMap en utilisant un arbre binaire rouge et noir 62 . Cest tr` es ecace, puisque les op erations fondamentales (containsKey, get, put et remove) sont garanties en O(log n) (n est le nombre dassociations dans le dictionnaire) et, de plus, lors des parcours de la structure les associations apparaissent avec les cl es en ordre croissant : soit relativement ` a un ordre naturel, et dans ce cas les cl es doivent impl ementer linterface Comparable, soit relativement ` a une relation dordre (un objet Comparator) fournie lors de la cr eation du dictionnaire. Attention. Une relation dordre (m ethode compareTo dans le cas de linterface Comparable, m ethode compare dans le cas de linterface Comparator) doit etre compatible avec l egalit e (cf. section 9.2.4) pour quun objet TreeMap qui lutilise soit correct. 9.2.2 It erateurs

Un objet qui impl emente linterface Iterator repr esente le parcours dune collection. Il permet donc, au moyen dop erations ind ependantes de la collection particuli` ere dont il sagit, de se positionner sur le premier el ement de la collection et dobtenir successivement chaque el ement de cette derni` ere. Ce que premier el ement veut dire et lordre dans lequel les el ements sont obtenus d ependent de la nature de la collection parcourue, comme il a et e indiqu e dans la section pr ec edente. Un objet Iterator encapsule une position courante qui repr esente l etat du parcours. Les m ethodes constitutives de linterface Iterator sont : boolean hasNext() : Pr edicat vrai si et seulement si le parcours que lit erateur repr esente nest pas ni (cest-` a-dire si la position courante est valide). Object next() : Renvoie lobjet sur lequel lit erateur est positionn e et fait avancer la position courante. void remove() : Supprime de la collection le dernier el ement pr ec edemment renvoy e par lit erateur. Il faut avoir pr ealablement appel e next, et un appel de remove au plus est permis pour un appel de next.
62. A propos des arbres rouge et noir, voyez Thomas Cormen, Charles Leiserson et Ronald Rivest, Introduction a ` lalgorithmique, Dunod, 1994.

c H. Garreta, 2000-2013

69

9.2

Collections et algorithmes

QUELQUES CLASSES UTILES

Lop eration remove est facultative . Plus pr ecis ement, elle est li ee 63 au caract` ere modiable de la collection qui est en train d etre parcourue : si la collection est modiable, cette op eration doit etre op erationnelle, si la collection est immuable, cette op eration doit se limiter ` a lancer une exception UnsupportedOperationException. Limpl ementation dun it erateur d epend de la collection ` a parcourir ; par cons equent, on construit un it erateur nouveau, positionn e au d ebut dune collection, en le demandant ` a cette derni` ere. Cela fonctionne selon le sch ema suivant : Collection uneCollection ; ... Iterator unIterateur = uneCollection .iterator(); while ( unIterateur .hasNext() ) { Object unObjet = unIterateur .next(); exploitation de unObjet } Exemple. Le programme purement d emonstratif suivant ache la liste tri ee des nombres distincts 64 obtenus en tirant pseudo-al eatoirement N nombres entiers dans lintervalle [ 0, 100 [ : ... TreeSet nombres = new TreeSet(); for (int i = 0; i < N; i++) { int r = (int) (Math.random() * 100); nombres.add(new Integer(r)); } Iterator it = nombres.iterator(); while (it.hasNext()) { Object x = it.next(); System.out.print(x + " "); } ... Enumeration. Signalons lexistence de linterface Enumeration, sensiblement equivalente ` a Iterator. Sans aller jusqu` a dire que Enumeration est d esapprouv ee (deprecated ), la documentation ocielle indique quil faut lui pr ef erer Iterator... ce qui nest pas toujours possible car un certain nombre de services sont r eserv es aux enum erations et nont pas de contrepartie pour les it erateurs (par exemple, la m ethode list de la classe Collections, cf. section 9.2.4). Les homologues des m ethodes hasNext et next, dans Enumeration, sont hasMoreElements et nextElement. Le sch ema, dans le cas des enum erations, est donc celui-ci : Collection uneCollection ; ... Enumeration uneEnumeration = uneCollection .elements(); while ( uneEnumeration .hasMoreElements() ) { Object unObjet = uneEnumeration .nextElement(); exploitation de unObjet } 9.2.3 Quelques m ethodes des collections

Voici quelques m ethodes des collections parmi les plus importantes (il y en a beaucoup plus que cela) : Collection. Toutes les collections r epondent aux messages suivants : boolean isEmpty() est vrai si et seulement si la collection est vide, int size() renvoie le nombre d el ements de la collection, boolean contains(Object unObjet) est vrai si et seulement si la collection contient un el ement elt v eriant elt .equals(unObjet ),
63. Cette question est cruciale pour les collections dont les op erations fondamentales sont d enies ` a partir de lit erateur correspondant, comme dans le cas de AbstractSequentialList (cf. section 9.2.1). 64. On a des nombres distincts parce quon les range dans un ensemble, et cette liste est tri ee parce quil sagit un TreeSet.

70

c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.2

Collections et algorithmes

void add(Object unObjet) ajoute lobjet indiqu e` a la collection ; la place ` a laquelle lobjet est ajout e d epend du type particulier de la collection, void remove(Object unObjet) si la collection a des el ements elt v eriant elt .equals(unObjet ) alors lun dentre eux est enlev e de la collection ; dans le cas o` u il y en a plusieurs, savoir lequel est elimin e d epend du type de la collection. List. Les listes ont ceci de plus que les simples collections : Object get(int i) renvoie l el ement qui se trouve ` a la ieme place, void set(int i, Object unObjet) remplace le ieme el ement par lobjet indiqu e, void add(Object unObjet) ajoute lobjet indiqu e` a la n de la liste, void add(int i, Object unObjet) ins` ere lobjet indiqu e ` a la ieme place (les el ements dont lindice etait i ont, apr` es linsertion, un indice augment e de 1). Set. Les ensembles nont pas des m ethodes additionnelles, mais un certain comportement est garanti : boolean add(Object unObjet) si lensemble ne contient pas un el ement elt v eriant elt .equals(unObjet ) alors cette m ethode ajoute cet objet et renvoie true ; sinon, lensemble reste inchang e et cette m ethode renvoie false. Map. Les dictionnaires sont des collections de paires (cl e, valeur ) : Object put(Object cle, Object valeur) ajoute au dictionnaire lassociation (cl e, valeur ) indiqu ee ; cette m ethode renvoie la pr ec edente valeur associ ee ` a la cl e indiqu e, ou null si une telle cl e ne se trouvait pas dans la structure de donn ees, Object get(Object cle) renvoie la valeur associ ee ` a la cl e indiqu ee, ou null si une telle cl e nexiste pas. Attention, obtenir null comme r esultat nimplique pas n ecessairement que la cl e cherch ee nest pas dans la structure : si le couple (cl e, null) existe on obtient le m eme r esultat (pour savoir si une cl e existe il vaut mieux utiliser containsKey), boolean containsKey(Object cle) vrai si et seulement si un couple comportant la cl e indiqu ee se trouve dans le dictionnaire, boolean containsValue(Object valeur) vrai si et seulement si un ou plusieurs couples comportant la valeur indiqu ee existent dans le dictionnaire. 9.2.4 Algorithmes pour les collections

La classe Collections (notez le pluriel 65 ) est enti` erement faite de m ethodes statiques qui op` erent sur des collections, pour les transformer, y eectuer des recherches, en construire de nouvelles, etc. Nous pr esentons ici quelques m ethodes de la classe Collections parmi les plus importantes. A propos de relation dordre. Certaines des op erations d ecrites ci-apr` es cr eent ou exploitent des collections tri ees. Il faut savoir quil y a deux mani` eres de sp ecier la relation dordre par rapport ` a laquelle une structure est dite tri ee : Linterface Comparable. Dire dune classe quelle impl emente linterface Comparable cest dire que ses instances forment un ensemble muni dune relation dordre, donn ee par lunique m ethode de cette interface int compareTo(Object o) d enie par : a.compareTo(b) est n egatif, nul ou positif selon que la valeur de a est inf erieure, egale ou sup erieure ` a celle de b. Linterface Comparator. Les impl ementations de cette interface sont des relations 66 quon passe comme arguments aux m ethodes qui utilisent ou cr eent des collections ordonn ees. Cette interface comporte essentiellement la m ethode : int compare(Object o1, Object o2)
65. Il est rare quune classe soit d esign ee par un substantif pluriel ; une classe ordinaire porte plut ot le nom singulier qui d ecrit ses instances. On utilise des pluriels pour d esigner des classes enti` erement faites dutilitaires se rapportant a ` une classe qui aurait le nom en question, au singulier. Compos ees de variables et m ethodes statiques, ces classes ne sont pas destin ees a ` avoir des instances, elles sont des biblioth` eques de fonctions. 66. Ne pas confondre ces deux interfaces : un Comparable repr esente un objet sur lequel est d enie une relation dordre, un Comparator repr esente la relation dordre elle-m eme.

c H. Garreta, 2000-2013

71

9.2

Collections et algorithmes

QUELQUES CLASSES UTILES

d enie, comme la pr ec edente, par : compare(a, b) est n egatif, nul ou positif selon que la valeur de a est inf erieure, egale ou sup erieure ` a celle de b. Dans un cas comme dans lautre, ces comparaisons supportent quelques contraintes (ce qui est dit ici sur compare sapplique egalement ` a compareTo) : on doit avoir signe (compare(x,y)) == -signe (compare(y,x)) pour tout couple de valeurs x et y ; la relation est transitive : si compare(x,y) > 0 et compare(y,z) > 0 alors compare(x,z) > 0 ; si compare(x,y) == 0 alors signe (compare(x,z)) == signe (compare(y,z)) pour tout z ; en outre, bien que ce ne soit pas strictement requis, on fait g en eralement en sorte que (compare(x,y) == 0) == x.equals(y) Lorsque cette derni` ere contrainte nest pas satisfaite, la documentation doit comporter lavertissement Note : this comparator imposes orderings that are inconsistent with equals. Tri dune collection. static void sort(List uneListe) trie uneListe selon lordre naturel de ses el ements, ce qui requiert que ces el ements impl ementent linterface Comparable et soient comparables deux ` a deux. static void sort(List uneList, Comparator compar) trie uneListe selon lordre d etermin e par compar. Dans lun et lautre cas le tri est garanti stable : deux el ements equivalents (pour la relation dordre) se retrouvent plac es lun par rapport ` a lautre dans la liste tri ee comme ils etaient dans la liste avant le tri. static Comparator reverseOrder() renvoie un comparateur qui repr esente lordre inverse de lordre naturel dune collection. Par exemple, si lexpression Collections.sort(uneListe ) est correcte, alors Collections.sort(uneListe , Collections.reverseOrder()); est correcte aussi et produit le tri de la liste donn ee par ordre d ecroissant . static Object max(Collection uneCollection) static Object max(Collection uneCollection, Comparator compar) static Object min(Collection uneCollection) static Object min(Collection uneCollection, Comparator compar) Ces quatre m ethodes recherchent le maximum ou le minimum dune collection donn ee, soit par rapport ` a lordre naturel de la collection (dont les el ements doivent alors impl ementer linterface Comparable) soit par rapport ` a la relation dordre repr esent ee par largument compar. e Recherches dans une collection trie static int binarySearch(List uneListe, Object uneValeur) Recherche la valeur indiqu ee dans la liste donn ee en utilisant lalgorithme de la recherche binaire (ou dichotomique ). La liste doit etre tri ee selon son ordre naturel, ce qui implique que ses el ements impl ementent linterface Comparable et sont comparables deux ` a deux. static int binarySearch(List uneListe, Object uneValeur, Comparator compar) Recherche la valeur indiqu ee dans la liste donn ee en utilisant lalgorithme de la recherche binaire (ou dichotomique ). La liste doit etre tri ee selon lordre d eni par compar. Dans lun et lautre cas, le co ut dune recherche est de lordre de log n si la liste est bas ee sur un vrai acc` es direct aux el ements (i.e. le co ut de la recherche est O(log n) si le co ut dun acc` es est O(1)). static int indexOfSubList(List grandeListe, List petiteListe) Recherche le d ebut de la premi` ere occurrence de petiteListe en tant que sous-liste de grandeListe. Plus pr ecis ement, renvoie la plus petite valeur i 0 telle que grandeListe.subList(i, i + petiteListe.size()).equals(petiteListe) ou -1 si une telle valeur nexiste pas. static int lastIndexOfSubList(List grandeListe, List petiteListe) Recherche le d ebut de la derni` ere occurrence de petiteListe en tant que sous-liste de grandeListe. Plus pr ecis ement, renvoie la plus grande valeur i 0 telle que grandeListe.subList(i, i + petiteListe.size()).equals(petiteListe) ou -1 si une telle valeur nexiste pas. Pour les deux m ethodes ci-dessus la documentation indique que la technique employ ee est celle de la force brute . Peut- etre ne faut-il pas en attendre une grande ecacit e... 72
c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.2

Collections et algorithmes

Utilitaires de base static List nCopies(int n, Object uneValeur) Renvoie une liste immuable form ee de n copies de la valeur uneValeur. Il sagit de copie supercielle : lobjet uneValeur nest pas clon e pour en avoir n exemplaires. static void copy(List destin, List source) Copie les el ements de la liste source dans les el ements correspondants de la liste destin, qui doit etre au moins aussi longue que source. Attention, cette op eration ne cr ee pas de structure : les deux listes doivent exister. static void fill(List uneListe, Object uneValeur) Remplace toutes les valeurs de uneListe par lunique valeur uneValeur. static boolean replaceAll(List uneListe, Object ancienneValeur, Object nouvelleValeur) Remplace dans uneListe tous les el ements egaux ` a ancienneValeur par nouvelleValeur. Renvoie true si au moins un remplacement a eu lieu, false sinon. static ArrayList list(Enumeration uneEnumeration) Construit un objet ArrayList contenant les el ements successivement renvoy es par l enum eration indiqu ee, plac es dans lordre dans lequel cette derni` ere les a donn es. static void swap(List uneListe, int i, int j) Echange les valeurs de uneListe qui se trouvent aux emplacements i et j. static void reverse(List uneListe) Renverse lordre des el ements de uneListe. static void rotate(List uneListe, int distance) Fait tourner les el ements de uneListe : l el ement qui se trouvait ` a lemplacement i se trouve, apr` es lappel de cette m ethode, ` a lemplacement (i + distance) modulo uneListe.size() static void shuffle(List uneListe) R earrange pseudo-al eatoirement les el ements de uneListe. static Set singleton(Object unObjet) Renvoie un ensemble immuable constitu e de lunique el ement repr esent e par unObjet. static List singletonList(Object unObjet) Renvoie une liste immuable constitu ee de lunique el ement unObjet. static Map singletonMap(Object cl e, Object valeur) Renvoie une liste associative immuable constitu ee de lunique association (cle, valeur). La classe Collections contient encore deux autres s eries de m ethodes, pour lesquelles nous renvoyons ` a la documentation ocielle : des m ethodes synchronizedCollection(Collection c), synchronizedList(List l), synchronizedMap(Map m), etc., pour obtenir une version synchronis ee (i.e. pouvant faire face aux acc` es simultan es faits par plusieurs thread concurrents) dune collection donn ee, des m ethodes unmodifiableCollection(Collection c) unmodifiableList(List l), unmodifiableMap(Map m), etc., pour obtenir une copie immuable dune collection donn ee. 9.2.5 Algorithmes pour les tableaux

La classe Arrays (encore un pluriel) est enti` erement faite de m ethodes statiques qui op` erent sur des tableaux. Voici certaines de ces m ethodes parmi les plus importantes : static List asList(Object[] unTableau) Construit et renvoie une liste dont les el ements sont ceux du tableau indiqu e. static int binarySearch(type [] unTableau, type uneValeur) Recherche binaire (ou dichotomique ). type est un des mots byte, short, int, long, float, double ou char. Ces m ethodes recherchent uneValeur dans le tableau unTableau, qui doit etre tri e par rapport ` a lordre naturel du type en question. Elles renvoient un entier i qui repr esente si i 0, lemplacement dans le tableau de la valeur recherch ee, si i < 0, la valeur i = (j + 1) o` u j est lemplacement dans le tableau dans lequel il faudrait mettre uneValeur si on voulait lins erer tout en gardant tri e le tableau.

c H. Garreta, 2000-2013

73

9.3

R eexion et manipulation des types

QUELQUES CLASSES UTILES

static int binarySearch(Object[] unTableau, Object uneValeur) static int binarySearch(Object[] unTableau, Object uneValeur, Comparator compar) M eme d enition que pr ec edemment. Le tableau doit etre tri e, dans le premier cas par rapport ` a lordre naturel de ses el ements (qui doivent alors impl ementer linterface Comparable), dans le second cas par rapport ` a la relation dordre exprim ee par largument compar. static boolean equals(type [] unTableau, type [] unAutreTableau) Egalit e de tableaux. type est un des mots byte, short, int, long, float, double, boolean, char ou Object (autant dire nimporte quel type). Ce pr edicat est vrai si et seulement si les deux tableaux pass e comme arguments sont egaux (au sens de equals, dans le cas des tableaux dobjets). static void fill(type [] unTableau, type uneValeur) static void fill(type [] unTableau, int debut, int fin, type uneValeur) Remplissage dun tableau avec une m eme valeur. type est un des mots byte, short, int, long, float, double, boolean, char ou Object. La valeur indiqu ee est aect ee ` a tous les el ements du tableau (premier cas) ou aux el ements de rangs debut, debut+1, ... fin (second cas). static void sort(type[] unTableau) static void sort(type[] unTableau, int debut, int fin) Tri dun tableau, soit tout entier (premier cas) soit depuis l el ement dindice debut jusqu` a l el ement dindice fin (second cas). type est un des mots byte, short, int, long, float, double, boolean, char ou Object (autant dire nimporte quel type). Le tri se fait par rapport ` a lordre naturel des el ements du tableau ce qui, dans le cas o` u type est Object, oblige ces el ements ` a etre dun type qui impl emente linterface Comparable. La m ethode de tri employ ee est une variante elabor ee du lalgorithme du tri rapide (quicksort ) qui, nous dit-on, ore un co ut de n log n m eme dans un certain nombre de cas pourris o` u le quicksort de base serait quadratique. static void sort(Object[] a, int fromIndex, int toIndex, Comparator compar) M eme chose que ci-dessus, mais relativement ` a la relation dordre d enie par largument compar.

9.3

R eexion et manipulation des types

La classe java.lang.Class et les classes du paquet java.lang.reflect (aux noms evocateurs, comme Field, Method, Constructor, Array, etc.) orent la possibilit e de pratiquer une certaine introspection : un objet peut inspecter une classe, eventuellement la sienne propre, acc eder ` a la liste de ses membres, appeler une m ethode dont le nom nest connu qu` a lex ecution, etc. Une instance de la classe java.lang.Class repr esente un type (cest-` a-dire un type primitif ou une classe). Supposons que nous ayons une variable d eclar ee ainsi : Class uneClasse; Nous avons plusieurs mani` eres de lui donner une valeur : une classe-enveloppe dun type primitif (Integer, Double, etc.) poss` ede une constante de classe TYPE qui repr esente le type primitif en question ; de plus, lexpression type .class a le m eme eet. Ainsi, les deux expressions suivantes aectent le type int ` a la variable uneClasse : uneClasse = Integer.TYPE; uneClasse = int.class; si uneClasse est lidenticateur dune classe, alors lexpression uneClasse .class a pour valeur la classe en question 67 . Lexemple suivant aecte le type java.math.BigInteger ` a la variable uneClasse : uneClasse = java.math.BigInteger.class;
67. Notez la di erence entre TYPE et class pour les classes-enveloppes des types primitifs : Integer.TYPE est le type int, tandis que Integer.class est le type java.lang.Integer.

74

c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.3

R eexion et manipulation des types

on peut aussi demander le chargement de la classe, ` a partir de son nom compl` etement sp eci e. Cest un proc ed e plus on ereux que les pr ec edents, o` u la plupart du travail de chargement (dont la d etection d eventuelles erreurs dans les noms des classes) etait fait durant la compilation alors que, dans le cas pr esent, il sera fait pendant lex ecution. Lexemple suivant aecte encore le type java.math.BigInteger a la variable uneClasse : ` uneClasse = Class.forName("java.math.BigInteger"); enn, le moyen le plus naturel est de demander ` a un objet quelle est sa classe. Lexemple suivant aecte encore le type java.math.BigInteger ` a la variable uneClasse : Object unObjet = new BigInteger("92233720368547758079223372036854775807"); ... uneClasse = unObjet.getClass(); Pour survoler cette question assez pointue, voici un exemple qui illustre quelques unes des possibilit es de la classe Class et du paquet reflect. La m ethode demoReflexion ci-dessous, purement d emonstrative, prend deux objets quelconques a et b et appelle successivement toutes les m ethodes qui peuvent etre appel ees sur a avec b pour argument, cest-` a-dire les m ethodes dinstance de la classe de a qui ont un unique argument de type la classe de b :

import java.lang.reflect.Method; import java.math.BigInteger; public class DemoReflexion { static void demoReflexion(Object a, Object b) { try { Class classe = a.getClass(); Method[] methodes = classe.getMethods(); for (int i = 0; i < methodes.length; i++) { Method methode = methodes[i]; Class[] params = methode.getParameterTypes(); if (params.length == 1 && params[0] == b.getClass()) { Object r = methode.invoke(a, new Object[] { b }); System.out.println( a + "." + methode.getName() + "(" + b + ") = " + r); } } } catch (Exception exc) { System.out.println("Probl` eme : " + exc); } } public static void main(String[] args) { demoReflexion(new BigInteger("1001"), new BigInteger("1003")); } } Le programme pr ec edent ache la sortie 1001.compareTo(1003) = -1 1001.min(1003) = 1001 1001.add(1003) = 2004 ... 1001.gcd(1003) = 1 1001.mod(1003) = 1001 1001.modInverse(1003) = 501

c H. Garreta, 2000-2013

75

9.4

Entr ees-sorties

QUELQUES CLASSES UTILES

9.4

Entr ees-sorties

Note importante. Java 5 a introduit des outils simples et pratiques pour eectuer la lecture et l ecriture de donn ees format ees. Ils sont expliqu ee dans la section 12.3.4 (page 159). 9.4.1 Les classes de ux

Java fournit un nombre impressionnant de classes prenant en charge les op erations dentr ee sortie. Voici une pr esentation tr` es succincte des principales (la marge laiss ee ` a gauche re` ete la relation dh eritage). Plusieurs exemples dutilisation de ces classes sont donn es dans la section 9.4.2 : e Flux doctets en entre InputStream Cette classe abstraite est la super-classe de toutes les classes qui repr esentent des ux doctets en entr ee. Comporte une unique m ethode, int read(), dont chaque appel renvoie un octet extrait du ux. Un ux qui obtient les donn ees lues, des octets, ` a partir dun chier. Construction ` a partir dun String (le nom du chier), dun File ou dun FileDescriptor. Un ux qui obtient les donn ees lues, des octets, ` a partir dun tableau doctets indiqu e lors de la construction. Un ux qui obtient les donn ees lues, des octets, ` a partir dun PipedOutputStream auquel il est connect e. Ce deuxi` eme ux doit appartenir ` a un thread distinct, sous peine de blocage. Construction ` a partir dun PipedOutputStream ou a partir de de rien. ` Un ux qui obtient les donn ees lues, des octets, ` a partir dun autre InputStream, auquel il ajoute des fonctionnalit es. Ajoute aux fonctionnalit es dun autre InputStream la mise en tampon des octets lus. Construction ` a partir dun InputStream. Ajoute aux fonctionnalit es dun autre InputStream la possibilit e de d elire un octet (un octet d elu est retrouv e lors dune lecture ult erieure). Construction ` a partir dun InputStream. Un objet de cette classe obtient de lInputStream sousjacent des donn ees appartenant aux types primitifs de Java. Voir DataOutputStream, plus loin. Construction ` a partir dun InputStream. Un ux capable de d e-s erialiser les objets pr ealablement s erialis es dans un ObjectOutputStream. Voir les sections s erialisation et ObjectOutputStream. Construction ` a partir dun InputStream. Un ux qui obtient les donn ees lues, des octets, ` a partir de la concat enation logique dune suite dobjets InputStream. Construction ` a partir de deux InputStream ou dune enumeration dont les el ements sont des InputStream.

FileInputStream

ByteArrayInputStream PipedInputStream

FilterInputStream

BufferedInputStream

PushbackInputStream

DataInputStream

ObjectInputStream

SequenceInputStream

En r esum e: les sous-classes directes de InputStream se distinguent par le type de la source des donn ees lues, les sous classes de FilterInputStream sont diverses sortes de couches ajout ees par-dessus un autre ux. Flux doctets en sortie OutputStream sentent 76 Classe abstraite, super-classe de toutes les classes qui repr e-

c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.4

Entr ees-sorties

des ux (doctets) en sortie. Un tel ux re coit des octets et les envoie vers un certain puits ( puits soppose ` a source ) Comporte une m ethode abstraite : void write(int b), qui ecrit un octet. FileOutputStream Un ux de sortie associ e` a un chier du syst` eme sous-jacent. Construction ` a partir dun String, dun File ou dun FileDescriptor. Un ux de sortie dans lequel les donn ees sont rang ees dans un tableau doctets. Construction ` a partir de rien. Voir PipedInputStream. Construction ` a partir dun PipedInputStream ou ` a partir de rien. Un ux qui envoie les donn ees ` a un autre ux (donn e lors de la construction) apr` es leur avoir appliqu e un certain traitement. Construction ` a partir dun OutputStream. Un ux de sortie qui regroupe les octets logiquement ecrits avant de provoquer un appel du syst` eme sous-jacent en vue dune ecriture physique. Construction ` a partir dun OutputStream. Un ux de sortie destin e` a l ecriture de donn ees des types primitifs de Java. Les donn ees ne sont pas format ees (traduites en textes lisibles par un humain) mais elles sont ecrites de mani` ere portable. Construction ` a partir dun OutputStream. Un ux destin e` a l ecriture de toutes sortes de donn ees, sous une forme lisible par un humain. Ces ux ne g en` erent jamais dexception ; ` a la place, ils positionnent une variable priv ee qui peut etre test ee ` a laide de la m ethode checkError. De plus, ces ux g` erent le vidage (ushing) du tampon dans certaines circonstances : appel dune m ethode println, ecriture dun caract` ere \n, etc. Construction ` a partir dun OutputStream. Un ux de sortie pour ecrire des donn ees de types primitifs et des objets Java dans un OutputStream. Cela sappelle la s erialisation des donn ees. Les objets peuvent ensuite etre lus et reconstitu es en utilisant un ObjectInputStream. Construction ` a partir dun OutputStream. Seuls les objets qui impl ementent linterface Serializable peuvent etre ecrits dans un ux ObjectOutputStream. La classe (nom et signature) de chaque objet est cod ee, ainsi que les valeurs des variables dinstance (sauf les variables d eclar ees transient). La s erialisation dun objet implique la s erialisation des objets que celui-ci r ef erence, il sagit donc de mettre en s equence les nuds dun graphe, qui peut etre cyclique. Cest pourquoi cette op eration, assez complexe, est tr` es utile. `res en entre e Flux de caracte Les ux de caract` eres, en entr ee et en sortie. Ces ux sont comme les ux doctets, mais linformation el ementaire y est le caract` ere (Java utilisant le codage Unicode, un caract` ere nest pas la m eme chose quun octet).
c H. Garreta, 2000-2013

ByteArrayOutputStream

PipedOutputStream

FilterOutputStream

BufferedOutputStream

DataOutputStream

PrintStream

ObjectOutputStream

77

9.4

Entr ees-sorties

QUELQUES CLASSES UTILES

Reader

Classe abstraite, super-classe de toutes les classes qui lisent des ux de caract` eres. Deux m ethodes abstraites : int read(char[], int, int) et void close(). Les objets de cette classe am eliorent lecacit e des op eradentr ee en bu erisant les lectures sur un ux sousjacent (un objet Reader donn e en argument du constructeur). Construction ` a partir dun Reader. LineNumberReader Un ux dentr ee bu eris e qui garde trace des num eros des lignes lues. (Une ligne est une suite de caract` eres termin ee par \r, \n ou \r\n). Construction ` a partir dun Reader. Un ux qui obtient les caract` eres lus ` a partir dun tableau de caract` eres interne, quon indique lors de la construction du ux. Construction ` a partir dun char[]. Un ux de caract` eres qui obtient les donn ees dans un ux doctets (un objet InputStream donn e en argument du constructeur). Un tel objet assure donc le travail de conversion des octets en caract` eres. Construction ` a partir dun InputStream. (Classe de confort) Un ux dentr ee de caract` eres qui obtient ses donn ees dans un chier. On suppose que le codage des caract` eres par d efaut et la taille par d efaut du tampon sont ad equats. (Si tel nest pas le cas il vaut mieux construire un InputStreamReader sur un FileInputStream) Construction ` a partir dun String, dun File ou dun FileDescriptor. Classe abstraite pour la lecture de ux ltr es ( ?) Poss` ede, ` a titre de membre, un objet Reader dont il ltre les caract` eres lus. Flux dentr ee de caract` eres ayant la possibilit e de d elire un ou plusieurs caract` eres. Construction ` a partir dun Reader. L equivalent, pour des ux de caract` eres, dun PipedInputStream. Construction ` a partir dun PipedWriter ou ` a partir de rien. Un ux de caract` eres dont la source est un objet String. Construction ` a partir dun String.

BufferedReader tions

CharArrayReader

InputStreamReader

FileReader

FilterReader

PushbackReader

PipedReader StringReader

`res en sortie Flux de caracte Writer Classe abstraite, super-classe de toutes les classes qui ecrivent des ux de caract` eres. M ethodes abstraites : void write(char[], int, int), void flush() et void close(). Un ux de sortie dans lequel les caract` eres logiquement ecrits sont group es pour diminuer le nombre eectif d ecriphysiques. Construction ` a partir dun Writer. CharArrayWriter 78 Un ux qui met les caract` eres produits dans un tableau de
c H. Garreta, 2000-2013

BufferedWriter tures

QUELQUES CLASSES UTILES

9.4

Entr ees-sorties

caract` eres. Construction ` a partir de rien. OutputStreamWriter Un ux qui met les caract` eres ecrits dans un OutputStream pr ealablement construit. Un tel objet prend donc en charge la conversion des caract` eres en des octets. Construction ` a partir dun OutputStream. (Classe de confort) Un ux qui envoie les caract` eres ecrits dans un chier. Construction ` a partir dun String, dun File ou dun FileDescriptor. Classe abstraite pour la d enition de ux ltr es d ecriture de caract` eres. L equivalent, pour un ux de caract` eres, dun PipedOutputStream. Voir PipedReader. Construction ` a partir dun PipedReader ou ` a partir de rien. Un ux qui met les caract` eres ecrits dans un objet StringBuffer, lequel peut etre utilis e pour construire un String. Construction ` a partir de rien. Un ux de caract` eres destin e` a lenvoi de repr esentations format ees de donn ees dans un ux pr ealablement construit. Un PrintWriter se construit au-dessus dun OutputStream ou dun Writer pr ealablement cr e e.

FileWriter

FilterWriter PipedWriter

StringWriter

PrintWriter

Autres classes File Un objet File est la repr esentation abstraite dun chier, dun r epertoire ou, plus g en eralement, dun chemin du syst` eme de chiers sous-jacent. Un FileDescriptor est un objet opaque qui repr esente une entit e sp ecique de la machine sous-jacente : un chier ouvert, un socket ouvert ou toute autre source ou puits doctets. La principale utilit e dun tel objet est la cr eation dun FileInputStream ou dun FileOutputStream. Un objet RandomAccessFile repr esente un chier supportant lacc` es relatif. Cette classe impl emente les interfaces DataInput et DataOutput, cest-` a-dire quelle supporte les op erations de lecture et d ecriture, ainsi que des op erations pour positionner et obtenir la valeur dune certaine position courante dans le chier Un objet de cette classe est un analyseur qui reconna t des unit es lexicales form ees doctets ou de caract` eres provenant dune source de donn ees. Les unit es sont de quatre types : TT_NUMBER (la valeur est un double), TT_WORD, TT_EOF et ( eventuellement) TT_EOL. Dans le m eme ordre did ees, voir aussi StringTokenizer.

FileDescriptor

RandomAccessFile

StreamTokenizer

9.4.2

Exemples

1. Ecriture et lecture dans un fichier binaire . Les deux m ethodes de la classe FichierBinaire suivante permettent denregistrer un tableau de nombres ottants (des double) dans un chier, ou bien de reconstituer un tel tableau ` a partir de ses valeurs pr ealablement enregistr ees. Le chier en question est form e dun nombre entier n suivi de n nombres ottants en double pr ecision :
c H. Garreta, 2000-2013

79

9.4

Entr ees-sorties

QUELQUES CLASSES UTILES

class FichierBinaire { public void sauver(double nombres[], String nomFichier) throws IOException { FileOutputStream fichier = new FileOutputStream(nomFichier); DataOutputStream donnees = new DataOutputStream(fichier); int combien = nombres.length; donnees.writeInt(combien); for (int i = 0; i < combien; i++) donnees.writeDouble(nombres[i]); donnees.close(); } public double[] restaurer(String nomFichier) throws IOException { FileInputStream fichier = new FileInputStream(nomFichier); DataInputStream donnees = new DataInputStream(fichier); int combien = donnees.readInt(); double[] result = new double[combien]; for (int i = 0; i < combien; i++) result[i] = donnees.readDouble(); donnees.close(); return result; } } 2. Ecriture et lecture dans un fichier de texte. M eme sorte de travail qu` a lexemple pr ec edente, mais le chier est maintenant de texte. Cest moins ecace, puisque les donn ees sont exprim ees sous une forme textuelle (donc du travail suppl ementaire lors de l ecriture et lors de la lecture), mais cela permet lexploitation ou la modication du chier par des outils g en eraux (imprimantes, editeurs de texte, etc.). Pour faciliter l eventuelle exploitation humaine du chier, devant chaque donn ee ni on ecrit son rang i : class FichierDeTexte { public void sauver(double nombres[], String nomFichier) throws IOException { FileOutputStream fichier = new FileOutputStream(nomFichier); PrintWriter donnees = new PrintWriter(fichier); int combien = nombres.length; donnees.println(combien); for (int i = 0; i < combien; i++) donnees.println(i + " " + nombres[i]); donnees.close(); } public double[] restaurer(String nomFichier) throws IOException { FileInputStream fichier = new FileInputStream(nomFichier); InputStreamReader adaptateur = new InputStreamReader(fichier); LineNumberReader donnees = new LineNumberReader(adaptateur); String ligne = donnees.readLine(); int combien = Integer.parseInt(ligne); double[] result = new double[combien]; for (int i = 0; i < combien; i++) { ligne = donnees.readLine(); StringTokenizer unites = new StringTokenizer(ligne); unites.nextToken(); // on ignore le rang i result[i] = Double.parseDouble(unites.nextToken()); } if (donnees.readLine() != null) throw IOException("Il y a plus de donn ees que pr evu"); donnees.close(); return result; } e standard. La classe Est (comme Entree STandard) ore un petit nombre 3. Lecture sur lentre de m ethodes statiques destin ees ` a eectuer simplement des op erations de lecture ` a lentr ee standard (souvent le clavier) : int lireInt() : lecture dun nombre entier, 80
c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.4

Entr ees-sorties

double lireDouble() : lecture dun nombre ottant, char lireChar() : lecture dun caract` ere, String lireString() : lecture de toute une ligne, void viderTampon() : remise ` a z ero du tampon dentr ee.

Note Java 5. La classe Est montr ee ici reste un exemple int eressant dutilisation de la biblioth` eque des entr ees-sorties, mais il faut savoir qu` a partir de la version 5 de Java le service rendu par cette classe est pris en charge de mani` ere un peu plus professionnelle par la classe java.util.Scanner de la biblioth` eque standard (cf. 12.3.4, page 159). Exemple dutilisation de notre classe Est : ... int numero; String denomination; double prix; char encore; ... do { System.out.print("numero? "); numero = Est.lireInt(); System.out.print("d enomination? "); Est.viderTampon(); denomination = Est.lireString(); System.out.print("prix? "); prix = Est.lireDouble(); System.out.print("Encore (o/n)? "); Est.viderTampon(); encore = Est.lireChar(); } while (encore == o); ... Voici la classe Est : import java.io.*; import java.util.StringTokenizer; public class Est { public static int lireInt() { return Integer.parseInt(uniteSuivante()); } public static double lireDouble() { return Double.parseDouble(uniteSuivante()); } public static char lireChar() { if (tampon == null) tampon = lireLigne(); if (tampon.length() > 0) { char res = tampon.charAt(0); tampon = tampon.substring(1); return res; } else { tampon = null; return \n; } } public static String lireString() { if (tampon == null) return lireLigne();
c H. Garreta, 2000-2013

// Si tous les caract` eres ordinaires // de la ligne courante ont et e lus, // le caract` ere renvoy e est \n

81

9.4

Entr ees-sorties

QUELQUES CLASSES UTILES

else { String res = tampon; tampon = null; return res; } } public static void viderTampon() { tampon = null; } private static String uniteSuivante() { if (tampon == null) tampon = lireLigne(); StringTokenizer unites = new StringTokenizer(tampon, limites); while ( ! unites.hasMoreTokens()) { tampon = lireLigne(); unites = new StringTokenizer(tampon, limites); } String unite = unites.nextToken(); tampon = tampon.substring(tampon.indexOf(unite) + unite.length()); return unite; } private static String lireLigne() { try { // Les IOException sont transform ees return entree.readLine(); // en RuntimeException (non contr^ ol ees) } catch (IOException ioe) { throw new RuntimeException("Erreur console [" + ioe.getMessage() +"]"); } } private static BufferedReader entree = new BufferedReader(new InputStreamReader(System.in)); private static String tampon = null; private static final String limites = " \t\n,;:/?!%#$()[]{}"; } 9.4.3 Analyse lexicale

Lanalyse lexicale est la transformation dune suite de caract` eres en une suite dunit es lexicales ou tokens des mots ob eissant ` a une grammaire lexicale souvent d enie par un ensemble dexpressions r eguli` eres. En Java, lanalyse lexicale la plus basique est prise en charge par les objets StringTokenizer et StreamTokenizer. A partir de la version 1.4, des analyseurs plus sophistiqu es peuvent etre r ealis es ` a laide des classes de manipulation dexpressions r eguli` eres, java.util.regex.Pattern et java.util.regex.Matcher. A ce sujet, voyez la section 9.5. Dautre part, Java 5 introduit la classe java.util.Scanner, plus puissante que StreamTokenizer mais plus simple demploi que le couple Pattern et Matcher. Pour illustrer lemploi des objets StreamTokenizer, ou analyseurs lexicaux de ux , voici un exemple classique (classique dans certains milieux !) : le programme suivant reconna t et evalue des expressions arithm etiques lues ` a lentr ee standard, form ees avec des nombres, les quatre op erations et les parenth` eses, et termin ees par le caract` ere =. Il est int eressant dobserver lempilement de ux dentr ee r ealis e dans le constructeur de la classe Calculateur : ` a la base, il y a System.in, qui est un ux doctets (un InputStream) ; autour de ce ux on a mis adaptateur, qui est un ux de caract` eres (un InputStreamReader, donc un Reader) ; autour de ce dernier, on a construit unites, un ux dunit es lexicales (un StreamTokenizer).

82

c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.4

Entr ees-sorties

class Calculateur { private StreamTokenizer unites; public Calculateur() throws IOException { InputStreamReader adaptateur = new InputStreamReader(System.in); unites = new StreamTokenizer(adaptateur); }

public double unCalcul() throws Exception { unites.nextToken(); double result = expression(); if (unites.ttype != =) throw new ErreurSyntaxe("= attendu ` a la fin de lexpression"); return result; }

private double expression() throws IOException, ErreurSyntaxe { double result = terme(); int oper = unites.ttype; while (oper == + || oper == -) { unites.nextToken(); double tmp = terme(); if (oper == +) result += tmp; else result -= tmp; oper = unites.ttype; } return result; }

private double terme() throws IOException, ErreurSyntaxe { double result = facteur(); int oper = unites.ttype; while (oper == * || oper == /) { unites.nextToken(); double tmp = facteur(); if (oper == *) result *= tmp; else result /= tmp; oper = unites.ttype; } return result; }

private double facteur() throws IOException, ErreurSyntaxe { double result = 0;

if (unites.ttype == StreamTokenizer.TT_NUMBER) { result = unites.nval; unites.nextToken(); }


c H. Garreta, 2000-2013

83

9.4

Entr ees-sorties

QUELQUES CLASSES UTILES

else if (unites.ttype == () { unites.nextToken(); result = expression(); if (unites.ttype != )) throw new ErreurSyntaxe(") attendue " + unites.ttype); unites.nextToken(); } else throw new ErreurSyntaxe("nombre ou ( attendu " + unites.ttype); return result; } } class ErreurSyntaxe extends Exception { ErreurSyntaxe(String message) { super(message); } } 9.4.4 Mise en forme de donn ees

Le paquet java.text est fait de classes et dinterfaces pour la mise en forme de textes, dates, nombres, etc. Les plus utiles, pour nous : Format NumberFormat Classe abstraite concernant la mise en forme des donn ees sensibles aux particularit es locales (nombres, dates, etc.). Classe abstraite, super-classe des classes concernant la mise en forme et la reconnaissance des nombres (aussi bien les types primitifs que leurs classes-enveloppes). Classe concr` ete, prenant en charge l ecriture en base 10 des nombres. Un objet de cette classe repr esente lensemble des symboles qui interviennent dans le formatage dun nombre (s eparad ecimal, s eparateur de paquets de chires, etc.). Le constructeur par d efaut de cette classe initialise un objet avec les valeurs locales de tous ces symboles. Examinons quelques exemples : Exemple 1. Ecriture dun nombre en utilisant le format local (i.e. le format en vigueur ` a lendroit o` u le programme est ex ecut e) : import java.text.NumberFormat; public class AProposDeFormat { static public void main(String[] args) { NumberFormat formateur = NumberFormat.getInstance(); double x = 1234567.23456789; System.out.println("format \"brut\"

DecimalFormat DecimalFormatSymbols teur

: " + x);

String s = formateur.format(x); System.out.println("format local par d efaut : " + s); ... Achage obtenu (en France) : format "brut" : 1234567.23456789 format local par d efaut : 1 234 567,235 Comme on le voit ci-dessus, il se peut que des nombres format es en accord avec les particularit es locales ne puissent pas etre donn es ` a relire aux m ethodes basiques de Java, comme Integer.parseInt ou 84
c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.4

Entr ees-sorties

Double.parseDouble. Pour reconstruire les nombres que ces textes expriment on doit employer les m ethodes correspondantes de la classe NumberFormat. Voici une possible continuation de lexemple pr ec edent : ... try { Number n = formateur.parse(s); x = n.doubleValue(); } catch (ParseException exc) { System.out.println("Conversion impossible : " + exc.getMessage()); } System.out.println("valeur \"relue\" : " + x); } } Achage obtenu maintenant : format "brut" : 1234567.23456789 format local par d efaut : 1 234 567,235 valeur "relue" : 1234567.235 Exemple 2. Utilisation de ces classes pour obtenir une mise en forme pr ecise qui ne correspond pas forc ement aux particularit es locales. Dans lexemple suivant on ecrit les nombres avec exactement deux d ecimales, la virgule d ecimale etant repr esent ee par un point et les chires avant la virgule group es par paquets de trois signal es par des apostrophes : public class Formatage { static public void main(String[] args) { DecimalFormatSymbols symboles = new DecimalFormatSymbols(); symboles.setDecimalSeparator(.); symboles.setGroupingSeparator(\); DecimalFormat formateur = new DecimalFormat("###,###,###.00", symboles); double d = 1.5; System.out.println(formateur.format(d)); d = 0.00123; System.out.println(formateur.format(d)); int i = 12345678; System.out.println(formateur.format(i)); } } lachage est ici : 1.50 .00 12345678.00 Variante, avec : DecimalFormat formateur = new DecimalFormat("000,000,000.00", symboles); lachage aurait et e: 000000001.50 000000000.00 012345678.00 Exemple 3. Des formats sp eciques comme les pr ec edents peuvent aussi etre compos es ` a laide de m ethodes set... de la classe DecimalFormat :
c H. Garreta, 2000-2013

85

9.4

Entr ees-sorties

QUELQUES CLASSES UTILES

public class Formatage { public static void main(String[] args) { DecimalFormat formateur = (DecimalFormat) NumberFormat.getInstance(); // Modifier ce format afin quil ressemble ` a 999.99[99] DecimalFormatSymbols symboles = new DecimalFormatSymbols(); symboles.setDecimalSeparator(.); formateur.setDecimalFormatSymbols(symboles); formateur.setMinimumIntegerDigits(3); formateur.setMinimumFractionDigits(2); formateur.setMaximumFractionDigits(4); double d = 1.5; System.out.println(d + " se formate en " + formateur.format(d)); d = 1.23456789; System.out.println(d + " se formate en " + formateur.format(d)); } } Ex ecution :

1.5 se formate en 001.50 1.23456789 se formate en 001.2346

Exemple 4. La classe Fomat et ses voisines norent pas un moyen simple deectuer un cadrage ` a droite des nombres ou, plus exactement, un cadrage calcul e` a partir de la position de la virgule. De telles mises en forme sont n ecessaires pour constituer des colonnes de nombres correctement align es. Par exemple, proposons-nous dacher une table de conversion en degr es Celsius dune s erie de temp eratures exprim ees en degr es Fahrenheit : public class ConversionTemperature { public static void main(String[] args) { NumberFormat formateur = new DecimalFormat("##.###"); for (int f = -40; f <= 120; f += 20) { double c = (f - 32) / 1.8; System.out.println(f + " " + formateur.format(c)); } } } Lachage obtenu nest pas tr` es beau : -40 -40 -20 -28,889 0 -17,778 20 -6,667 40 4,444 60 15,556 80 26,667 100 37,778 120 48,889 Voici une deuxi` eme version de ce programme, dans laquelle un objet FieldPosition est utilis e pour conna tre, dans lexpression format ee dun nombre, lindice du caract` ere sur lequel se termine sa partie enti` ere (cest-` a-dire, selon le cas, soit la n du nombre, soit la position de la virgule). Cet indice permet de calculer le nombre de blancs quil faut ajouter ` a la gauche du nombre pour le cadrer proprement : 86
c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.4

Entr ees-sorties

public class ConversionTemperature { public static void main(String[] args) { NumberFormat formateur = new DecimalFormat("##.###"); FieldPosition pos = new FieldPosition(NumberFormat.INTEGER_FIELD); for (int c = -40; c <= 120; c += 20) { double f = (c - 32) / 1.8; String sc = formateur.format(c, new StringBuffer(), pos).toString(); sc = ajoutEspaces(4 - pos.getEndIndex(), sc); String sf = formateur.format(f, new StringBuffer(), pos).toString(); sf = ajoutEspaces(4 - pos.getEndIndex(), sf); System.out.println(sc + " " + sf); } } private static String ajoutEspaces(int n, String s) { return " ".substring(0, n) + s; } } Lachage obtenu maintenant est nettement mieux align e: -40 -20 0 20 40 60 80 100 120 9.4.5 -40 -28,889 -17,778 -6,667 4,444 15,556 26,667 37,778 48,889

Repr esentation des dates

La manipulation et lachage des dates sont trait es en Java avec beaucoup de soin (portabilit e oblige !), mais la question peut sembler un peu embrouill ee car elle est r epartie sur trois classes distinctes de mani` ere un peu arbitraire : java.util.Date - Un objet de cette classe encapsule un instant dans le temps (repr esent e par le nombre de millisecondes ecoul ees entre le 1er janvier 1970, ` a 0:00:00 heures GMT, et cet instant). Dautre part, ces objets ont des m ethodes pour le calcul de lann ee, du mois, du jour, etc., mais elles sont d esapprouv ees, ce travail doit d esormais etre donn e` a faire aux objets Calendar. java.util.GregorianCalendar - Cette classe est une sous-classe de la classe abstraite Calendar. Ses instances repr esentent des dates, d ecompos ees en plusieurs nombres qui expriment lann ee, le mois, le jour dans le mois, dans lann ee et dans la semaine, lheure, les minutes, etc. java.text.DateFormat - Les instances de cette classe, fortement d ependante des particularit es locales, soccupent de lexpression textuelle des dates. Exemple 1. Voici comment mesurer le temps que prend lex ecution dun certain programme (attention, il sagit de temps ecoul e , qui comprend donc le temps pris par d eventuelles autres t aches qui ont et e entrelac ees avec celle dont on cherche ` a mesurer la dur ee) : ... void unCalcul() { Date d0 = new Date(); un calcul prenant du temps... Date d1 = new Date(); System.out.println("Temps ecoul e: " + (d1.getTime() - d0.getTime()) / 1000.0 + " secondes");
c H. Garreta, 2000-2013

87

9.4

Entr ees-sorties

QUELQUES CLASSES UTILES

} ... Exemple 2. Un programme pour savoir en quel jour de la semaine tombe une date donn ee : class Jour { public static void main(String[] args) { if (args.length < 3) System.out.println("Emploi: java Jour <jour> <mois> <annee>"); else { int j = Integer.parseInt(args[0]); int m = Integer.parseInt(args[1]); int a = Integer.parseInt(args[2]); GregorianCalendar c = new GregorianCalendar(a, m - 1, j); int s = c.get(GregorianCalendar.DAY_OF_WEEK); String[] w = { "dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi" }; System.out.println(w[s - 1]); } } } Exemple 3. Achage personnalis e de la date. Chaque fois quon demande ` a un objet Maintenant de se convertir en cha ne de caract` eres, il donne une expression de la date et heure courantes : class Maintenant { private static String[] mois = { "janvier", "f evrier", "mars", ... "d ecembre" }; private static String[] jSem = { "dimanche", "lundi", "mardi", ... "samedi" }; public String toString() { GregorianCalendar c = new GregorianCalendar(); return jSem[c.get(c.DAY_OF_WEEK) - 1] + " " + c.get(c.DAY_OF_MONTH) + " " + mois[c.get(c.MONTH) - 1] + " " + c.get(c.YEAR) + " ` a " + c.get(c.HOUR) + " heures " + c.get(c.MINUTE); } public static void main(String[] args) { System.out.println("Aujourdhui: " + new Maintenant()); } } Exemple 4. La m eme chose, ` a laide dun objet DateFormat : class Maintenant { DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.MEDIUM, Locale.FRANCE); public String toString() { return df.format(new Date()); } public static void main(String[] args) { System.out.println("Aujourdhui: " + new Maintenant()); } } 9.4.6 La s erialisation

La s erialisation est un m ecanisme tr` es puissant, tr` es utile et tr` es simple demploi pour sauvegarder des objets entiers dans des chiers et de les restaurer ult erieurement. Les points cl es en sont : pour que les instances dune classe puissent etre s erialis ees il doit etre dit que cette classe impl emente linterface Serializable, une interface vide par laquelle le programmeur exprime quil ny a pas dopposition ` a ce que les objets en question soient conserv es dans un chier, la s erialisation dun objet implique la sauvegarde des valeurs de toutes ses variables dinstance, sauf celles d eclar ees transient (transitoires), la s erialisation dun objet implique en principe celle des objets quil r ef erence (ses objets membres) qui doivent donc etre egalement s erialisables, le couple s erialisation (sauvegarde dans un chier) d es erialisation (restauration depuis un chier) comporte un m ecanisme de contr ole des versions, assurant que les classes servant ` a la reconstitution des objets sont coh erentes avec les classes dont ces objets etaient instances lors de leur s erialisation, 88
c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.4

Entr ees-sorties

Le service rendu par Java lors de la s erialisation dun objet est important, car la t ache est complexe. En eet, pour sauvegarder un objet il faut sauvegarder aussi les eventuels objets qui sont les valeurs de ses variables dinstance ; ` a leur tour, ces objets peuvent en r ef erencer dautres, quil faut sauver egalement, et ainsi de suite. Cela revient ` a parcourir un graphe, qui tr` es souvent comporte des cycles, en evitant de sauvegarder plusieurs fois un m eme objet et sans sombrer dans des boucles innies. A titre dexemple, voici un programme purement d emonstratif qui cr ee une liste cha n ee circulaire et la sauvegarde dans un chier. Chaque maillon porte une date (linstant de sa cr eation) dont on a suppos e que la sauvegarde etait sans int er et ; pour cette raison, cette variable a et e d eclar ee transient :

class Maillon implements Serializable { String info; transient Date date; Maillon suivant; Maillon(String i, Maillon s) { info = i; suivant = s; date = new Date(); } public String toString() { return info + " " + date; } } class TestSerialisation { static String[] jour = { "Dimanche", "Lundi", "Mardi", ... "Samedi" }; public static void main(String[] args) { Maillon tete, queue; tete = queue = new Maillon(jour[6], null); for (int i = 5; i >= 0; i--) tete = new Maillon(jour[i], tete); queue.suivant = tete; try { ObjectOutputStream sortie = new ObjectOutputStream( new FileOutputStream("Liste.dat")); sortie.writeObject(tete); sortie.close(); } catch (Exception e) { System.out.println("probl` eme fichier: " + e.getMessage()); } } }

Et voici un programme qui reconstruit la liste cha n ee (bien entendu, dans la liste reconstitu ee les maillons nont pas de date) : class TestDeserialisation { public static void main(String[] args) { Maillon tete = null; try { ObjectInputStream entree = new ObjectInputStream( new FileInputStream("Liste.dat")); tete = (Maillon) entree.readObject(); entree.close(); }
c H. Garreta, 2000-2013

89

9.5

Expressions r eguli` eres

QUELQUES CLASSES UTILES

catch (Exception e) { System.out.println("probl` eme fichier: " + e.getMessage()); } // affichage de contr^ ole for (int i = 0; i < 7; i++, tete = tete.suivant) System.out.println(tete); } }

9.5
9.5.1

Expressions r eguli` eres


Principe

Le lecteur est suppos e conna tre par ailleurs la notion dexpression r eguli` ere, dont lexplication, m eme succincte, d epasserait le cadre de ce cours. Disons simplement que les expressions r eguli` eres consid er ees ici sont grosso modo celles du langage Perl 68 , et donnons quelques exemples montrant leur utilisation en Java. Le paquetage concern e, java.util.regex, se compose des deux classes Pattern et Matcher : Pattern - Un objet de cette classe est la repr esentation compil ee 69 dune expression r eguli` ere. Cette classe na pas de constructeur. On cr ee un objet Pattern par une expresion de la forme : Pattern motif = Pattern.compile(texteExpReg [, ags ]); o` u texteExpReg est une cha ne de caract` eres contenant lexpression r eguli` ere. Si cette derni` ere est incorrecte, linstruction ci-dessus lance une exception PatternSyntaxException, qui est une sousclasse de RuntimeException 70 . Matcher - Un objet de cette classe se charge dappliquer une expression r eguli` ere sur un texte, pour eectuer les op erations de reconnaissance, de recherche ou de remplacement souhait ees. On cr ee un objet Matcher ` a partir dun objet Pattern, par une expression de la forme : Matcher reconnaisseur = motif .matcher(texteAExaminer ); Lobjet reconnaisseur ainsi cr e e dispose des m ethodes : boolean matches() : lexpression r eguli` ere reconna t-elle la totalit e du texte ` a examiner ? boolean lookingAt() : lexpression r eguli` ere reconna t-elle le d ebut du texte ` a examiner ? boolean find([int start]) : lexpression r eguli` ere reconna t-elle un morceau du texte ` a examiner ? A la suite dun appel dune des trois m ethodes ci-dessus, les m ethodes int start() et int end() de lobjet Matcher renvoient le d ebut et la n de la sous-cha ne reconnue, tandis que la m ethode String group() renvoie la cha ne reconnue elle-m eme. On se reportera ` a la documentation de lAPI pour des explications sur les (nombreuses) autres possibilit es de la classe Matcher. 9.5.2 Exemples

couper un texte. Pour les op 1. De erations les plus simples il ny a pas besoin de cr eer des objets Matcher, des m ethodes ordinaires (exemple 1) ou statiques (exemple 2) de la classe Pattern susent. Par exemple, le programme suivant prend une cha ne donn ee en argument et lache ` a raison dun mot par ligne, en consid erant que les s eparateurs de mots sont la virgule ( , ), le point-virgule ( ; ) et les caract` eres blancs de toute sorte (collectivement repr esent es par \s ) :

68. La syntaxe pr ecise des expressions r eguli` eres accept ees par Java est donn ee dans la documentation de lAPI, au d ebut de lexplication concernant la classe java.util.regex.Pattern 69. Un objet Pattern consiste essentiellement en lencapsulation des tables qui d enissent lautomate d etats ni correspondant ` a lexpression r eguli` ere donn ee. 70. Rappelons que les RuntimeException sont des exceptions non contr ol ees. Par cons equent, si une m ethode contient des appels de Pattern.compile il nest pas n ecessaire de lui adjoindre une clause throws PatternSyntaxException .

90

c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.5

Expressions r eguli` eres

import java.util.regex.Pattern; public class Mots { public static void main(String[] args) { Pattern motif = Pattern.compile("[,;\\s]+"); // d ecoupe de la cha^ ne args[0] en mots String[] tabMots = motif.split(args[0]); for (int i = 0; i < tabMots.length; i++) System.out.println(tabMots[i]); } }

Exemple dutilisation :

$ java Mots Andr e B eatrice Caroline Emile $

"Andr e, B eatrice

Caroline,

Emile"

rifier la correction dune cha 2. Ve ne. Une autre op eration simple quune m ethode statique de la classe Pattern peut eectuer sans laide dun objet Matcher : compiler une expression r eguli` ere et d eterminer si elle correspond ` a la totalit e dune cha ne donn ee. Par exemple, la m ethode suivante d etermine si la cha ne pass ee en argument est l ecriture correcte dun nombre d ecimal en virgule xe :

boolean bienEcrit(String texte) { final String expr = "[+-]?[0-9]+(\\.[0-9]*)?"; // texte appartient-il ` a lensemble de mots d efini par expr ? return Pattern.matches(expr, texte); }

Note 1. Cette m ethode donne pour bonnes des cha nes comme "12.3", "123." et "123", mais rejette ".123". Pour corriger cela il sut de d enir expr comme ceci : final String expr = "[+-]?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))";

Note 2. Dans le cas o` u la m ethode pr ec edente est susceptible d etre fr equemment appel ee, il est manifestement maladroit de compiler chaque fois la m eme expression r eguli` ere. Lemploi dun objet Pattern permet d eviter cela :

Pattern pattern = Pattern.compile("[+-]?[0-9]+(\\.[0-9]*)?"); boolean bienEcrit(String texte) { return pattern.matcher(texte).matches(); } 3. Recherches multiples. Le programme suivant extrait les liens contenus dans une page html (repr esent es par des balises comme <a href="http://www.luminy.univ-mrs.fr" ... >) :
c H. Garreta, 2000-2013

91

9.5

Expressions r eguli` eres

QUELQUES CLASSES UTILES

import java.io.*; import java.util.regex.*; public class TrouverURL { public static void main(String[] args) { String texte; try { File fichier = new File(args[0]); char[] tampon = new char[(int) fichier.length()]; Reader lecteur = new FileReader(fichier); lecteur.read(tampon); lecteur.close(); texte = new String(tampon); } catch (IOException e) { e.printStackTrace(); return; } String expReg = "<a[ \\t\\n]+href=\"[^\"]+\""; Pattern motif = Pattern.compile(expReg, Pattern.CASE_INSENSITIVE); Matcher recon = motif.matcher(texte); int pos = 0; while (recon.find(pos)) { String s = texte.substring(recon.start(), recon.end()); System.out.println(s); pos = recon.end(); } } } Ce programme ache des lignes de la forme <a href="MonSoft.html" <a href="Polys/PolyJava.html" ... <a href="http://www.luminy.univ-mrs.fr/" <a href="mailto:garreta@univmed.fr" On peut extraire des informations plus nes, en utilisant la notion de groupe de capture des expressions r eguli` eres. Voici les seules modications ` a faire dans le programme pr ec edent : public class TrouverURL { ... String expReg = "<a[ \\t\\n]+href=\"([^\"]+)\""; ... String s = texte.substring(recon.start(1), recon.end(1)); ... } Lachage est maintenant comme ceci (magique, nest-ce pas ?) : MonSoft.html Polys/PolyJava.html ... http://www.luminy.univ-mrs.fr/ mailto:garreta@univmed.fr 4. Remplacer toutes les occurrences. Le programme suivant remplace les occurrences du mot chat par le mot chien 71 . Appel e avec largument un chat, deux chats, trois chats dans mon jardin il ache donc la cha ne un chien, deux chiens, trois chiens dans mon jardin.
71. Utile, hein ?

92

c H. Garreta, 2000-2013

QUELQUES CLASSES UTILES

9.5

Expressions r eguli` eres

Notez que cest recon, lobjet Matcher, qui prend soin de recopier dans la cha ne sortie les caract` eres qui se trouvent entre les occurrences du motif cherch e: public static void main(String[] args) throws Exception { Pattern motif = Pattern.compile("chat"); Matcher recon = motif.matcher(args[0]); StringBuffer sortie = new StringBuffer(); while(recon.find()) recon.appendReplacement(sortie, "chien"); recon.appendTail(sortie); System.out.println(sortie.toString()); } Lexemple ci-dessus a et e r edig e comme cela pour illustrer les m ethodes appendReplacement et appendTail. On notera cependant que, sagissant de remplacer toutes les occurrences dun motif par une cha ne, il y a un moyen plus simple : public static void main(String[] args) throws Exception { Pattern motif = Pattern.compile("chat"); Matcher recon = motif.matcher(args[0]); String sortie = recon.replaceAll("chien"); System.out.println(sortie); }

c H. Garreta, 2000-2013

93

10

THREADS

10

Threads

L etude des threads est ` a sa place dans un cours sur la programmation parall` ele et sort largement du cadre de ce polycopi e. Nous nous limitons ici ` a donner quelques explications sur certaines notions basiques auxquelles on est confront e dans les applications les plus courantes, par exemple lorsquon programme des interfaces utilisateur graphiques. Un thread ou processus l eger (on dit aussi l dex ecution ) est lentit e constitu ee par un programme en cours dex ecution. Cela se mat erialise par un couple (code, donn ees ) : le code en cours dex ecution et les donn ees que ce code traite. Si on en parle ici cest que Java supporte lexistence simultan ee de plusieurs threads : ` a un instant donn e plusieurs programmes peuvent sex ecuter en m eme temps et en agissant sur les m emes donn ees. Ce que en m eme temps veut dire exactement d epend du mat eriel utilis e. Dans un syst` eme poss edant plusieurs processeurs il est possible que divers threads sex ecutent chacun sur un processeur distinct et on est alors en pr esence dun parall elisme vrai. Mais, plus couramment, les syst` emes ne b en ecient que dun ou deux processeurs et il faut se contenter dun parall elisme simul e : les divers threads existant ` a un instant donn e disposent du processeur ` a tour de r ole. Di erentes raisons peuvent faire quun thread qui est en train dutiliser le processeur le c` ede ` a un autre thread qui patiente pour lavoir : 1) le blocage du thread actif explicitement demand e par une commande plac ee dans le code, comme wait (attendre) ou sleep (dormir), 2) le blocage du thread actif par le fait quil entame une op eration dentr ee-sortie 72 , 3) le d eblocage dun thread ayant une priorit e sup erieure ` a celle du thread actif, 4) l epuisement dune tranche de temps allou ee au thread actif. Notez que les blocages des deux derniers cas ne d ecoulent pas dop erations ex ecut ees par le code qui se bloque ; ils sont donc tout ` a fait impr evisibles. Si tout thread cesse d etre actif d` es quun thread de priorit e sup erieure est pr et (cas 3, ci-dessus) on dit quon a aaire ` a un parall elisme pr eemptif. La machine Java proc` ede g en eralement ainsi. Le fonctionnement par attribution de tranches de temps (cas 4) nest pas mentionn e par les sp ecications de la machine Java. Celle-ci en b en ecie ou non, selon les caract eristiques du mat eriel sous-jacent.

10.1
10.1.1

Cr eation et cycle de vie dun thread


D eclaration, cr eation et lancement de threads

Il y a deux mani` eres, tr` es proches, de cr eer un thread : en d enissant et en instanciant une sous-classe de la classe Thread d enie ` a cet eet, dans laquelle au moins la m ethode void run() aura et e red enie, en appelant le constructeur de Thread avec pour argument un objet Runnable 73 Dans un cas comme dans lautre, le thread cr e e est rendu vivant lors de lappel de sa m ethode start(). Java met alors en place tout le n ecessaire pour g erer le nouveau thread, puis appelle sa m ethode run(). Au moment de son d emarrage, le thread nouvellement cr e e: a pour code la m ethode run(), a pour donn ees celles du thread dans lequel il vient d etre cr e e. Exemple. Le thread purement d emonstratif suivant est tr` es simple : dix fois il ache son nom et un entier croissant, puis sendort pour une p eriode comprise entre 0 et 1000 millisecondes : public class ThreadSimple extends Thread { public ThreadSimple(String nom) { super(nom); }
72. Cest en consid erant ce type de situations quon peut comprendre pourquoi le parall elisme fait gagner du temps m eme lorsquil est simul e : quand un thread se met en attente dune entr ee-sortie sur disque (op eration beaucoup plus lente que le travail en m emoire centrale) ou, pire, en attente dune frappe au clavier, dun ev enement r eseau, etc., le contr ole est c ed ea ` un thread non bloqu e ; ainsi, le processeur est moins souvent oisif. 73. Un objet Runnable c.-` a-d. impl ementant linterface java.lang.Runnable est tout simplement un objet poss edant une m ethode run().

94

c H. Garreta, 2000-2013

10

THREADS

10.1

Cr eation et cycle de vie dun thread

public void run() { for (int i = 0; i < 10; i++) { System.out.println(getName() + " " + i); try { sleep((long) (Math.random() * 1000)); } catch (InterruptedException e) { } } System.out.println(getName() + " termin e"); } } Note. La m ethode sleep doit toujours etre appel ee dans un bloc try...catch puisque cest par le lancement dune exception InterruptedException que le thread endormi est r eveill e lorsque le temps indiqu e est ecoul e. Il en est de m eme, et pour la m eme raison, de la m ethode wait. Voici un programme qui fait tourner en parall` ele deux exemplaires de ce thread : public class DemoDeuxThreads { public static void main (String[] args) { new ThreadSimple("Seychelles").start(); new ThreadSimple("Maurice").start(); } } Achage obtenu (cest un exemple ; lors dune autre ex ecution, limbrication des messages Seychelles ... parmi les messages Maurice ... peut etre di erente) : Seychelles 0 Seychelles 1 Maurice 0 Seychelles 2 Seychelles 3 Maurice 1 Maurice 2 ... Seychelles termin e Maurice 8 Maurice 9 Maurice termin e Deuxi` eme exemple (un peu pr ematur e, les interfaces graphiques ne sont etudi ees qu` a la section suivante). Nous souhaitons disposer dun cadre dont la barre de titre ache constamment lheure courante ` a la seconde pr` es. Il sura pour cela de cr eer, en m eme temps que le cadre, un deuxi` eme thread qui dort 74 la plupart du temps, se r eveillant chaque seconde pour mettre ` a jour le texte ach e dans la barre de titre : import java.text.DateFormat; import java.util.*; import javax.swing.*; public class CadreAvecHeure extends JFrame { private String titre; public CadreAvecHeure(String titre) { super(titre); this.titre = titre; new Thread(new Runnable() { public void run() { gererAffichageHeure(); } }).start(); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(600, 400); setVisible(true); }
74. Quand un thread dort il ne consomme aucune ressource syst` eme.

c H. Garreta, 2000-2013

95

10.2

Synchronisation

10

THREADS

private void gererAffichageHeure() { while (true) { try { Thread.sleep(1000); } catch(InterruptedException e) { } Date h = Calendar.getInstance().getTime(); String s = DateFormat.getTimeInstance().format(h); setTitle(titre + " " + s); } } public static void main(String[] args) { new CadreAvecHeure("Test"); } } 10.1.2 Terminaison dun thread

Lorsquun thread atteint la n de sa m ethode run(), il se termine normalement et lib` ere les ressources qui lui ont et e allou ees. Mais comment provoque-t-on la terminaison anticip ee 75 dun thread ? La classe Thread comporte une m ethode stop() dont le nom exprime bien la fonction. Mais elle est vigoureusement d esapprouv ee (deprecated ), car elle laisse dans un etat ind etermin e certains des objets qui d ependent du thread stopp e. La mani` ere propre et able de terminer un thread consiste ` a modier la valeur dune variable que le thread consulte r eguli` erement. Par exemple, voici la classe CadreAvecHeure montr ee pr ec edemment, compl et ee par une m ethode arreterLaPendule() qui stoppe le rafra chissement de lheure ach ee : public class CadreAvecHeure extends JFrame { String titre; boolean go; public CadreAvecHeure(String titre) { comme la version pr ec edente } private void gererAffichageHeure() { go = true; while (go) { try { Thread.sleep(1000); } catch(InterruptedException e) { } Date d = Calendar.getInstance().getTime(); String s = DateFormat.getTimeInstance().format(d); setTitle(titre + " " + s); } } public void arreterLaPendule() { go = false; } ... }

10.2

Synchronisation

Lorsquil d emarre, un thread travaille sur les donn ees du thread dans lequel il a et e cr e e. Par exemple, dans le programme CadreAvecHeure ci-dessus, le thread ls qui ex ecute la m ethode gererAffichageHeure acc` ede aux donn ees this (atteinte lors de lappel de setTitle) et go qui appartiennent aussi au thread p` ere qui la cr e e. Cela pose le probl` eme de lacc` es concurrent aux donn ees, source potentielle de blocages
75. On notera que si un thread se compose dune boucle innie, comme dans la m ethode gererAffichageHeure, sa terminaison ne peut etre quanticip ee : sans intervention ext erieure, cette m ethode ne se terminera jamais.

96

c H. Garreta, 2000-2013

10

THREADS

10.2

Synchronisation

et derreurs subtiles, un probl` eme d elicat quon r` egle souvent ` a laide de verrous prot egeant les sections critiques. 10.2.1 Sections critiques

Imaginons la situation suivante : nous devons parcourir une collection, membre dUneCertaineClasse, en eectuant une certaine action sur chacun de ses el ements. La collection est repr esent ee par un objet List, laction par un objet Action (une interface express ement d enie ` a cet eet). interface Action { void agir(Object obj); } public class UneCertaineClasse { List liste; ... void parcourir(Action action) { Iterator iter = liste.iterator(); while (iter.hasNext()) action.agir(iter.next()); } ... } Sil ny a pas plusieurs threads pouvant acc eder ` a la liste, la m ethode pr ec edente est correcte. Mais sil peut arriver que, pendant quun thread parcourt la liste, un autre thread la modie en ajoutant ou en enlevant des el ements, alors le parcours pr ec edent a des chances de devenir incoh erent. Une premi` ere mani` ere de r esoudre ce probl` eme consiste ` a rendre synchronis ee la m ethode parcourir : public class UneCertaineClasse { List liste; ... synchronized void parcourir(Action action) { Iterator iter = liste.iterator(); while (iter.hasNext()) action.agir(iter.next()); } ... } Leet du qualieur synchronized plac e devant la m ethode parcourir est le suivant : lors dun appel de cette m ethode, de la forme 76 unObjet.parcourir(uneAction); un verrou sera pos e sur unObjet de sorte que tout autre thread qui tentera une op eration synchronis ee sur ce m eme objet (en appelant une autre m ethode synchronized de cette m eme classe) sera bloqu e jusqu` a ce que ce verrou soit enlev e. Cela r` egle le probl` eme de lacc` es concurrent ` a la liste, mais peut- etre pas de mani` ere optimale. En eet, si le traitement que repr esente la m ethode agir est long et complexe, alors la liste risque de se trouver verrouill e pendant une longue p eriode et ralentir lensemble du programme. Do` u une solution bien plus l eg` ere : etablir une section critique (i.e. prot eg ee par un verrou) dans laquelle on ne fait que cloner la liste puis, le verrou etant lev e, eectuer le parcours du clone, lequel ne craint pas les modications que dautres threads pourraient faire sur la liste originale : synchronized static void parcourir(List liste, Action action) { List copie = new LinkedList(); synchronized(liste) { Iterator iter = liste.iterator(); while (iter.hasNext()) copie.add(iter.next()); }
76. Un appel de la forme parcourir(uneAction) nest pas di erent, car il equivaut ` a this.parcourir(uneAction) .

c H. Garreta, 2000-2013

97

10.2

Synchronisation

10

THREADS

Iterator iter = copie.iterator(); while (iter.hasNext()) action.agir(iter.next()); } 10.2.2 M ethodes synchronis ees

Pour terminer cette pr esentation des threads voici un grand classique de la programmation parall` ele : une impl ementation du mod` ele dit des producteurs et consommateurs . Consid erons la situation suivante : un certain nombre de fois par exemple 10 chaque producteur fabrique un produit (num erot e), le d epose dans un entrep ot qui ne peut en contenir quun, puis dort un temps variable : public class Producteur extends Thread { private Entrepot entrepot; private String nom; public Producteur(Entrepot entrepot, String nom) { this.entrepot = entrepot; this.nom = nom; } public void run() { for (int i = 0; i < 10; i++) { entrepot.deposer(i); System.out.println("Le producteur " + this.nom + " produit " + i); try { sleep((int) (Math.random() * 100)); } catch (InterruptedException e) { } } } } Un certain nombre de fois par exemple 10 encore chaque consommateur prend le produit qui se trouve dans lentrep ot et le consomme : public class Consommateur extends Thread { private Entrepot entrepot; private String nom; public Consommateur(Entrepot entrepot, String nom) { this.entrepot = entrepot; this.nom = nom; } public void run() { int valeur = 0; for (int i = 0; i < 10; i++) { valeur = entrepot.prendre(); System.out.println("Le consommateur " + this.nom + " consomme " + valeur); } } } Ce qui est remarquable dans ce syst` eme cest que les producteurs et les consommateurs ne se connaissent pas et ne prennent aucune mesure pour pr evenir les conits. Or, lorsque lentrep ot est vide les consommateurs ne peuvent pas consommer et lorsquil est plein les producteurs ne peuvent pas produire. Cest lentrep ot qui g` ere ces conits. En revanche, lentrep ot est ind ependant du nombre de producteurs et de consommateurs qui traitent avec lui : public class Entrepot { private int contenu; private boolean disponible = false;

98

c H. Garreta, 2000-2013

10

THREADS

10.2

Synchronisation

public synchronized int prendre() { while (disponible == false) { try { wait(); } catch (InterruptedException e) { } } disponible = false; notifyAll(); return contenu; } public synchronized void deposer(int valeur) { while (disponible == true) { try { wait(); } catch (InterruptedException e) { } } contenu = valeur; disponible = true; notifyAll(); } } Ne vous y trompez pas : le fonctionnement de lentrep ot est assez savant. Les m ethodes prendre et deposer etant synchronized, un seul thread peut sy trouver ` a un instant donn e. Lorsquun consommateur appelle la m ethode prendre si un produit est disponible (i.e. disponible == true) alors disponible devient false et une notication est envoy ee ` a tous les threads qui sont en attente dune notication sur cet entrep ot ; en m eme temps, le consommateur obtient le produit, sil ny a pas de produit disponible (i.e. disponible == false) alors le thread appelle wait et se met donc en attente dune notication sur cet entrep ot. Lappel de notifyAll d ebloque tous les threads en attente. Si parmi eux il y a des producteurs, au plus un dentre eux trouve disponible == false et peut donc produire, tous les autres (producteurs et consommateurs) se rebloquent (` a cause du while) et attendent une nouvelle notication. Le fonctionnement de lentrep ot vu du c ot e de la m ethode deposer est rigoureusement sym etrique du pr ec edent. Voici un programme principal qui lance deux de ces threads : public class Essai { public static void main(String[] args) { Entrepot entrepot = new Entrepot(); Producteur producteur = new Producteur(entrepot, "A"); Consommateur consommateur = new Consommateur(entrepot, "B"); producteur.start(); consommateur.start(); } } Achage obtenu : Le producteur A Le consommateur Le producteur A Le consommateur etc. depose 0 B obtient 0 depose 1 B obtient 1

c H. Garreta, 2000-2013

99

11

INTERFACES GRAPHIQUES

11

Interfaces graphiques

Plus encore que pour les sections pr ec edentes, il faut rappeler que ces notes ne cherchent pas ` a etre un manuel de r ef erence, m eme pas succinct. Quels que soient les langages et les syst` emes utilis es, les biblioth` eques pour r ealiser des interfaces graphiques sont toujours extr emement copieuses. Celles de Java ne font pas exception ; nous navons pas la place ici pour expliquer les tr` es nombreuses classes et m ethodes qui les constituent. Nous nous contenterons donc dexpliquer les principes de fonctionnement des el ements dAWT et de Swing les plus importants et den montrer le mode demploi ` a travers des exemples de taille raisonnable. Outre un certain nombre de livres plus ou moins exhaustifs, dont louvrage (en fran cais, ` a part le titre) : David Flanagan Java Foundation Classes in a Nutshell OReilly, 2000 deux r ef erences absolument indispensables pour programmer des interfaces graphiques en Java sont les deux hypertextes d ej` a cit es : la documentation en ligne de lAPI Java : http://java.sun.com/javase/6/docs/api/, notamment tout ce qui concerne les paquets dont les noms commencent par java.awt et javax.swing, le tutoriel en ligne : http://java.sun.com/tutorial/, sp ecialement sa section Creating a GUI with JFC/Swing.

11.1

JFC = AWT + Swing

Une caract eristique remarquable du langage Java est de permettre l ecriture de programmes portables avec des interfaces-utilisateur graphiques, alors que partout ailleurs de telles interfaces sont r ealis ees au moyen de biblioth` eques s epar ees du langage et tr` es d ependantes du syst` emes dexploitation sur lequel lapplication doit tourner, ou du moins de la couche graphique employ ee. La premi` ere biblioth` eque pour r ealiser des interfaces-utilisateur graphiques 77 en Java a et e AWT, acronyme de Abstract Windowing Toolkit. Fondamentalement, lensemble des composants de AWT est d eni comme la partie commune des ensembles des composants graphiques existant sur les di erents syst` emes sur lesquels la machine Java tourne. Ainsi, chaque composant dAWT est impl ement e par un composant homologue (peer ) appartenant au syst` eme h ote, qui en assure le fonctionnement. AWT est une biblioth` eque graphique originale et pratique, qui a beaucoup contribu e au succ` es de Java, mais elle a deux inconv enients : puisque ses composants sont cens es exister sur tous les environnements vis es, leur nombre est forc ement r eduit ; dautre part, m eme r eput es identiques, des composants appartenant a ` des syst` emes di erents pr esentent malgr e tout des di erences de fonctionnement qui nissent par limiter la portabilit e des programmes qui les utilisent. Cest la raison pour laquelle AWT a et e compl et ee par une biblioth` eque plus puissante, Swing. Apparue comme une extension (c.-` a-d. une biblioth` eque optionnelle) dans danciennes versions de Java, elle appartient a la biblioth` ` eque standard depuis lapparition de Java 2 . En Swing, un petit nombre de composants de haut niveau (les cadres et les bo tes de dialogue ) sont appari es ` a des composants homologues de lenvironnement graphique sous-jacent, mais tous les autres composants qui, par d enition, nexistent quinclus dans un des pr ec edents sont ecrits en pur Java 78 et donc ind ependants du syst` eme h ote. Au nal, Swing va plus loin que AWT mais ne la remplace pas ; au contraire, les principes de base et un grand nombre d el ements de Swing sont ceux de AWT. Ensemble, AWT et Swing constituent la biblioth` eque ociellement nomm ee JFC (pour Java Foundation Classes 79 ). Lobjet de la description qui va suivre est Swing mais, comme on vient de le dire, cela ne nous dispensera pas dexpliquer beaucoup de concepts de AWT qui jouent un r ole important dans Swing, comme le syst` eme des ev enements (EventListener ), les gestionnaires de disposition (LayoutManager ), etc. Les classes de AWT constituent le paquet java.awt et un ensemble de paquets dont les noms commencent par java.awt : java.awt.event, java.awt.font, java.awt.image, etc. Les classes de Swing forment le paquet javax.swing et un ensemble de paquets dont les noms commencent par javax.swing : javax.swing.border, javax.swing.filechooser, javax.swing.tree, etc.
77. Pour nommer les interfaces-utilisateur graphiques vous trouverez souvent lacronyme GUI, pour Graphics User Interface. 78. La documentation ocielle exprime cela en disant que les composants de AWT, chacun appari e avec un composant du syst` eme sous-jacent, sont lourds , tandis que ceux de Swing, ecrits en pur Java, sont l egers . Ah, la belle langue technicommerciale... ! 79. JFC est une sorte de citation de la c el` ebre MFC ou Microsoft Foundation Classes, une biblioth` eque de classes C++ de chez Microsoft pour programmer les interfaces-utilisateur graphiques des applications destin ees ` a Windows.

100

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.2

Le haut de la hi erarchie

11.2

Le haut de la hi erarchie

Commen cons par donner quelques indications sur la mani` ere dont le travail se partage entre les classes qui constituent le haut de la hi erarchie dh eritage, cest-` a-dire les classes dont toutes les autres h eritent. Cette section 11.2 est enti` erement culturelle (elle ne contient pas dinformations techniques pr ecises), mais il vaut mieux avoir compris les concepts quelle expose avant de commencer ` a utiliser les composants graphiques. Composants (Component) La classe java.awt.Component est le sommet de la hi erarchie qui nous int eresse ici, cest-` a-dire la superclasse de toutes les classes qui repr esentent des composants graphiques, aussi bien AWT que Swing. Le comportement dun objet Component est tr` es riche, mais si on se limite aux fonctionnalit es les plus repr esentatives du r ole dun composant il faut mentionner : Se dessiner. Puisquun composant est un objet graphique, la plus pr evisible de ses m ethodes est celle qui en produit lexposition sur un ecran ou un autre organe dachage. Cette m ethode se nomme paint et elle est toute pr ete pour les composants pr ed enis, qui prennent soin de leur apparence graphique, mais on doit la red enir lorsquon cr ee des composants au dessin sp ecique. Comme on le verra, cette m ethode obligatoire nest jamais appel ee par les programmes ; au lieu de cela, cest la machine Java qui lappelle, chaque fois que lapparence graphique dun composant a et e endommag ee et doit etre r epar ee. Davantage dinformations au sujet de la m ethode paint et des op erations graphiques sont donn ees dans la section 11.6. Obtenir la taille et la position du composant. Une autre propri et e fondamentale de tout composant est que, une fois dessin e, il occupe un rectangle 80 sur l ecran ou lorgane dachage. Des m ethodes nomm ees getBounds, getSize, getLocation, etc., permettent dobtenir les coordonn ees de ce rectangle. D enir la taille et la position du composant. On pourrait penser que puisquil y a des m ethodes pour obtenir la taille et la position dun composant, il y en a egalement pour xer ces param` etres. Ces m ethodes existent (elles se nomment setSize, setMinimumSize, setMaximumSize, setPreferredSize, etc.) mais la question est plus compliqu ee quon ne pourrait le penser dabord car, sauf exception, la taille et la position dun composant d ecoulent dune n egociation permanente avec le gestionnaire de disposition (LayoutManager) du conteneur dans lequel le composant a et e plac e. Des explications sur les gestionnaires de disposition sont donn ees ` a la section 11.7 D enir et obtenir les propri et es graphiques. Puisque le propre dun composant est d etre dessin e il est normal quil comporte tout un ensemble de m ethodes pour d enir ou consulter ses propri et es graphiques, comme la couleur du fond (setBackground, getBackground), la couleur de ce qui est dessin e par-dessus (setForeground, getForeground), la police courante (setFont, getFont), etc. Les propri et es graphiques dun composant d enissent les valeurs initiales du contexte graphique (objet Graphics) utilis e par toute op erations de peinture (i.e. lappel par la machine Java de la m ethode paint). Les contextes graphiques et la m ethode paint sont expliqu es ` a la section 11.6. source d Etre ev enements. Puisquun composant est visible sur un ecran, il est naturellement pr edestin e a ` etre la cible dactions faites par lutilisateur ` a laide de la souris, du clavier ou de tout autre organe de saisie disponible. Lorsquune telle action se produit, Java cr ee un ev enement , un objet d ecrivant le type et les circonstances de laction produite ; on dit que le composant sur lequel laction sest produite est la source de l ev enement. Java notie alors cet ev enement ` a un ou plusieurs objets, appel es les auditeurs de l ev enement, qui sont cens es d eclencher la r eaction requise. Ce m ecanisme se manifeste au programmeur ` a travers des m ethodes nomm ees addXxx Listener (la partie Xxx d epend de l ev enement en question), qui permettent dattacher des auditeurs des divers types d ev enements aux objets qui peuvent en etre des sources : addMouseListener, addActionListener, etc. La question des ev enements et de leurs auditeurs est reprise en d etail ` a la section 11.5. Conteneurs (Container) La classe java.awt.Container est une sous-classe de java.awt.Component. Un conteneur est un composant qui peut en contenir dautres. Cela se traduit par deux m ethodes fondamentales : Ajouter un composant. Cest la m ethode add, sous la forme leConteneur .add(unComposant ) qui eectue de tels ajouts. Selon le gestionnaire de disposition en vigueur, elle peut requ erir dautres arguments.
80. On consid` ere presque toujours quun composant occupe un rectangle, m eme lorsquil ne semble pas rectangulaire.

c H. Garreta, 2000-2013

101

11.2

Le haut de la hi erarchie

11

INTERFACES GRAPHIQUES

Associer au conteneur un gestionnaire de disposition. Un gestionnaire de disposition, ou layout manager, est un objet (invisible) qui conna t le conteneur et la liste de ses composants et qui commande la taille et la position de ces derniers, cela aussi bien lors de lachage initial du conteneur, au moment de sa cr eation que, par la suite, chaque fois que la taille ou la forme du conteneur sont modi ees. Des explications sur les gestionnaires de disposition sont donn ees ` a la section 11.7. Fen etres (Window) La classe java.awt.Window est une sous-classe de java.awt.Container. La caract eristique dune fen etre est la possibilit e d etre visible sans n ecessiter d etre incluse dans un autre composant, contrairement ` a tous les composants qui ne sont pas des fen etres. La classe Window apporte donc la machinerie n ecessaire pour g erer lexistence dun composant sur lorgane dachage, ce qui demande, parmi dautres choses, de g erer la coexistence avec les autres fen etres dont beaucoup nont pas de lien avec lapplication en cours, ni m eme avec Java qui sont visibles sur lorgane dachage en m eme temps. Cette machinerie est mise en route ` a travers des m ethodes comme setVisible (ou show) et pack, que nous expliquerons plus en d etail ` a la section 11.4. Dune certaine mani` ere, les fen etres sont le si` ege de la vie des interfaces graphiques. Lorsquune fen etre est rendue visible, un nouveau thread est cr e e dans lequel sex ecute le programme qui d etecte les actions de lutilisateur sur la fen etre et sur chacun des composants quelle contient. Cela permet ` a la fen etre d etre r eactive m eme lorsque lapplication est occup ee ` a dautres t aches. Les diverses fen etres appartenant ` a une m eme application et existant ` a un instant donn e forment une arborescence : sauf le cadre de lapplication, chaque fen etre en r ef erence une autre, sa propri etaire ; ensemble, les fen etres constituent donc un arbre ayant pour racine le cadre de lapplication. Cela assure, par exemple, que la destruction du cadre principal entra nera bien la destruction de toutes les fen etres cr e ees par lapplication. Malgr e limportance de la classe Window il est rare quelle soit explicitement mentionn ee dans les applications courantes : les fonctionnalit es de cette classe sont presque toujours exploit ees ` a travers les sous-classes Frame et Dialog. Cadres et bo tes de dialogue (Frame, Dialog) Les classes java.awt.Frame (cadre) et java.awt.Dialog (bo te de dialogue) sont des sous-classes de Window. Les instances de ces deux classes sont des objets bien connus de quiconque a vu on ordinateur (en marche), car de nos jours on les rencontre dans les interfaces graphiques de toutes les applications. Un cadre est une fen etre munie dun bord, un bandeau de titre et, eventuellement, une barre de menus. Sur un syst` eme moderne chaque application ordinaire 81 a un cadre et la plupart des applications nen ont quun, si bien que lapplication et son cadre nissent par se confondre dans lesprit de lutilisateur ; ce nest pas f acheux, cest m eme un eet recherch e. Du point de vue de lutilisateur, le cadre dune application remplit au moins les trois fonctions suivantes : le cadre est loutil standard pour modier la taille et la forme de linterface, le cadre porte la barre des menus de lapplication, la fermeture du cadre produit la terminaison de lapplication. Du point de vue du programmeur, un cadre est la seule fen etre qui na pas besoin de poss eder une fen etre propri etaire. Il en d ecoule que le point de d epart dune interface graphique est toujours un cadre, et que tout composant est rattach e` a un cadre 82 : un composant qui nest pas une fen etre (Window) doit etre inclus dans un conteneur, un composant qui est une fen etre mais pas un cadre doit r ef erencer une autre fen etre, sa propri etaire. Les bo tes de dialogue sont elles aussi des fen etres munies dun bord et dune barre de titre mais, contrairement aux cadres, elles sont par nature nombreuses, diversi ees et eph em` eres. Les bo tes de dialogue sont loutil standard pour acher un message, poser une question ou demander des informations. Leur apparition est command ee par le programme, au moment requis, et elles permettent a lutilisateur de lire le message ou la question pos ` ee et, le cas ech eant, de faire les actions demand ees (cocher des cases, remplir des champs de texte, faire des choix dans des listes, etc.) ; il y a toujours un ou plusieurs
81. Par application ordinaire nous entendons une application visible ` a l ecran qui interagit avec lutilisateur. Cela exclut les applications invisibles, les services , les d emons , etc. 82. En particulier, la destruction dun cadre produit celle de tous les composants qui lui sont rattach es ; cela r esout les probl` emes de fen etres orphelines survivant ` a la terminaison de lapplication qui les a cr e ees, de bouts de composant oubli es et, plus g en eralement, de certains types de fuites de m emoire qui ont empoisonn e les premi` eres biblioth` eques graphiques.

102

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.3

Le point de d epart : JFrame et une application minimale.

boutons ( OK , Oui , Non , Open , etc.) dont la pression produit la disparition de la bo te de dialogue et, sil y a lieu, lacquisition par le programme des informations que lutilisateur a donn ees en agissant sur la bo te. Les bo tes de dialogue peuvent etre modales et non modales. Aussi longtemps quelle est visible, une bo te modale bloque (cest-` a-dire rend insensibles aux actions de lutilisateur) toutes les autres fen etres de lapplication, sauf celles dont la bo te en question est propri etaire, directement ou indirectement. Les bo tes non modales nont pas cet eet bloquant : une bo te de dialogue non modale et les autres fen etres de lapplication vivent en parall` ele, ce qui peut etre une cause de trouble de lutilisateur. Les bo tes de dialogue sont tr` es majoritairement modales.

Le cas des composants de Swing Swing est venu apr` es AWT et, quand il est arriv e, tous les noms int eressants etaient d ej` a pris : Component, Frame, Dialog, Button, Panel, etc. Plut ot que dinventer des noms enti` erement nouveaux, forc ement peu signicatifs, les concepteurs de Swing ont pr ef er e nommer les classes de Swing par les m emes noms que AWT, avec un signe distinctif constant, un J en d ebut du nom : JComponent, JFrame, JDialog, JButton, JPanel, etc. Attention, loubli de ce J initial change le sens de ce quon ecrit, mais dune mani` ere que le compilateur ne peut pas toujours signaler comme une erreur ; cela introduit des dysfonctionnements plus ou moins importants dans les programmes. Les sections pr ec edentes traitant des classes java.awt.Component, java.awt.Container, java.awt.Window, java.awt.Frame, java.awt.Dialog, etc. on pourrait penser quelles ne concernent pas Swing. Cest tout le contraire, car toutes les classes des composants de Swing sont sous-classes dune ou plusieurs de celles-l` a: javax.swing.JComponent est (pour des raisons techniques) sous-classe de java.awt.Container, donc de java.awt.Component, et la majorit e des composants de Swing sont sous-classes de java.awt.JComponent ; javax.swing.JFrame et javax.swing.JDialog sont sous-classes de java.awt.Frame et java.awt.Dialog respectivement. Enn, nos avons d ej` a dit que certaines des fonctions les plus fondamentales de Swing sont assur ees par des el ements de AWT qui nont pas et e etendus lors de la conception de Swing : les ev enements, les gestionnaires de disposition, etc.

11.3

Le point de d epart : JFrame et une application minimale.

Venons-en ` a des choses plus pratiques. Pour commencer, voici une application parmi les plus r eduites quon puisse ecrire : import java.awt.Color; import javax.swing.*; public class Bonjour { public static void main(String[] args) { JFrame cadre = new JFrame("Respect des traditions"); JLabel etiquette = new JLabel("Bonjour ` a tous!", JLabel.CENTER); cadre.getContentPane().add(etiquette); cadre.getContentPane().setBackground(Color.WHITE); cadre.setSize(250, 100); cadre.setVisible(true); } } Lex ecution de ce programme ache le cadre montr e` a la gure 9. Il est extr emement simple, mais il est vivant : lutilisateur peut en changer la taille et la position, le maximiser ou liconier, le faire passer devant ou derri` ere une autre fen etre, etc. Attention. Contrairement aux apparences, si comme ici le programmeur na pas pris les dispositions utiles, cliquer sur la case de fermeture (le bouton avec une croix ` a lextr eme droite du bandeau de titre) fera dispara tre le cadre mais ne terminera pas lapplication, qui continuera ` a tourner, et ` a consommer des ressources, alors quelle naura plus aucun el ement visible !
c H. Garreta, 2000-2013

103

11.3

Le point de d epart : JFrame et une application minimale.

11

INTERFACES GRAPHIQUES

Figure 9 Une version Swing de lincontournable PRINT "HELLO"

En attendant une meilleure id ee 83 on peut evacuer ce probl` eme aga cant en ajoutant, apr` es la cr eation du cadre, linstruction cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Notez que, contrairement ` a ce quon aurait pu penser (et contrairement ` a ce qui se passe pour les Frame de AWT), un JFrame ne contient pas directement les composants quon souhaite voir dans le cadre. Un JFrame est un objet complexe dont un el ement, le panneau de contenu (content pane ) est le conteneur auquel il faut ajouter des composants. Sur la gure 9, le panneau de contenu est le rectangle blanc contenant le texte Bonjour ` a tous ! . On acc` ede au panneau de contenu dun objet JFrame par lexpression getContentPane() 84 . En r ealit e, le programme pr ec edent nest pas tout ` a fait minimal. Si on se contentait dun cadre vide on pourrait faire encore plus simple en supprimant les trois lignes ` a partir de JLabel etiquette = ... . Mais les trois instructions restant alors sont obligatoires : appel de new JFrame(...) pour cr eer lobjet JFrame. Si on etait, comme cest souvent le cas, en train de d enir une sous-classe de JFrame, lappel du constructeur de JFrame serait cach e dans une instruction super(...) implicite ou explicite, appel de setSize(...) pour donner une taille au cadre, sinon il sera r eduit ` a quelques pixels. A la place de setSize(...) on peut appeler la m ethode pack(), qui donne au cadre une taille juste susante pour contenir les composantes qui lui sont ajout es, mais il faut alors que ces composants aient une taille minimum signicative ; de plus, il faut appeler pack apr` es avoir ajout e ces composants, appel de setVisible() pour faire appara tre le cadre parmi les autres el ements graphiques visibles ` a l ecran et pour initier le thread charg e de d etecter et traiter les actions de lutilisateur sur le cadre. En pratique les cadres des applications sont destin es ` a etre fortement personnalis es, en recevant des composants divers et nombreux. Cest pourquoi il est plus commode de d enir une sous-classe plut ot quune instance de JFrame. Voici une nouvelle version du programme pr ec edent, plus en accord avec ce qui se fait habituellement : import java.awt.Color; import javax.swing.*; public class Bonjour extends JFrame { public Bonjour() { super("Respect des traditions"); setDefaultCloseOperation(EXIT_ON_CLOSE); JLabel etiquette = new JLabel("Bonjour ` a tous!", JLabel.CENTER); getContentPane().add(etiquette); getContentPane().setBackground(Color.WHITE); setSize(250, 100); setVisible(true); } public static void main(String[] args) { JFrame cadre = new Bonjour(); } }
83. Une meilleure id ee serait un de ces dialogues qui sinstaurent dans beaucoup dapplications lorsque lutilisateur manifeste des envies de d epart, genre Attention, votre travail nest pas enregistr e, vous voulez vraiment quitter lapplication ? . 84. Cette complication dans lajout des composants aux cadres de Swing a disparu dans la version 5 du JDK, car la m ethode add de JFrame y a et e surcharg ee an quon puisse ecrire unCadre .add(unComposant ).

104

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.4

Le thread de gestion des ev enements

Note. Puisquelle nest plus mentionn ee par la suite, la variable locale cadre est tout ` a fait superue. La m ethode pr ec edente peut aussi bien s ecrire : public static void main(String[] args) { new Bonjour(); }

11.4

Le thread de gestion des ev enements

On peut etre surpris par le programme pr ec edent : le thread 85 principal de lapplication celui qui se cr ee quand on lance le programme, et dont la t ache est dappeler la m ethode main ex ecute une unique instruction, la cr eation dune instance de Bonjour, puis se termine. Lex ecution de ce programme ne devrait donc durer quun instant. Pourtant, lexp erience montre quune interface graphique est mise en place et reste apr` es la terminaison du thread principal. Cest donc quun deuxi` eme thread a et e cr e e et se charge de faire vivre linterface graphique, ce qui veut dire d etecter les actions de lutilisateur, notamment ` a laide de la souris, et r eagir en cons equence, par exemple en modiant laspect de linterface. Tant que ce deuxi` eme thread ne sera pas termin e, linterface graphique existera. Ce thread est appel e thread de traitement des ev enements (event-dispatching thread). Il faut surtout savoir deux choses ` a son sujet : ` a quel moment il est cr e e et quil est le seul habilit e` a modier linterface graphique. ation. Le thread de traitement des Cre ev enements est cr e e lorsque linterface graphique est r ealis ee, cest-` a-dire eectivement ach ee ou pr ete ` a l etre : un composant de haut niveau (JFrame, JDialog ou JApplet) est r ealis e lors de lappel dune de ses m ethodes setVisible(true), show() ou pack(), la r ealisation dun composant de haut niveau produit la r ealisation de tous les composants quil contient a ce moment-l` ` a, lajout dun composant ` a un conteneur d ej` a r ealis e entra ne la r ealisation du composant ajout e. `s concurrents a ` linterface. Le thread de traitement des Acce ev enements est le seul habilit e` a modier linterface. Imaginez une application dans laquelle le thread principal ne se termine pas imm ediatement apr` es avoir r ealis e le cadre de lapplication ; ce serait une mauvaise id ee que de faire que ce thread, ou un autre cr e e par la suite, ajoute ou modie ult erieurement des composants de linterface car plusieurs thread feraient alors des acc` es concurrents aux m emes objets. Il pourrait en r esulter diverses sortes de situations derreur et de blocage. La r` egle, appel ee r` egle du thread unique , est la suivante : Lorsquun composant Swing a et e r ealis e, tout code qui peut aecter l etat de ce composant ou en d ependre doit etre ex ecut e dans le thread de traitement des ev enements. Quun code soit ex ecut e dans le thread de traitement des ev enements signie en pratique quil est ecrit dans un gestionnaire d ev enements (i.e. une m ethode dun EventListener, destin ee ` a etre appel ee par Java en r eaction ` a la survenue de l ev enement) ou dans une m ethode appel ee par un tel gestionnaire. Il y a des exceptions ` a cette r` egle, cest-` a-dire des op erations sur des composants de linterface qui peuvent etre appel ees sans danger depuis nimporte quel thread. Elles sont toujours signal ees dans la documentation par le texte This method is thread safe, although most Swing methods are not. Par exemple, les zones de texte JTextArea poss` edent des m ethodes setText(String t) et append(String t) permettant de remplacer ou dallonger le texte ach e dans la zone de texte. Ces op erations sont thread safe, car le contraire serait tr` es malcommode. Dautres op erations thread safe bien connues sont les m ethodes repaint(...), revalidate(...), etc. de la classe JComponent. Ces m ethodes sont cens ees mettre ` a jour lachage des composants, mais en r ealit e elles ne font que poster des requ etes dans la le dattente des ev enements (cest le thread de traitement des ev enements qui les en extraira). A retenir. Cons equence pratique de la r` egle du thread unique : lappel de setVisible(true) ou de show() doit etre la derni` ere instruction du processus de construction dun cadre ou dune bo te de dialogue.
85. Un thread (cf. 10, page 94), on dit aussi l dex ecution ou processus l eger, est lentit e constitu ee par un programme en cours dex ecution. Les el ements principaux de cette entit e sont le code qui sex ecute et les donn ees que ce code manipule. Le langage Java est multithread : le lancement dune application cr ee un thread principal, dont le code est d etermin e par la m ethode main, mais ce thread peut en cr eer un ou plusieurs autres, qui sex ecuteront en parall` ele (parall elisme vrai si votre machine comporte plusieurs processeurs, parall elisme simul e si elle nen comporte quun). On dit que les thread sont des processus l egers surtout pour indiquer quils partagent les donn ees : lorsquun thread est cr e e il acc` ede a ` toutes les variables du thread qui la cr e e.

c H. Garreta, 2000-2013

105

11.5

enements Ev

11

INTERFACES GRAPHIQUES

Sil y a un appel de pack() alors celui-ci doit se trouver imm ediatement avant 86 setVisible(true) ou show(). La plus petite application avec interface graphique revisit ee Respecter la r` egle du thread unique (ci-dessus) nest pas toujours commode, ni m eme possible. Il existe des composants complexes dont la mise en place requiert quon agisse sur eux apr` es quils ont et e r ealis es et rendus visibles, ce qui introduit la possibilit e dinter-blocages. Une mani` ere evidemment correcte de r esoudre en bloc tous ces probl` emes consiste ` a ex ecuter toutes les op erations concernant linterface graphique dans un seul thread, forc ement le thread de gestion des ev enements. Cest pourquoi l equipe de d eveloppement de Java promeut d esormais une nouvelle mani` ere de cr eer et lancer les interfaces graphiques. Le programme correct montr e ` a la section 11.3 etait, jusquen d ecembre 2003, la version canonique dune petite application avec interface graphique, mais la forme ocielle dun tel programme est d esormais la suivante : import java.awt.Color; import javax.swing.*; public class Bonjour { private static void creerEtMontrerInterface() { JFrame cadre = new JFrame("Respect des traditions"); JLabel etiquette = new JLabel("Bonjour ` a tous!", JLabel.CENTER); cadre.getContentPane().add(etiquette); cadre.getContentPane().setBackground(Color.WHITE); cadre.setSize(250, 100); cadre.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { creerEtMontrerInterface(); } }); } } Ce programme peut sembler obscur. Il se lit comme ceci : la m ethode SwingUtilities.invokeLater(obj ) prend pour argument un objet Runnable (cest-` a-dire un objet poss edant une m ethode run()) et elle produit lappel de obj .run() dans le thread de gestion des ev enements 87 . Nous obtenons un objet runnable en cr eant une instance dune classe anonyme d enie comme impl ementation de linterface Runnable et ayant une m ethode run() qui se r eduit ` a un appel dune m ethode creerEtMontrerInterface qui, d evidence, remplace ce qui etait pr ec edemment la m ethode main.

11.5

enements Ev

Puisquun composant est visible sur un ecran, il est naturellement pr edestin e` a devenir la cible dactions faites par lutilisateur ` a laide de la souris, du clavier ou de tout autre organe de saisie disponible. Au moment o` u elle est d etect ee par lordinateur, une action de lutilisateur provoque la cr eation par la machine Java dun ev enement , un objet quon peut imaginer comme un rapport d ecrivant la nature et ev enement les circonstances de cette action ; on dit que le composant qui en a et e la cible est la source 88 de l en question. Lorsquun ev enement est cr e e, le composant qui en est la source a la charge de notier ce fait ` a tous les objets qui ont et e enregistr e aupr` es de lui comme etant concern es par ce type d ev enements et souhaitant
86. En th eorie, la s equence pack(); show(); nest pas en accord avec la r` egle du thread unique, puisque lappel de show est un acc` es, dans le thread principal, ` a un composant d ej` a r ealis e par lappel de pack. En pratique cela passe, car il y a bien peu de chances quun troisi` eme thread fasse des acc` es aux composants dune interface qui na pas encore et e rendue visible. 87. Cela nous concerne peu ici, mais il faut savoir que la m ethode invokeLater(obj ) produit lappel de obj .run() uniquement apr` es que tous les ev enements en attente ont et e trait es (cest l` a laspect later de cette m ethode). 88. Attention, le mot est un peu trompeur : la vraie source de l ev enement est lutilisateur (ou sa main qui tient la souris), mais cela nint eresse notre programme qu` a partir du moment o` u laction est ressentie par la machine ; ` a ce moment, cest bien la cible de laction de lutilisateur qui devient le point dapparition, ou source, de l ev enement.

106

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

enements 11.5 Ev

donc etre pr evenus lorsquils se produiraient. Bien entendu, notier un ev enement cest appeler une certaine m ethode, sp ecique de l ev enement. Les objets qui demandent ` a recevoir les notications des ev enements dun certain type doivent donc poss eder les m ethodes correspondantes ; on garantit cela en imposant que ces objets soient des impl ementations dinterfaces ad hoc, nomm ees XxxListener , o` u Xxx caract erise le type d ev enement consid er e: MouseListener, WindowListener, ActionListener, etc. En r esum e : pour quun objet puisse recevoir les notications dune cat egorie Xxx d ev enements il faut que sa classe impl emente linterface XxxListener ; cet objet peut alors etre enregistr e aupr` es dune source d ev enements Xxx en tant quauditeur (listener ) des ev enements Xxx. Par cons equent, si un objet est source d ev enements Xxx alors il doit poss eder la m ethode addXxxListener 89 gr ace a ` laquelle dautres objets lui sont enregistr es en qualit e dauditeurs de ces ev enements. 11.5.1 Exemple : d etecter les clics de la souris.

Donnons-nous le probl` eme suivant : d etecter les clics de la souris au-dessus dun panneau et en acher les coordonn ees.

Figure 10 D etecter les clics La gure 10 montre notre application et l etat de la console do` u on la lanc ee, apr` es quon a cliqu e pr` es des quatre coins du panneau. Voici une premi` ere version de ce programme (des explications sont donn ees apr` es le listing) : import javax.swing.*; import java.awt.Color; import java.awt.event.*; public class CadreAvecPanneauSensible extends JFrame { CadreAvecPanneauSensible() { super("Un cadre sensible"); setDefaultCloseOperation(EXIT_ON_CLOSE); JPanel panneau = new JPanel(); panneau.setBackground(Color.WHITE); GuetteurSouris felix = new GuetteurSouris(); panneau.addMouseListener(felix); getContentPane().add(panneau); setSize(250, 150); setVisible(true); } public static void main(String[] args) { new CadreAvecPanneauSensible(); } }
89. On peut en d eduire un moyen de d ecouvrir lensemble des ev enements dont un composant peut etre la source : chercher, dans la documentation de sa classe, les m ethodes nomm ees addXxxListener.

c H. Garreta, 2000-2013

107

11.5

enements Ev

11

INTERFACES GRAPHIQUES

class GuetteurSouris implements MouseListener { public void mousePressed(MouseEvent e) { System.out.println("Clic en (" + e.getX() + ", " + e.getY() + ")"); } public void mouseReleased(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } } Le code pr ec edent met en evidence les trois el ements cl es dans tout processus dexploitation dactions de lutilisateur : les ev enements quil faut d etecter et traiter ; ici, il sagit des instances de la classe MouseEvent. Notez que le programme ne montre pas la cr eation de ces objets, pas plus que lappel des m ethodes pour les exploiter, cela est laaire de m ethodes (h erit ees de la classe Component) qui ne sont appel ees que par la machine Java ; la source de ces ev enements, une instance indirecte de la classe java.awt.Component. Ici, la source des ev enements est lobje JPanel qui est la valeur de la variable panneau ; le gestionnaire de ces ev enements, un auditeur d ument enregistr e aupr` es de la source. Ici, cet auditeur est une instance, nomm ee felix, de notre classe GuetteurSouris. On constate donc que lexpression panneau.addMouseListener(felix) joue un r ole central dans cette aaire : elle indique que panneau est consid er e ici comme une source d ev enements souris 90 et que ces ev enements, lorsquils surviennent, doivent etre noti es ` a lobjet felix. Les quatre m ethodes vides de la classe GuetteSouris peuvent surprendre. Il faut comprendre quelles d ecoulent de contraintes successives : dune part, pour pouvoir etre enregistr e comme auditeur d ev enements souris, un objet doit appartenir a une classe qui impl ` emente linterface MouseListener, cela est impos e par la d eclaration de la m ethode addMouseListener, dautre part, linterface MouseListener se compose de cinq m ethodes (abstraites), correspondant aux cinq ev enements quon peut d eclencher avec une souris. Note 1. Puisque la classe GuetteSouris nest utilis ee que dans des m ethodes de la classe CadreAvecPanneauSensible, on aurait pu d eclarer la premi` ere ` a lint erieur de la deuxi` eme. De cette mani` ere, GuetteSouris serait devenue un classe interne (cf. section 6.6) ` a la classe CadreAvecPanneauSensible. Note 2. Rien noblige ` a ce que le r ole dauditeur dune sorte d ev enements soit tenu par des objets dune classe sp eciquement d enie ` a cet eet. Nimporte quel objet peut tenir ce r ole y compris celui qui est la source des ev enements en question ` a la condition quon en ait fait une impl ementation de linterface XxxListener correspondante. Par exemple, voici une autre ecriture de notre exemple, dans laquelle cest le cadre qui exploite les ev enements souris : import javax.swing.*; import java.awt.Color; import java.awt.event.*; public class CadreAvecPanneauSensible extends JFrame implements MouseListener { CadreAvecPanneauSensible() { super("Un cadre sensible"); setDefaultCloseOperation(EXIT_ON_CLOSE); JPanel panneau = new JPanel(); panneau.setBackground(Color.WHITE); panneau.addMouseListener(this);
90. Entendons-nous bien : un JPanel est toujours une source d ev enements souris. Mais ces ev enements ne sont exploit es par lapplication que si un ou plusieurs auditeurs ont et e enregistr es.

108

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

enements 11.5 Ev

getContentPane().add(panneau); setSize(250, 150); setVisible(true); } public static void main(String[] args) { new CadreAvecPanneauSensible(); } public void mousePressed(MouseEvent e) { System.out.println("Clic en (" + e.getX() + ", " + e.getY() + ")"); } public } public } public } public } } void mouseReleased(MouseEvent e) { void mouseClicked(MouseEvent e) { void mouseEntered(MouseEvent e) { void mouseExited(MouseEvent e) {

11.5.2

Adaptateurs et classes anonymes

Adaptateurs. Quand on ecrit limpl ementation dune interface Xxx Listener il est regrettable de devoir ecrire toutes les m ethodes de linterface alors que seul un petit nombre d ev enements possibles, voire un seul, nous int eresse. Les adaptateurs sont des impl ementations toutes pr etes des interfaces dauditeurs d ev enements, enti` erement faites de m ethodes vides. Chaque interface 91 Xxx Listener poss` ede une classe Xxx Adapter correspondante. Pour ecrire le traitement des ev enements qui nous int eressent il sut alors de d enir une sous classe de ladaptateur concern e, dans laquelle seules les m ethodes pertinentes sont d enies. Par exemple, voici notre programme pr ec edent premi` ere version repris dans cet esprit : import javax.swing.*; import java.awt.Color; import java.awt.event.*; public class CadreAvecPanneauSensible extends JFrame { CadreAvecPanneauSensible() { super("Un cadre sensible"); setDefaultCloseOperation(EXIT_ON_CLOSE); JPanel panneau = new JPanel(); panneau.setBackground(Color.WHITE); GuetteurSouris felix = new GuetteurSouris(); panneau.addMouseListener(felix); getContentPane().add(panneau); setSize(250, 150); setVisible(true); } public static void main(String[] args) { new CadreAvecPanneauSensible(); } }

91. Sauf les interfaces constitu ees dune seule m ethode, comme ActionListener, pour lesquelles un adaptateur naurait aucun int er et.

c H. Garreta, 2000-2013

109

11.5

enements Ev

11

INTERFACES GRAPHIQUES

class GuetteurSouris extends MouseAdapter { public void mousePressed(MouseEvent e) { System.out.println("Clic en (" + e.getX() + ", " + e.getY() + ")"); } } Classes anonymes. On peut faire encore plus simple. Dans lexemple pr ec edent nous d enissons une sous-classe de MouseAdapter dans le but exclusif den cr eer une unique instance. Dans un tel cas de gure, Java permet quon d enisse la sous-classe dans la m eme expression qui cr ee linstance. La sous-classe est alors sans nom, mais cela na pas dimportance puisquon nenvisage pas de lui faire dautres instances. Cela s ecrit : import javax.swing.*; import java.awt.Color; import java.awt.event.*; public class CadreAvecPanneauSensible extends JFrame { CadreAvecPanneauSensible() { super("Un cadre sensible"); setDefaultCloseOperation(EXIT_ON_CLOSE); JPanel panneau = new JPanel(); panneau.setBackground(Color.WHITE); MouseListener felix = new MouseAdapter() { public void mousePressed(MouseEvent e) { System.out.println("Clic en (" + e.getX() + ", " + e.getY() + ")"); } }; panneau.addMouseListener(felix); getContentPane().add(panneau); setSize(250, 150); setVisible(true); } public static void main(String[] args) { new CadreAvecPanneauSensible(); } } Note. Si on ne craint pas les ecritures compactes on peut m eme se passer de la variable felix : ... panneau.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { System.out.println("Clic en (" + e.getX() + ", " + e.getY() + ")"); } }); ... 11.5.3 Principaux types d ev enements

Chaque type d ev enement correspond ` a une interface dauditeurs. Les principales (et les seules en AWT ) sont les suivantes : MouseListener Linterface MouseListener concerne les ev enements isol es 92 g en er es ` a laide de la souris. Il sagit d ev enements de bas niveau, cest-` a-dire des actions avec la souris sur des composants qui ne sont pas equip es pour traduire ces gestes el ementaires en informations de plus haut niveau, comme cest le cas pour les boutons, les menus, etc. Les m ethodes de cette interface sont :
92. Par ev enements isol es nous entendons les ev enements autres que les trains d ev enements que produisent les d eplacements de la souris, voyez Mouse motion events, plus loin.

110

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

enements 11.5 Ev

void mousePressed(MouseEvent e) Appel ee lorsquun bouton de la souris a et e press e, le pointeur se trouvant sur le composant dont on guette les ev enements. void mouseReleased(MouseEvent e) Appel ee lorsquun bouton de la souris a et e rel ach e, alors quil avait et e press e quand le pointeur se trouvait sur le composant dont on guette les ev enements. void mouseClicked(MouseEvent e) Appel ee lorsque la souris a et e cliqu ee (press ee puis rel ach ee au m eme endroit ), le curseur se trouvant sur le composant dont on guette les ev enements. De par sa d enition, cet ev enement est toujours pr ec ed e dun ev enement mouseReleased. La r eciproque nest pas vraie : un ev enement mouseReleased nest suivi dun ev enement mouseClicked que si la position de la souris na pas chang e depuis le dernier ev enement mousePressed. void mouseEntered(MouseEvent e) Appel ee lorsque le pointeur de la souris commence ` a survoler le composant dont on guette les ev enements. void mouseExited(MouseEvent e) Appel ee lorsque le pointeur de la souris cesse de survoler le composant dont on guette les ev enements. Largument de ces m ethodes est un objet MouseEvent. Les m ethodes les plus int eressantes dun tel objet sont : getX(), getY() qui renvoient les coordonn ees 93 du pointeur au moment o` u l ev enement a et e noti e, getButton() qui permet de savoir quel bouton a et e press e. MouseMotionListener Cette interface concerne les mouvements de la souris. Lorsquon fait bouger la souris sans appuyer sur un de ses boutons on dit quon la d eplace (move ), lorsquon la fait bouger tout en maintenant un bouton press e on dit quon la tra ne (drag ). Cette interface comporte donc deux m ethodes : void mouseMoved(MouseEvent e) Appel ee lorsque la souris change de position sans quaucun bouton ne soit press e. void mouseDragged(MouseEvent e) Appel ee lorsque la souris change de position avec un de ses boutons press e. Il faut etre plut ot sobre en impl ementant les m ethodes pr ec edentes, car elles ont ` a traiter des ev enements qui arrivent par trains. Selon les performances du syst` eme utilis e, un grand nombre dappels de ces m ethodes est g en er e pendant un seul d eplacement de la souris. Il faut que la r eponse soit courte pour ne pas introduire un asynchronisme d esagr eable. KeyListener Il se produit un ev enement clavier chaque fois quune touche est press ee ou rel ach ee. Tous les composants peuvent etre sources de tels ev enements, il sut quils aient le focus . Cette interface se compose de trois m ethodes : void keyPressed(KeyEvent e) Appel ee lorsquune touche a et e press ee. void keyReleased(KeyEvent e) Appel ee lorsquune touche a et e rel ach ee. void keyTyped(KeyEvent e) Appel ee lorsquun caract` ere a et e saisi au clavier. Les ev enements keyPressed et keyReleased sont de bas niveau. Chacun correspond ` a une touche unique, et fournit un code num erique (le code de touche virtuelle, ou VK code ). En particulier, keyPressed est le seul moyen de d etecter la pression dune touche ne produisant pas de caract` ere (comme Shift , Ctrl , etc.). L ev enement keyTyped, au contraire, est assez elabor e, puisquil est capable dagr eger plusieurs touches press ees ensemble pour former un unique caract` ere : A majuscule, Control-C, etc. Largument de ces m ethodes est un objet KeyEvent, dont les m ethodes les plus int eressantes sont : char getKeyChar() Renvoie le caract` ere associ e` a l ev enement clavier (compte tenu des eventuelles touches de modication) Dans le cas de keyPressed et keyReleased il peut nexister aucun caract` ere Unicode repr esentant la touche concern ee, la valeur KeyEvent.CHAR_UNDEFINED est alors renvoy ee. int getKeyCode() Dans le cas de keyPressed et keyReleased, renvoie le code de touche virtuelle correspondant ` a la touche press ee ou rel ach ee. Dans le cas de keyTyped, le r esultat est KeyEvent.VK_UNDEFINED. Sur beaucoup de syst` emes, si lutilisateur maintient une touche press ee, un ot d ev enements keyPressed est g en er e.
93. On notera que, dans le cas des ev enements MouseExited et, surtout, MouseReleased, ces coordonn ees peuvent etre n egatives.

c H. Garreta, 2000-2013

111

11.5

enements Ev

11

INTERFACES GRAPHIQUES

FocusListener Les ev enements qui nous int eressent ici concernent lacquisition ou la perte du focus par un composant. A tout moment, un seul composant a le focus ; par d enition, cest ` a lui que sont adress es les ev enements du clavier. G en eralement, un composant acquiert le focus lorsquil subit un clic de la souris ; le composant qui avait le focus ` a ce moment-l` a le perd. La pression successive de la touche tabulation fait egalement circuler le focus parmi les composants plac es sur un m eme conteneur. void focusGained(FocusEvent e) Appel ee lorsque le composant en question acquiert le focus (cest-` a-dire que les actions sur le clavier lui seront d esormais adress ees). void focusLost(FocusEvent e) Appel ee lorsque le composant perd le focus (un autre composant la pris).

ActionListener Cette interface concerne des actions (avec la souris ou le clavier) sur un composant qui les traduit en une commande de plus haut niveau, comme un choix dans une liste ou un menu, une pression sur un bouton, etc. Linterface se compose dune seule m ethode : void actionPerformed(ActionEvent e) Appel ee lorsquune action a et e faite (ce que action veut dire d epend du composant : presser un bouton, cocher ou d ecocher une case ` a cocher, faire un choix dans un menu, etc.). Largument de cette m ethode est un objet ActionEvent, muni de la m ethode String getActionCommand() Renvoie une cha ne qui identie laction en question. En r` egle g en erale, il sagit dune cha ne ecrite sur le composant sur lequel laction de lutilisateur sest eectu ee : le titre dun bouton press e ou dune case coch ee, le texte de l el ement de liste ou de litem de menu choisi, etc.

Figure 11 Trois boutons

Exemple : voici la d enition dune classe Panneau tr` es na ve qui est un conteneur portant trois boutons (voyez la gure 11) et, en m eme temps, lauditrice des actions dont ces boutons sont la source : import javax.swing.*; import java.awt.event.*; class TroisBoutons extends JPanel implements ActionListener { public TroisBoutons() { JButton bouton = new JButton("Oui"); bouton.addActionListener(this); add(bouton); bouton = new JButton("Non"); bouton.addActionListener(this); add(bouton); bouton = new JButton("Euh..."); bouton.addActionListener(this); add(bouton); }

112

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

enements 11.5 Ev

public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Oui")) System.out.println("Il a dit oui"); else if (e.getActionCommand().equals("Non")) System.out.println("Il a dit non"); else System.out.println("Il ne sait pas"); } public static void main(String[] args) { JFrame cadre = new JFrame("Boutons"); cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cadre.getContentPane().add(new TroisBoutons()); cadre.pack(); cadre.setVisible(true); } }

Voici une autre mani` ere d ecrire une classe fonctionnellement identique ` a la pr ec edente, en utilisant les r ef erences des boutons plut ot que leurs cha nes action command 94 : import javax.swing.*; import java.awt.event.*; class TroisBoutons extends JPanel implements ActionListener { JButton bOui, bNon; public TroisBoutons() { bOui = new JButton("Oui"); bOui.addActionListener(this); add(bOui); bNon = new JButton("Non"); bNon.addActionListener(this); add(bNon); JButton bouton = new JButton("Euh..."); bouton.addActionListener(this); add(bouton); } public void actionPerformed(ActionEvent e) { if (e.getSource() == bOui) System.out.println("Il dit Oui"); else if (e.getSource() == bNon) System.out.println("Il dit Non"); else System.out.println("Il ne sait pas"); } public static void main(String[] args) { JFrame cadre = new JFrame("Boutons"); cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cadre.getContentPane().add(new TroisBoutons()); cadre.pack(); cadre.setVisible(true); } }

94. Cette mani` ere de faire est plus ecace, puisquon remplace les comparaisons equals par des comparaisons == , mais cela oblige ` a d eclarer des collections de variables dinstance.

c H. Garreta, 2000-2013

113

11.5

enements Ev

11

INTERFACES GRAPHIQUES

ItemListener Il se produit un ev enement ditem lorsquun item est s electionn e ou d eselectionn e. Par item nous entendons ici un el ement dune liste d eroulante, dune liste de choix, une case ` a cocher, etc. Une seule m ethode dans cette interface : void itemStateChanged(ItemEvent e) Appel ee lorsquun item a et e s electionn e ou d eselectionn e. AdjustmentListener Cette interface concerne les actions faites sur des barres de d element. Une seule m ethode : void adjustmentValueChanged(AdjustmentEvent e) Appel ee lorsque le curseur de la barre de d element a et e d eplac e (quelle quen soit la raison : on a tir e le curseur, on a cliqu e sur une des ` eches de la barre ou bien on a cliqu e sur la barre en dehors du curseur). En g en eral, ` a la suite dun tel ev enement on interroge la barre de d element ` a laide de la m ethode getValue de la classe Scrollbar. Dans le cas o` u lon dispose de plusieurs barres de d element on peut utiliser la m ethode Object getSource() pour identier celle qui est la source de l ev enement. Ces ev enements ne sont pas dun usage aussi fr equent quon pourrait le penser car, dans la plupart des applications, les barres de d element des fen etres sont g er ees par la machinerie interne des objets JScrollPane. TextListener Les ev enements de cette interface notient les modications du texte en cours de saisie dans un champ ou une zone de texte. Une seule m ethode : void textValueChanged(TextEvent e) Appel ee lorsque le texte concern e a chang e. On notera que les champs de texte (JTextField et JPasswordField) produisent egalement un ev enement action lorsque lutilisateur presse la touche Entr ee , ce qui est souvent l ev enement r eellement guett e. WindowListener Les ev enements que cette interface concerne sont les actions sur une fen etre : ouverture et fermeture et, dans le cas dun cadre ou dun dialogue, les actions sur les el ements de la barre de titre. Ce qui donne les m ethodes : void windowClosing(WindowEvent e) Appel ee lorsque lutilisateur essaye de fermer la fen etre en agissant sur son menu syst` eme ou sa case de fermeture. Dans le cas du cadre principal dune application cest ici quon doit mettre l eventuel code de conrmation avant terminaison, voir lexemple ci-dessous. void windowActivated(WindowEvent e) Appel ee lorsque la fen etre est rendue active. void windowDeactivated(WindowEvent e) Appel ee lorsquune fen etre cesse d etre la fen etre active. void windowClosed(WindowEvent e) Appel ee lorsque la fen etre a et e ferm ee, suite ` a un appel de sa m ethode dispose. Ne pas confondre cet ev enement, qui na de sens que pour une fen etre lle (apr` es la fermeture du cadre principal il ny a plus dapplication) avec l ev enement windowClosing. void windowOpened(WindowEvent e) Appel ee lorsquune fen etre est rendue visible pour la premi` ere fois. void windowIconified(WindowEvent e) Appel ee lorsquune fen etre est minimis ee (iconi ee). void windowDeiconified(WindowEvent e) Appel ee lorsquune fen etre qui avait et e minimis ee (iconi ee) retrouve une taille normale. 11.5.4 Exemple : fermeture prudente du cadre principal

Voici une illustration classique de la mani` ere de d etecter et traiter les ev enements Window : demander ` lutilisateur une conrmation avant de fermer le cadre principal et mettre n ` a a lapplication (voyez la gure 12). Bien s ur, dans une vraie application, au lieu des quatre lignes ` a partir de JPanel panneau = new JPanel(); on verrait lajout au cadre de choses plus int eressantes quun simple panneau vide. Tr` es int eressant, cet exemple montre egalement lemploi des tr` es utiles bo tes de question (JOptionPane).

114

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.6

Peindre et repeindre

Figure 12 Conrmation avant fermeture

import javax.swing.*; import java.awt.event.*; import java.awt.*; public class CadreAvecSortieGardee extends JFrame { public CadreAvecSortieGardee(String titre) { super(titre); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { sortiePrudente(); } }); JPanel panneau = new JPanel(); panneau.setPreferredSize(new Dimension(200, 150)); panneau.setBackground(Color.WHITE); getContentPane().add(panneau); pack(); setVisible(true); } void sortiePrudente() { if (JOptionPane.showConfirmDialog(this, "Voulez-vous vraiment quitter ce programme?", "Attention!", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) System.exit(0); } public static void main(String[] args) { new CadreAvecSortieGardee("On sort pas comme on veut"); } }

11.6
11.6.1

Peindre et repeindre
La m ethode paint

Les composants graphiques doivent etre peints (sur l ecran) : une premi` ere fois lors de leur achage initial, ensuite chaque fois quils ont et e totalement ou partiellement modi es, eac es, agrandis, etc. Tout composant qui nest pas une fen etre est forc ement inclus dans un conteneur qui, sil nest pas luim eme une fen etre, doit ` a son tour etre inclus dans un autre conteneur, lui-m eme peut- etre inclus dans un troisi` eme, etc. Cette cha ne dinclusions se poursuit jusqu` a une fen etre, le seul conteneur qui nest pas oblig e d etre inclus dans un autre. Or, la gestion que fait la machine Java des fen etres (en comp etition avec les autres
c H. Garreta, 2000-2013

115

11.6

Peindre et repeindre

11

INTERFACES GRAPHIQUES

fen etres, Java ou non, visibles ` a l ecran) lui permet de d etecter des situations comme celle-ci : une fen etre qui etait totalement ou partiellement masqu ee par une autre, vient d etre d ecouverte et, par cons equent, tous ou certains des composants plac es dans cette fen etre doivent etre redessin es. La machine Java met alors dans une certaine le dattente de choses ` a faire une requ ete indiquant quil faut repeindre les composants qui se trouvent dans la partie endommag ee, quil faut restaurer 95 . Aussi longtemps que lapparence standard dun composant vous convient, vous navez pas ` a vous pr eoccuper de sa peinture : le composant prend soin de lui m eme. L` a o` u cette question devient int eressante cest lorsquon consid` ere des composants personnalis es , dont lapparence graphique souhait ee nest pas celle que leur classe pr evoit par d efaut. Souvent cela veut dire que le composant est un panneau (JPanel) et quon doit y montrer un dessin form e de trac es el ementaires (segments, arcs, rectangles et ovales pleins, etc.) ou bien une image obtenue ` a partir dun chier dun format reconnu par Java, comme GIF ou JPEG. Cest la m ethode paint qui a la responsabilit e de peindre un composant. Tous les composants en ont une version, ne serait-ce que celle quils ont h erit ee de la classe Component. Pour quun composant ait un dessin personnalis e il faut et il sut de red enir cette m ethode dans la classe du composant 96 . La m ethode paint nest jamais explicitement appel ee par le programme ; au lieu de cela, cest la machine Java qui se charge de lappeler, chaque fois que lapparence du composant doit etre refaite. Cela arrive principalement dans trois sortes de situations, dont seule la troisi` eme est ` a notre port ee : le composant doit etre repeint suite ` a un ev enement ext erieur ` a notre application, voire m eme ` a la machine Java (exemple : une autre fen etre est apparue devant le composant, puis a disparu), le composant doit etre repeint ` a cause dun ev enement qui sadresse bien ` a linterface graphique de notre application mais qui est pris en charge par un el ement ou une super-classe du composant (exemple : lutilisateur a chang e la taille de la fen etre, en agissant sur son bord), le composant doit etre repeint car les donn ees dont il exhibe une repr esentation ont chang e (la machine Java ne peut pas deviner cela, nous sommes les seuls ` a le savoir). Largument de la m ethode paint etant un objet de type Graphics, il nous fait pour commencer expliquer ce quest un tel objet. 11.6.2 Les classes Graphics et Graphics2D

Un contexte graphique est un objet qui encapsule lensemble des informations et des outils n ecessaires pour eectuer des op erations graphiques. Les contextes graphiques sont instances de la classe Graphics, ou dune de ses sous-classes comme Graphics2D. L etat dun tel objet se manifeste ` a travers un ensemble de m ethodes get (les m ethodes set correspondantes existent) dont les plus importantes sont : Shape getClip() donne la zone de coupe courante, cest-` a-dire la r egion en dehors de laquelle les op erations graphiques sont sans eet, Rectangle getClipRect() donne lenveloppe rectangulaire de la zone de coupe (voir ci-dessus), Color getColor() donne la couleur qui sera employ ee par les op erations graphiques, aussi bien pour tracer des traits que pour remplir des gures ou pour dessiner des textes, Font getFont() donne la police de caract` eres employ ee pour ecrire des textes, FontMetrics getFontMetrics() un objet FontMetrics qui repr esente un ensemble de mesures ` a propos de la police de caract` eres courante. Le comportement dun objet Graphics est constitu e par ses op erations graphiques. Parmi les principales : void clearRect(int x, int y, int width, int height) eace le rectangle sp eci e en le peignant avec la couleur de fond (background) du composant, void copyArea(int x, int y, int width, int height, int dx, int dy) copie une portion de limage en la pla cant ` a un endroit d eni par dx et dy, Graphics create() cr ee un contexte graphique qui est un clone de celui sur lequel cette m ethode est appel ee,
95. Ces requ etes sont aect ees de la priorit e la plus basse possible, si bien que la machine ne soccupera de repeindre les composants que lorsque elle naura vraiment rien dautre ` a faire ; de plus, Java ne conserve dans la le dattente quun exemplaire au plus dune telle requ ete. On evite ainsi les s eries de peintures successives que provoquerait la prise en charge prioritaire de ces requ etes, entra nant un travail inutile et des clignotements d esagr eables. 96. Cons equence pratique : si un composant doit avoir un dessin personnalis e, alors il devra etre instance dune classe sp ecialement d enie ` a cet eet.

116

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.6

Peindre et repeindre

(x,y) arcAngle startAngle

height

width

Figure 13 Trac e dun arc

void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) trace un arc dellipse mesurant arcAngle degr es et commen cant au point d eni par startAngle degr es (lorigine est ` a 3 heures ). Cette ellipse est inscrite dans le rectangle de largeur width et de hauteur height dont le coin sup erieur gauche est le point de coordonn ees x et y (cf. gure 13). boolean drawImage(Image img, int x, int y, ImageObserver observer) dessine limage img en pla cant son coin sup erieur gauche au point de coordonn ees x, y. observer est un objet destinataire des notications sur l etat davancement de limage qui par exemple dans le cas dimages obtenues sur le web peut se charger tr` es lentement ; si la question est sans int er et (par exemple sil sagit dimages qui narrivent pas par le r eseau) on peut mettre ici nimporte quel composant. void drawLine(int x1, int y1, int x2, int y2) trace un segment de droite joignant le point (x1 , y1 ) au point (x2 , y2 ), void drawRect(int x, int y, int width, int height) trace le bord dun rectangle de largeur width et de hauteur height dont le coin sup erieur gauche est plac e au point de coordonn ees x et y. void drawOval(int x, int y, int width, int height) trace le bord dune ellipse d enie par son enveloppe rectangulaire (voyez drawRect ci-dessus),

arcWidth (x,y) arcHeight

height

width

Figure 14 Un rectangle aux coins arrondis void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) trace le bord dun rectangle (x,y,width,height) dont les coins sont des quarts de lellipse inscrite dans un rectangle de largeur arcWidth et de hauteur arcHeight (cf. gure 14). void drawString(String str, int x, int y) trace la cha ne str de telle mani` ere que le coin inf erieur gauche de lenveloppe rectangulaire du premier caract` ere soit sur le point de coordonn ees x et y, void fillRect(int x, int y, int width, int height) peint lint erieur dun rectangle (cf. drawRect) en utilisant la couleur courante, void fillOval(int x, int y, int width, int height) peint lint erieur dune ellipse (cf. drawOval) en utilisant la couleur courante,
c H. Garreta, 2000-2013

117

11.6

Peindre et repeindre

11

INTERFACES GRAPHIQUES

void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) peint lint erieur dun rectangle aux coins arrondis (cf. drawRoundRect) en utilisant la couleur courante, void translate(int x, int y) place lorigine des coordonn ees sur le point de coordonn ees x et y (relatives a lorigine pr ` ec edente). A propos de Graphics2D La classe Graphics2D etend la classe Graphics en permettant un contr ole beaucoup plus sophistiqu e de la g eom etrie, les syst` emes de coordonn ees, les transformations graphiques, la couleur, laspect des textes, etc. Il faut savoir que la valeur du param` etre de type Graphics pass e` a la m ethode paint est en r ealit e un objet Graphics2D. Lorsque les op erations am elior ees de la classe Graphics2D sont n ecessaires, la m ethode paint commence donc de la mani` ere suivante, qui est donc l egitime : public void paint(Graphics g) { super.paint(g); Graphics2D g2d = (Graphics2D) g; ... op erations graphiques mettant en uvre lobjet g2d (toutes les op erations des classes Graphics et Graphics2D sont donc l egitimes) ... } 11.6.3 Exemple : la mauvaise mani` ere de dessiner

Figure 15 Gribouillages...

Donnons-nous le probl` eme suivant (voyez la gure 15) : dessiner une ligne polygonale que lutilisateur d enit en cliquant successivement sur les points quil souhaite placer comme sommets de la construction. Premi` ere version, nous expliquons plus loin en quoi elle nest pas bonne : import javax.swing.*; import java.awt.*; import java.awt.event.*; public class UnGribouillis extends JPanel { UnGribouillis() { setPreferredSize(new Dimension(600, 400)); setBackground(Color.WHITE); addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { clic(e.getX(), e.getY()); } }); }

118

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.6

Peindre et repeindre

private int xPrec = -1; private int yPrec;

// coordonn ees du // clic pr ec edent

void clic(int x, int y) { if (xPrec >= 0) { Graphics g = getGraphics(); g.drawLine(xPrec, yPrec, x, y); } xPrec = x; yPrec = y; } public static void main(String[] args) { JFrame cadre = new JFrame("Des gribouillis"); cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cadre.getContentPane().add(new UnGribouillis()); cadre.pack(); cadre.setVisible(true); } }

Le principe de ce programme est simple : ` a partir du second, chaque clic d etect e provoque le trac e dun segment joignant le point o` u il sest produit au point o` u sest produit le clic pr ec edent. On dessine donc ` a fonds perdu , ce qui est le d efaut de cette mani` ere de faire : si la ligne polygonale est endommag ee, notre application ne sera pas capable de la redessiner 97 .

11.6.4

Exemple : la bonne mani` ere de dessiner.

On laura compris, la bonne mani` ere de dessiner ne consiste pas ` a tracer les el ements graphiques au fur et ` a mesure que leurs param` etres sont connus, mais au contraire ` a m emoriser linformation requise pour tout (re-)dessiner chaque fois que cela est n ecessaire :

import import import import

javax.swing.*; java.awt.*; java.awt.event.*; java.util.*;

public class UnAutreGribouillis extends JPanel { UnAutreGribouillis() { setPreferredSize(new Dimension(600, 400)); setBackground(Color.WHITE); addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { points.add(new Point(e.getX(), e.getY())); repaint(); } }); } private Vector points = new Vector();

97. Dans certains cas, le syst` eme sous-jacent prend sur lui de m emoriser le contenu des fen etres an d etre en mesure de les restaurer lorsquelles auront et e partiellement ou totalement masqu ees. Cest gentil mais na f car cela ignore le fait que limage ` a montrer nest peut- etre pas la m eme que celle qui a et e sauvegard ee.

c H. Garreta, 2000-2013

119

11.7

Gestionnaires de disposition

11

INTERFACES GRAPHIQUES

public void paint(Graphics g) { super.paint(g); Iterator it = points.iterator(); if (it.hasNext()) { Point p = (Point) it.next(); while (it.hasNext()) { Point q = (Point) it.next(); g.drawLine(p.x, p.y, q.x, q.y); p = q; } } } public static void main(String[] args) { JFrame cadre = new JFrame("Des gribouillis"); cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cadre.getContentPane().add(new UnAutreGribouillis()); cadre.pack(); cadre.setVisible(true); } } Dans ce second programme, la r eaction a ` un clic de la souris nest plus le dessin dun segment, mais uniquement la m emorisation des coordonn ees du clic suivie dun appel de la m ethode repaint 98 pour indiquer que le dessin du composant nest plus valide (puisque la ligne polygonale poss` ede d esormais un sommet de plus, que la gure ne montre pas encore). Le dessin eectif est laaire de la m ethode paint, dont le programmeur doit ecrire la d enition mais jamais lappel, car la plupart des appels de cette m ethode sont impr evisibles. La cr eation dun sommet de la ligne polygonale est une exception : repaint ayant et e appel ee, lappel de paint est pour une fois pr evisible, mais les autres situations qui requi` erent le travail de paint (masquage de la fen etre, redimensionnement, etc.) ne peuvent pas etre explicitement pr edites et plac ees parmi les instructions du programme. Note 1. Presque toujours la version red enie de la m ethode paint commence, comme ici, par appeler la version h erit ee : super.paint(g); Cela est est n ecessaire car, sinon, le fond de l ecran ne serait pas repeint et de curieux dysfonctionnements appara traient. Note 2. La m ethode paint est la seule (bonne) m ethode pour peindre les composants de AWT. Pour les composants de Swing, cependant, la m ethode paint consiste en des appels successifs de trois m ethodes d el egu ees paintComponent, paintBorder et paintChildren. Cest pourquoi, dans le cas o` u notre composant a un bord et comporte des sous-composants, il vaut souvent mieux red enir la m ethode paintComponent au lieu de sen prendre ` a paint. La di erence nest pas bien grande : public class UnAutreGribouillis extends JPanel { ... public void paintComponent(Graphics g) { super.paintComponent(g); ... le reste de la m ethode est identique ` a paint, ci-dessus ... } ... }

11.7

Gestionnaires de disposition

Le placement des composants dans les conteneurs est laaire des gestionnaires de disposition, ou layout managers, qui se chargent :
98. Contrairement ` a ce quon pourrait penser, la m ethode repaint ne provoque pas un appel imm ediat de paint. Au lieu de cela, elle se limite a ` mettre dans la le des choses ` a faire une requ ete de peinture, sil ny en avait pas d ej` a une. Ce nest que quand toutes les autres requ etes de cette le auront et e trait ees (cest-` a-dire quand la machine Java naura rien dautre ` a faire) que la m ethode paint sera eectivement appel ee et le composant redessin e.

120

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.7

Gestionnaires de disposition

du placement initial des composants, lors des appels de la m ethode add, le cas ech eant, de donner une taille et une forme ` a chaque composant, en fonction de sa taille pr ef er ee , de son contenu et de sa disposition relativement aux autres composants dans le m eme conteneur, du repositionnement des composants lorsque la taille ou la forme du conteneur change.

Figure 16 Un panneau avec un gestionnaire FlowLayout

Absence de gestionnaire Pour commencer, evacuons une question tr` es secondaire : il est possible (mais non recommand e) de se passer compl` etement de gestionnaire de disposition. Cela doit etre explicitement demand e, par linstruction conteneur .setLayout(null); A la suite de cette commande, chaque composant devra etre explicitement dimensionn e et positionn e lors de son ajout au conteneur (bonjour les calculs avec des pixels !). Les m ethodes pour cela sont void setLocation(int x, int y), void setLocation(Point p) d enit la position du coin sup erieur gauche du composant (ou plut ot de son enveloppe rectagulaire), relativement ` a une origine qui est plac ee au coin sup erieur gauche du conteneur, void setSize(int width, int height), void setSize(Dimension d) d enit les dimensions du composant (ou plut ot de son enveloppe rectangulaire), void setBounds(int x, int y, int width, int height), void setBounds(Rectangle r) remplit simultan ement les fonctions de setLocation et celles de setSize. Lorsque les composants ont et e plac es manuellement il y a int er et ` a interdire les changements de taille et de forme du conteneur. Cela sobtient par lexpression conteneur .setResizable(false); Attention. Certains programmeurs d ebutants, rebut es par la dicult e quil y a parfois ` a obtenir dun gestionnaire de disposition quil fasse ce quon veut, choisissent de placer manuellement les composants. Lexp erience montre que, sauf de rares exceptions, se passer de gestionnaire de disposition nest pas la mani` ere la plus simple de r ealiser une interface graphique. 11.7.1 FlowLayout

Un gestionnaire FlowLayout (voir gure 16) dispose les composants par lignes, de la gauche vers la droite et du haut vers le bas. Par d efaut les composants sont centr es horizontalement et ecart es entre eux de 5 pixels, mais on peut changer cela au moment de linstanciation. Par exemple, le panneau de la gure 16 a et e construit par la s equence suivante : ... JPanel panneau = new JPanel(); panneau.setLayout(new FlowLayout(FlowLayout.LEFT)); panneau.add(new JButton("Un")); panneau.add(new JButton("Deux")); ... Le gestionnaire de disposition par d efaut dun JPanel est FlowLayout.
c H. Garreta, 2000-2013

121

11.7

Gestionnaires de disposition

11

INTERFACES GRAPHIQUES

11.7.2

BorderLayout

Un BorderLayout (voir gure 17) distingue cinq zones dans le conteneur auquel il est attach e : le nord, le sud, lest, louest et le centre.

Figure 17 Un panneau avec un gestionnaire BorderLayout Le nord et le sud, lorsquils sont pr esents, prennent toute la largeur du conteneur et ont la plus petite hauteur qui convient aux composants quils contiennent. Lest et louest, lorsquils sont pr esents, prennent toute la hauteur du conteneur moins les parties eventuellement occup ees par le nord et le sud, et ont la largeur minimale qui respecte les composants quils contiennent. Enn, le centre prend toute la place restante. Par exemple, le panneau de la gure 17 a et e construit par la s equence ... JPanel panneau = new JPanel(); panneau.setLayout(new BorderLayout()); panneau.add(new JButton("Haut"), BorderLayout.NORTH); panneau.add(new JButton("Gauche"), BorderLayout.EAST); panneau.add(new JButton("Bas"), BorderLayout.SOUTH); panneau.add(new JButton("Droite"), BorderLayout.WEST); panneau.add(new JButton("Centre"), BorderLayout.CENTER); ... Le gestionnaire de disposition par d efaut du panneau de contenu dun JFrame ou dun JDialog est BorderLayout. 11.7.3 GridLayout

Un gestionnaire GridLayout (voir gure 18) organise les composants selon une grille rectangulaire ayant un nombre de lignes et de colonnes convenus lors de la cr eation du gestionnaire. Toutes les cases de cette grille ont les m emes dimensions.

Figure 18 Un panneau avec un gestionnaire GridLayout ` a 4 colonnes Par exemple, le panneau de la gure 18 a et e construit par la s equence suivante : 122
c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.7

Gestionnaires de disposition

... JPanel panneau = new JPanel(); panneau.setLayout(new GridLayout(5, 4)); for (int i = 0; i <= 16; i++) panneau.add(new JButton("" + i)); ... 11.7.4 GridBagLayout

Un gestionnaire GridBagLayout est plus puissant, mais bien plus complexe que les pr ec edents. Il se base sur un quadrillage imaginaire du conteneur tel que lespace occup e par chaque composant soit une r egion rectangulaire form ee par la r eunion dun certain nombre de cases de ce quadrillage. Lors de son ajout au conteneur, chaque composant est associ e ` a une certaine contrainte qui sp ecie quelles cases du quadrillage imaginaire le composant occupe et comment il les occupe. Ensemble, toutes ces contraintes d enissent les dimensions des lignes et des colonnes du quadrillage. Les contraintes sont des instances de la classe GridBagConstraints, dont les principaux champs sont : gridx : num ero de la colonne du quadrillage (la premi` ere colonne porte le num ero 0) o` u se place langle sup erieur gauche du composant. gridy : num ero de la ligne du quadrillage (la premi` ere ligne porte le num ero 0) o` u se place langle sup erieur gauche du composant. gridwidth : nombre de colonnes du quadrillage sur lesquelles le composant s etend. gridheight : nombre de lignes du quadrillage sur lesquelles le composant s etend. weightx : nombre exprimant la largeur de la colonne que le composant occupe ; peu importe lunit e, pourvu que ce soit la m eme pour toutes les colonnes. Mettez 0 si ce composant s etend sur plusieurs colonnes ou si la largeur peut se d eduire de la contrainte dun autre composant de cette colonne. weighty : nombre exprimant la hauteur de la ligne que le composant occupe ; peu importe lunit e, pourvu que ce soit la m eme pour toutes les lignes. Mettez 0 si ce composant s etend sur plusieurs lignes ou si la hauteur peut se d eduire de la contrainte dun autre composant de cette ligne. fill : indication de la mani` ere dont le composant doit remplir sa zone. Les valeurs possibles sont : GridBagConstraints.NONE : le composant doit garder sa taille propre, GridBagConstraints.HORIZONTAL : le composant doit remplir toute la largeur de sa zone, GridBagConstraints.VERTICAL : le composant doit remplir toute la hauteur de sa zone, GridBagConstraints.BOTH : le composant doit remplir toute sa zone. anchor : position du composant dans sa zone, sil ne la remplit pas enti` erement. Les valeurs possibles sont : GridBagConstraints.NORTH (au nord), GridBagConstraints.NORTHEAST (au nord-est), GridBagConstraints.EAST (` a lest), GridBagConstraints.SOUTHEAST (au sud-est), etc. 11.7.5 Exemple : un panneau muni dun GridBagLayout

A titre dexemple 99 , proposons-nous de construire un panneau contenant les huit composants montr es sur la gure 19. La gure 20 montre le quadrillage (qui nexiste que dans la t ete du programmeur) par rapport auquel les composants sont plac es. Pour chacun on doit construire une contrainte ; cela est rapidement p enible, ` a moins de se donner une m ethode auxiliaire comme notre m ethode ajout : import javax.swing.*; import java.awt.*; public class TestGridBagLayout extends JFrame {
99. Cet exemple est d emonstratif mais inutilisable. Dune part, ce nest pas r ealiste de mettre ce type de composants dans le cadre principal dune application ; cet exemple correspond plus ` a une bo te de dialogue (JDialog) qu` a un cadre (JFrame). Dautre part, cet exemple est construit avec des composants anonymes, ce qui rend impossible la r ecup eration des informations que lutilisateur donne en saisissant des textes dans les champs de texte ou en pressant les boutons.

c H. Garreta, 2000-2013

123

11.7

Gestionnaires de disposition

11

INTERFACES GRAPHIQUES

Figure 19 Un panneau avec un gestionnaire GridBagLayout

Figure 20 Le quadrillage sous-jacent au gestionnaire GridBagLayout de la gure 19

TestGridBagLayout() { super("Test GridBagLayout"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panneau = new JPanel(); panneau.setBackground(new Color(220, 220, 255)); panneau.setPreferredSize(new Dimension(400, 300)); panneau.setLayout(new GridBagLayout()); ajout(panneau, new JLabel("Nom "), 0, 0, 1, 1, 10, 10, GridBagConstraints.NONE, GridBagConstraints.EAST); ajout(panneau, new JLabel("Prenom "), 0, 1, 1, 1, 0, 10, GridBagConstraints.NONE, GridBagConstraints.EAST); ajout(panneau, new JTextField(), 1, 0, 2, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER); ajout(panneau, new JTextField(), 1, 1, 2, 1, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER); 124
c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.8

Composants pr ed enis

ajout(panneau, new JButton("Soleil"), 0, 2, 1, 1, 0, 10, GridBagConstraints.NONE, ajout(panneau, new JButton("Ombre"), 1, 2, 1, 1, 10, 0, GridBagConstraints.NONE, ajout(panneau, new JButton("Indiff erent"), 0, 3, 2, 1, 0, 10, GridBagConstraints.NONE, ajout(panneau, new JButton("OK"), 2, 2, 1, 2, 10, 0, GridBagConstraints.BOTH, getContentPane().add(panneau); pack(); setVisible(true); }

GridBagConstraints.CENTER); GridBagConstraints.CENTER); GridBagConstraints.CENTER); GridBagConstraints.CENTER);

private void ajout(Container conteneur, Component composant, int gridx, int gridy, int gridwidth, int gridheight, int weightx, int weighty, int fill, int anchor) { GridBagConstraints contrainte = new GridBagConstraints(); contrainte.gridx = gridx; contrainte.gridy = gridy; contrainte.gridwidth = gridwidth; contrainte.gridheight = gridheight; contrainte.weightx = weightx; contrainte.weighty = weighty; contrainte.fill = fill; contrainte.anchor = anchor; conteneur.add(composant, contrainte); } public static void main(String[] args) { new TestGridBagLayout(); } } Ci-dessus le programmeur a x e ` a 10 la largeur de chaque colonne et la hauteur de chaque ligne, le panneau tout entier ayant une largeur de 30 (cela se d eduit des composants Nom, Soleil et OK ) et une hauteur de 40 (cela d ecoule de Nom, Pr enom, Soleil et Indi erent ). Lunit e de mesure est sans importance, la seule information quon a voulu donner ainsi est que la largeur de chaque colonne est le tiers de la largeur totale et la hauteur de chaque ligne est le quart de la hauteur totale. 11.7.6 Exemple : imbrication de gestionnaires de disposition

Les GridBagLayout ne sont pas les seuls outils pour la construction de gestionnaires dinterfaces graphiques complexes. Une autre mani` ere de monter de telles interfaces, plus souple et avec de lexp erience plus simple, consiste ` a imbriquer plusieurs panneaux (objets JPanel) les uns dans les autres, chacun muni dun gestionnaire ad equat. A ce propos on consultera avec prot lexemple montr e ` a la section 11.8.2, Construire une bo te de dialogue. 11.7.7 Bordures

Il est possible de cr eer une bordure autour dun composant. La mani` ere la plus simple est de la faire fabriquer par lusine de bordures (BorderFactory) selon le sch ema : unComposant .setBorder(BorderFactory.createXxx Border(param` etres de la bordure )) Ci-dessus, Xxx repr esente des mots qui identient le type de bordure souhait e. La gure 21 montre diverses sortes de bordures, et le jargon avec lequel elles sont nomm ees dans la classe BorderFactory.

11.8

Composants pr ed enis

Nous ne ferons pas ici une pr esentation syst ematique des di erentes, et nombreuses, classes de composants disponibles dans AWT et Swing. Cela est tr` es bien fait dans le tutoriel Java (http://java.sun.com/
c H. Garreta, 2000-2013

125

11.8

Composants pr ed enis

11

INTERFACES GRAPHIQUES

Figure 21 Des bordures, sans et avec titres

tutorial/). En particulier, ` a la section A Visual Index to the Swing Components (le con Using Swing Components de la s equence Creating a GUI with JFC/Swing ) on trouve une pr esentation extr emement parlante de tous les composants disponibles. Au lieu de cela nous allons montrer le mode demploi de certains des composants les plus utilis es, ` a travers une application tr` es na ve g erant le carnet dadresses dun club sportif.

Figure 22 Cadre avec menus

11.8.1

Exemple : mise en place et emploi de menus

La premi` ere version de notre programme illustre la mise en place des menus, voyez la gure 22. Les actions sur les menus sont d etect ees, mais les r eactions en sont, pour le moment, des appels de m ethodes vides : import javax.swing.*; import java.awt.event.*; public class ClubSportif extends JFrame { ClubSportif() { super("Amicale Bouliste de Trifouillis-les-Oies"); setSize(400, 200); initialiserLesMenus(); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); 126
c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.8

Composants pr ed enis

addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { quitter(); } }); setVisible(true); } private void initialiserLesMenus() { JMenuBar barre = new JMenuBar(); setJMenuBar(barre); JMenu menu = new JMenu("Fichier"); barre.add(menu); JMenuItem item = new JMenuItem("Ouvrir..."); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ouvrirFichier(); } }); item = new JMenuItem("Enregistrer..."); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { enregistrerFichier(); } }); menu.addSeparator(); item = new JMenuItem("Quitter"); menu.add(item); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { quitter(); } }); menu = new JMenu("Membre"); barre.add(menu); item = new JMenuItem("Cr eer..."); menu.add(item); item.addActionListener(new ActionListener() public void actionPerformed(ActionEvent creerMembre(); } }); item = new JMenuItem("Modifier..."); menu.add(item); item.addActionListener(new ActionListener() public void actionPerformed(ActionEvent modifierMembre(); } }); item = new JMenuItem("Supprimer..."); menu.add(item); item.addActionListener(new ActionListener() public void actionPerformed(ActionEvent supprimerMembre(); } }); }

{ e) {

{ e) {

{ e) {

c H. Garreta, 2000-2013

127

11.8

Composants pr ed enis

11

INTERFACES GRAPHIQUES

private void creerMembre() { } private void modifierMembre() { } private void supprimerMembre() { } private void ouvrirFichier() { } private void enregistrerFichier() { } private void quitter() { System.exit(0); } public static void main(String[] args) { new ClubSportif(); } } Note. Pour r eagir aux actions faites sur les menus nous avons choisi de donner un auditeur distinct ` a chaque item de menu. Une autre solution aurait consist e` a donner le m eme auditeur ` a tous les item. Cela nous aurait oblig e` a ecrire une m ethode actionPerformed ressemblant ` a ceci 100 : ... public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Ouvrir...")) ouvrirFichier(); else if (e.getActionCommand().equals("Enregistrer...")) enregistrerFichier(); else if (e.getActionCommand().equals("Quitter")) quitter(); else if (e.getActionCommand().equals("Cr eer...")) creerMembre(); else if (e.getActionCommand().equals("Modifier...")) modifierMembre(); else if (e.getActionCommand().equals("Supprimer")) supprimerMembre(); else throw new RuntimeException("Action command inattendue: " + e.getActionCommand()); } ...

11.8.2

Exemple : construire une boite de dialogue

Concevoir et mettre en place les bo tes de dialogue (dans dautres milieux on les appelle masques de saisie ) est certainement la partie la plus ennuyeuse du d eveloppement dune interface-utilisateur graphique. En Java la chose est rendue encore plus p enible par la pr esence des gestionnaires de disposition qui, tout en etant tr` es utiles pour g erer les changements de taille et de forme des conteneurs, manifestent souvent une grande r eticence ` a placer les composants selon la volont e du programmeur. Pour illustrer cette question nous allons ajouter ` a notre application une bo te de dialogue pour saisir les informations qui caract erisent un membre du club. Pour commencer, nous ne nous occupons ici que dassembler les composants, nous verrons ` a la section suivante comment utiliser la bo te pour acqu erir des informations.
100. Cette mani` ere de d etecter les actions sur les menus est certainement moins ecace que la pr ec edente. Mais lecacit e a-t-elle une quelconque importance, quand il sagit de r eagir ` a des gestes de lutilisateur ?

128

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.8

Composants pr ed enis

Figure 23 Bo te de dialogue de saisie

La gure 23 montre laspect de la bo te lors de son utilisation. La gure 24 montre les di erents panneaux (JPanel), munis de gestionnaires de dispositions distincts, que nous avons d u imbriquer les uns dans les autres pour obtenir le placement des composants que montre la gure 23.

panneauHaut panneauBis panneauTer panneauBas

panneauGauche

panneauDroite

Figure 24 Imbrication de panneaux pour r ealiser la boite de dialogue de la gure 23 Voici le constructeur de notre classe : import java.awt.*; import java.awt.event.*; import javax.swing.*; public class BoiteDialogueMembre extends JDialog implements Sports { JTextField champNom, champPrenom; JRadioButton sexeMasculin, sexeFeminin; JTextArea zoneAdresse; JCheckBox[] casesSports; JButton boutonOK, boutonAnnuler; boolean donneesAcquises;

c H. Garreta, 2000-2013

129

11.8

Composants pr ed enis

11

INTERFACES GRAPHIQUES

BoiteDialogueMembre(JFrame cadre) { super(cadre, "Saisie dun membre", true); zoneAdresse = new JTextArea(5, 20); JPanel panneauTer = new JPanel(); panneauTer.add(new JLabel("Sexe")); panneauTer.add(sexeMasculin = new JRadioButton("Homme")); panneauTer.add(sexeFeminin = new JRadioButton("Femme")); ButtonGroup groupe = new ButtonGroup(); groupe.add(sexeMasculin); groupe.add(sexeFeminin); JPanel panneauBis = new JPanel(); panneauBis.setLayout(new GridLayout(6, 1)); panneauBis.add(new JLabel("Nom")); panneauBis.add(champNom = new JTextField(20)); panneauBis.add(new JLabel("Pr enom")); panneauBis.add(champPrenom = new JTextField(20)); panneauBis.add(panneauTer); panneauBis.add(new JLabel("Adresse")); JPanel panneauGauche = new JPanel(); panneauGauche.setLayout(new BorderLayout()); panneauGauche.add(panneauBis, BorderLayout.CENTER); panneauGauche.add(new JScrollPane(zoneAdresse), BorderLayout.SOUTH); JPanel panneauDroite = new JPanel(); panneauDroite.setLayout(new GridLayout(nomSport.length, 1)); casesSports = new JCheckBox[nomSport.length]; for (int i = 0; i < nomSport.length; i++) panneauDroite.add(casesSports[i] = new JCheckBox(nomSport[i])); JPanel panneauHaut = new JPanel(); panneauHaut.setLayout(new BorderLayout()); panneauHaut.add(panneauGauche, BorderLayout.CENTER); panneauHaut.add(panneauDroite, BorderLayout.EAST); panneauHaut.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); JPanel panneauBas = new JPanel(); panneauBas.add(boutonOK = new JButton(" OK ")); panneauBas.add(boutonAnnuler = new JButton("Annuler")); boutonOK.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { finDuDialogue(true); } }); boutonAnnuler.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { finDuDialogue(false); } }); getContentPane().setLayout(new BorderLayout()); getContentPane().add(panneauHaut, BorderLayout.CENTER); getContentPane().add(panneauBas, BorderLayout.SOUTH); } ... dautres membres de cette classe sont montr es dans les sections suivantes ... } Le constructeur de BoiteDialogueMembre ne se termine pas par le couple pack(); setVisible(true); habituel. Ces op erations sont ` a la charge de celui qui cr ee une bo te de dialogue, on verra pourquoi. 130
c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.8

Composants pr ed enis

Le troisi` eme argument, true, de lappel du constructeur de JDialog super(cadre, "Saisie dun membre", true); fait que la bo te de dialogue est modale : aussi longtemps quelle est visible ` a l ecran, lutilisateur ne peut pas agir sur une autre partie de linterface graphique de lapplication. Linterface Sports, mentionn ee pr ec edemment, sert juste ` a mettre en place un ensemble de constantes 101 communes ` a plusieurs classes : public interface Sports { long TENNIS = 1 << long SQUASH = 1 << long NATATION = 1 << long ATHLETISME = 1 << long RANDONNEE = 1 << long FOOT = 1 << long BASKET = 1 << long VOLLEY = 1 << long PETANQUE = 1 << 0; 1; 2; 3; 4; 5; 6; 7; 8; // // // // // // // // // ou ou ou ou ou ou ou ou ou 1 2 4 8 16 32 64 128 256

String[] nomSport = { "Tennis", "Squash", "Natation", "Athl etisme", "Randonn ee", "Foot", "Basket", "Volley", "P etanque" }; long[] valSport = { TENNIS, SQUASH, NATATION, ATHLETISME, RANDONNEE, FOOT, BASKET, VOLLEY, PETANQUE }; } 11.8.3 Exemple : saisie de donn ees

Dans la bo te de dialogue que nous d eveloppons ici les seuls composants dont les ev enements sont d etect es et trait es sont les deux boutons OK et Annuler 102 . La pression du bouton OK d eclenche la validation des informations port ees par les champs de la bo te de dialogue et, en cas de succ` es, la fermeture de cette bo te ; le bouton Annuler la ferme dans tous les cas. Voici le reste de notre classe BoiteDialogueMembre : public class BoiteDialogueMembre extends JDialog implements Sports { ... private void finDuDialogue(boolean sortieParBoutonOK) { donneesAcquises = false; if (sortieParBoutonOK) { donneesAcquises = validerDonnees(); if (donneesAcquises) dispose(); } else dispose(); } private boolean validerDonnees() { if (champNom.getText().length() == 0) JOptionPane.showMessageDialog(this, "Le champ nom est vide", "Donn ee manquante", JOptionPane.ERROR_MESSAGE); else if (champPrenom.getText().length() == 0) JOptionPane.showMessageDialog(this, "Le champ pr enom est vide", "Donn ee manquante", JOptionPane.ERROR_MESSAGE); else if ( ! sexeMasculin.isSelected() && ! sexeFeminin.isSelected()) JOptionPane.showMessageDialog(this, "Le sexe nest pas indiqu e", "Donn ee manquante", JOptionPane.ERROR_MESSAGE); else if (zoneAdresse.getText().length() == 0) JOptionPane.showMessageDialog(this, "Ladresse nest pas indiqu ee", "Donn ee manquante", JOptionPane.ERROR_MESSAGE);
101. Ne pas oublier que toutes les variables dune interface sont, par d enition, statiques et nales (i.e. des constantes de classe). 102. Nous lavons d ej` a dit, nous d eveloppons ici un exemple na f. Dans une application plus s erieuse nous pourrions d etecter les frappes au clavier an de v erier les eventuelles contraintes sur les textes tap es.

c H. Garreta, 2000-2013

131

11.8

Composants pr ed enis

11

INTERFACES GRAPHIQUES

else return true; return false; } } La validation des donn ees faite ici est sommaire : nous nous contentons de v erier que tous les champs ont et e renseign es. Dans les cas r eels il y a souvent ` a faire des validations plus nes. Il est important de bien comprendre le fonctionnement de la m ethode finDuDialogue. Lorsque lutilisateur presse le bouton Annuler, ou bien lorsquil presse le bouton OK et que les donn ees sont trouv ees valides, alors lappel de dispose() d etruit lobjet graphique correspondant ` a la bo te de dialogue (i.e. tout ce qui se voit ` a l ecran), mais lobjet Java (i.e. linstance de la classe BoiteDialogueMembre) nest pas encore d etruit car, comme nous allons le voir, il est la valeur dune certaine variable (la variable locale dial de la m ethode creerMembre de la classe ClubSportif). Notez que si lutilisateur appuie sur le bouton OK et que les donn ees ne sont pas valides alors il ne se passe rien : la m ethode finDuDialogue retourne sans voir appel e dispose, donc la bo te de dialogue est toujours visible. Il faut voir enn que, la bo te etant modale, cest lappel de dispose fait dans finDuDialogue qui met n au blocage de lapplication qui etait en place depuis lappel de setVisible(true) fait par le constructeur de BoiteDialogueMembre. Voyons maintenant comment les instances de BoiteDialogueMembre rendent service ` a la classe ClubSportif, dont voici la partie nouvelle : import javax.swing.*; import java.awt.event.*; import java.util.*; public class ClubSportif extends JFrame implements Sports { Vector membres = new Vector(); // ce vecteur contient les membres du club // ses el ements sont des objets Membre ... private void creerMembre() { BoiteDialogueMembre dial = new BoiteDialogueMembre(this); dial.pack() dial.setVisible(true) if (dial.donneesAcquises) { Membre unMembre = new Membre(); unMembre.nom = dial.champNom.getText(); unMembre.prenom = dial.champPrenom.getText(); unMembre.sexeMasculin = dial.sexeMasculin.isSelected(); unMembre.adresse = dial.zoneAdresse.getText(); unMembre.sportsPratiqu es = 0; for (int i = 0; i < valSport.length; i++) if (dial.casesSports[i].isSelected()) unMembre.sportsPratiqu es |= valSport[i]; membres.add(unMembre); } } ... } La m ethode creerMembre m erite une explication. Elle commence par la d eclaration dune variable locale dial et la construction dun objet BoiteDialogueMembre ; ensuite, elle appelle les m ethodes pack() et setVisible(true). Or, on va attendre tr` es longtemps le retour de ce dernier appel, car la bo te de dialogue etant modale, cette expression qui a pour eet de la rendre visible a egalement pour eet de bloquer le thread dans lequel la m ethode creerMembre etait en train de sex ecuter. Ainsi, le contr ole natteindra le point que lorsque la m ethode dispose de la bo te de dialogue aura et e appel ee nous avons vu plus haut dans quelles conditions cela se produit. 132
c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.8

Composants pr ed enis

Lorsque lutilisateur aura mis n au dialogue, lobjet qui est la valeur de dial ne sera plus visible mais il existera toujours (ce ne sera plus le cas lorsque, ` a la n de la m ethode creerMembre, la variable dial sera d etruite) et il ny a aucune dicult e` a r ecup erer les valeurs de ses membres. Notons au passage lendroit, signal e par le rep` ere , o` u il faut donner aux champs de texte et aux cases ` cocher des valeurs initiales lorsque la saisie ne doit pas se faire ` a a partir de z ero, par exemple dans le cas de la modication dun membre (voyez la section 11.8.6). Est apparue egalement dans notre application une petite classe auxiliaire nomm ee Membre 103 . Le r ole de cette classe est evident : m emoriser les informations qui caract erisent un membre de notre club. Notez que, comme la m ethode creerMembre le montre, les sports pratiqu es sont stock es chacun sur un bit de lentier long sportsPratiqu es (cela limite ` a 64 le nombre de sports possibles, on peut penser que cest susant...) : public class String String boolean String long } 11.8.4 Membre implements Serializable { nom; prenom; sexeMasculin; adresse; sportsPratiqu es;

Exemple : choisir un chier

Figure 25 Boite de dialogue denregistrement de chier

Pour montrer dautres bo tes de dialogue, en particulier les bo tes pr etes ` a lemploi oertes par Swing pour choisir un chier (voir la gure 25), nous allons ajouter ` a notre application la possibilit e de sauver et restaurer les membres du club dans un chier. Cest pour avoir le droit den ecrire les instances dans un chier (on dit plut ot s erialiser ) que nous avons d eclar e que la classe Membre impl emente linterface java.io.Serializable. Il sagit dune interface vide, qui nentra ne donc aucune obligation sur la classe qui limpl emente ; l enonc e implements Serializable sert uniquement ` a indiquer que le programmeur donne le feu vert ` a la s erialisation des instances de la classe. Pour obtenir les fonctionnalit es indiqu ees il nous sut d ecrire les deux m ethodes enregistrerFichier et ouvrirFichier :
103. Une fois de plus, ne pas oublier que nous d eveloppons un exemple na f, dans lequel seule linterface utilisateur nous int eresse. Dans un cas r eel, la classe Membre serait bien plus complexe et comporterait probablement des m ethodes pour garantir la coh erence de linformation.

c H. Garreta, 2000-2013

133

11.8

Composants pr ed enis

11

INTERFACES GRAPHIQUES

public class ClubSportif extends JFrame implements Sports { ... private void enregistrerFichier() { JFileChooser dial = new JFileChooser(); dial.setDialogTitle("Enregistrer les membres"); dautres personnalisations de la bo te de dialogue pourraient appara tre ici if (dial.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return; File nomFichier = dial.getSelectedFile(); try { FileOutputStream fos = new FileOutputStream(nomFichier); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(membres); fos.close(); } catch (IOException ex) { JOptionPane.showMessageDialog(this, ex.toString(), "Probl` eme fichier", JOptionPane.ERROR_MESSAGE); } } private void ouvrirFichier() { JFileChooser dial = new JFileChooser(); dial.setDialogTitle("Restaurer les membres"); dautres personnalisations de la bo te de dialogue pourraient appara tre ici if (dial.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) return; File nomFichier = dial.getSelectedFile(); try { FileInputStream fis = new FileInputStream(nomFichier); ObjectInputStream ois = new ObjectInputStream(fis); membres = (Vector) ois.readObject(); fis.close(); } catch (Exception ex) { JOptionPane.showMessageDialog(this, ex.toString(), "Probl` eme fichier", JOptionPane.ERROR_MESSAGE); } } ... } 11.8.5 Exemple : une table pour acher des donn ees

Figure 26 Le tableau des membres du club

134

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.8

Composants pr ed enis

Pour en nir avec notre exemple nous allons lui ajouter une table achant la liste des membres du club avec certaines informations associ ees, comme montr e sur la gure 26. Une table (classe JTable) est un composant relativement complexe ob eissant au mod` ele de conception MVC dont le principe est de diviser le travail entre deux ojets : le mod` ele et la vue. Le premier d etient les donn ees, la seconde en fait une pr esentation graphique. Le modele MVC est comment e avec plus de soin ` a section 11.9. Ici cest surtout sur le mod` ele que nous allons travailler ; la vue sera un objet JTable dont le comportement par d efaut nous sura enti` erement. Les devoirs dun mod` ele de table sont d enis par linterface TableModel, dont une impl ementation partielle tr` es utile est AbstractTableModel. Do` u notre classe ModeleTableClub : import javax.swing.table.*; public class ModeleTableClub extends AbstractTableModel implements Sports { Vector membres; ModeleTableClub(Vector membres) { this.membres = membres; } public int getRowCount() { return membres.size(); } public int getColumnCount() { return 3 + valSport.length; } public String getColumnName(int j) { if (j == 0) return "Nom"; else if (j == 1) return "Prenom"; else if (j == 2) return "Sexe"; else return nomSport[j - 3].substring(0, 3); } public Class getColumnClass(int j) { if (j < 2) return String.class; else if (j == 2) return Character.class; else return Boolean.class; } public Object getValueAt(int i, int j) { Membre unMembre = (Membre) membres.elementAt(i); if (j == 0) return unMembre.nom; else if (j == 1) return unMembre.prenom; else if (j == 2) return new Character(unMembre.sexeMasculin ? M : F); else return new Boolean((unMembre.sportsPratiqu es & valSport[j - 3]) != 0); } } Dans la classe ModeleTableClub nous [re-]d enissons celles des m ethodes impos ees par linterface TableModel que la classe abstraite AbstractTableModel ne d enit pas ou ne d enit pas comme il nous faut.
c H. Garreta, 2000-2013

135

11.8

Composants pr ed enis

11

INTERFACES GRAPHIQUES

Les m ethodes pr ec edentes sont assez faciles ` a comprendre : ModeleTableClub : le constructeur sert ` a m emoriser une r ef erence sur le vecteur de membres que le tableau est cens e repr esenter ; getRowCount : le nombre de lignes du tableau nest autre que le nombre de membres du club ; getColumnCount : le nombre de colonnes du tableau d epend que des champs que nous avons d ecid e de repr esenter (ici, le nom, le pr enom, le sexe et les sports pratiqu es) ; getColumnName : donne le nom de chaque colonne, cest-` a-dire ce quil faut acher dans la premi` ere ligne ; getColumnClass : donne le type des informations de chaque colonne (suppos ee homog` ene), cela permet den donner une pr esentation adapt ee comme, pour un bool een, une case ` a cocher ; getValueAt : cette m ethode est la plus importante : getValueAt(i, j) renvoie l el ement qui se trouve ` a la ligne i et la colonne j du tableau. En plus de lajout de la classe pr ec edente, nous devons modier notre programme ` a plusieurs endroits : dune part les variables dinstance et le constructeur de la classe principale : public class ClubSportif extends JFrame implements Sports { Vector membres = new Vector(); AbstractTableModel modeleTable; JTable table; ClubSportif() { pr ec edent contenu du constructeur modeleTable = new ModeleTableClub(membres); table = new JTable(modeleTable); getContentPane().add(new JScrollPane(table)); setVisible(true); } Dautre part, il faut faire en sorte que les changements dans la table des membres se r epercutent dans le mod` ele. Deux mani` eres de faire cela : pour de petits changement, comme lajout dun unique membre, il sut de le notier au mod` ele. Par exemple, la m ethode creerMembre se terminera maintenant ainsi : ... membres.add(unMembre); modeleTable.fireTableRowsInserted(membres.size() - 1, membres.size() - 1); Pour de plus grands changements, comme lors du chargement dun chier, on peut carr ement remplacer le mod` ele par un mod` ele neuf. Ainsi, dans la m ethode ouvrirFichier on trouvera maintenant ... membres = (Vector) ois.readObject(); modeleTable = new ModeleTableClub(membres); table.setModel(modeleTable); // // // // ce vecteur contient les membres du club ses el ements sont des objets Membre le "mod` ele" de la table la "vue" de la table

11.8.6

Exemple : s election et modication dans une table

Pour en nir avec notre exemple, voici la m ethode modifierMembre qui prend en charge les changements des informations concernant un membre existant. Ce que cette m ethode illustre surtout, par comparaison avec creerMembre, est la mise en place dune bo te de dialogue dont les composants contiennent des informations initiales. 136
c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.9

Le mod` ele MVC (Mod` ele-Vue-Controleur)

private void modifierMembre() { int rang = table.getSelectedRow(); if (rang < 0) { JOptionPane.showMessageDialog(this, "Il faut dabord s electionner un membre", "Erreur", JOptionPane.ERROR_MESSAGE); return; } Membre unMembre = (Membre) membres.elementAt(rang); BoiteDialogueMembre dial = new BoiteDialogueMembre(this); dial.champNom.setText(unMembre.nom); dial.champPrenom.setText(unMembre.prenom); dial.sexeMasculin.setSelected(unMembre.sexeMasculin); dial.sexeFeminin.setSelected(!unMembre.sexeMasculin); dial.zoneAdresse.setText(unMembre.adresse); for (int i = 0; i < valSport.length; i++) { boolean b = (unMembre.sportsPratiqu es & valSport[i]) != 0; dial.casesSports[i].setSelected(b); } dial.pack(); dial.setVisible(true); if (dial.donneesAcquises) { unMembre.nom = dial.champNom.getText(); unMembre.prenom = dial.champPrenom.getText(); unMembre.sexeMasculin = dial.sexeMasculin.isSelected(); unMembre.adresse = dial.zoneAdresse.getText(); unMembre.sportsPratiqu es = 0; for (int i = 0; i < valSport.length; i++) if (dial.casesSports[i].isSelected()) unMembre.sportsPratiqu es |= valSport[i]; modeleTable.fireTableRowsUpdated(rang, rang); } }

11.9

Le mod` ele MVC (Mod` ele-Vue-Controleur)

Le mod` ele MVC est un mod` ele de conception, ou design pattern, qui consiste ` a maintenir une s eparation nette entre les donn ees manipul ees par lapplication (le mod` ele ), les pr esentations qui en sont faites (les vues ) et les dispositifs par lesquels les actions de lutilisateur sont d etect ees (les contr oleurs ). Puisque lutilisateur a une tendance naturelle ` a agir sur les composants quil voit, les vues sont le plus souvent associ ees ` a des contr oleurs. Laspect le plus int eressant de cette m ethodologie est la s eparation de la vue et du mod` ele, qui garantit que le codage interne et le traitement des donn ees ne sont pas pollu es par des questions de pr esentation ; cela permet, par exemple, que des pr esentations di erentes dun m eme mod` ele (textuelle, graphique, sonore, etc.) soient donn ees, cons ecutivement ou simultan ement. Bien entendu, s eparation nest pas totale ind ependance : chaque changement du mod` ele doit etre noti e a la vue an que celle-ci puisse ` etre mise a ` jour et re` ete constamment l etat actuel du mod` ele. Les composants de Swing saccordent au mod` ele MVC : chaque composant est consid er e comme une vue (ou plut ot comme un couple vue-contr oleur), et il doit etre associ e` a un mod` ele qui joue le r ole de source des donn ees pour le composant. Les m ethodes quun objet doit poss eder pour etre le mod` ele dun composant sont d enies par une interface associ ee ` a ce composant : ButtonModel, ListModel, TableModel, TreeModel, etc. Pour les composants les plus el ementaires, ces mod` eles sont tr` es simples. Le programmeur peut presque toujours ignorer cette question, car il a la possibilit e dutiliser, souvent sans le savoir, des mod` eles par d efaut. Par exemple, cest un tel mod` ele qui est mis en place lorsquon cr ee un bouton par une instruction simple, comme new JButton("Oui") . La section suivante d eveloppe un exemple avec un composant bien plus complexe, nomm e JTree, dans lequel lexistence du mod` ele et sa s eparation davec la vue ne peut etre ignor ee.
c H. Garreta, 2000-2013

137

11.9

Le mod` ele MVC (Mod` ele-Vue-Controleur)

11

INTERFACES GRAPHIQUES

11.9.1

Exemple : les vues arborescentes (JTree)

Figure 27 Repr esentation arborescente (JTree) dun ensemble de mots

Donnons-nous le probl` eme suivant (cf. gure 27) : acher larborescence de tous les mots dau plus quatre lettres form es avec les trois lettres a, b et c 104 . Nous allons le traiter de quatre mani` eres di erentes, correspondant ` a divers choix que nous pouvons faire pour le mod` ele (la structure darbre sous-jacente ` a la vue JTree) et pour les nuds dont cet arbre se compose : Souvent on na aucun pr erequis ` a propos des nuds impl ementant larbre, lesquels nont pas besoin d etre tr` es sophistiqu es. On peut alors utiliser des objets de la classe pr ed enie DefaultMutableTreeNode pour les nuds et un objet DefaultTreeModel pour le mod` ele. Ci-apr` es, cest la version 3, celle o` u on travaille le moins. Parfois on a d ej` a une d enition de la classe des nuds, d ecoulant dautres parties de lapplication, mais on peut laugmenter et notamment lui ajouter ce qui lui manque pour etre une impl ementation de linterface TreeNode. Il nous sut alors de prendre pour mod` ele un objet DefaultTreeModel, associ e a de tels nuds enrichis. Cest notre version 1 ci-apr` ` es. Il peut arriver quon nous impose par ailleurs une d enition pr ecise de la classe des nuds, ` a laquelle on nous interdit dajouter quoi que ce soit. On doit alors d enir notre propre classe du mod` ele, impl ementant linterface TreeModel, sachant manipuler ces nuds sp eciques. Nous avons fait cela ` a la version 2. Enn, lorsquon d ecide comme dans la situation pr ec edente de d enir notre propre classe du mod` ele, il peut arriver que cette classe puisse etre purement calculatoire , cest-` a-dire quelle ne repose sur aucune structure de donn ees sous-jacente. Cest le cas de notre version 4. es sous-jacente. Pour commencer, supposons que les Construction dune structure de donne nuds de larborescence nous soient impos es par ailleurs : ce sont les instances dune certaine classe Arbuste. Chacun comporte une cha ne de caract` eres, un vecteur m emorisant lensemble des ls et une r ef erence sur le pere :

104. Oui, bon, ce nest pas tr` es utile. Mais cest un exemple, non ?

138

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.9

Le mod` ele MVC (Mod` ele-Vue-Controleur)

public class Arbuste { private String info; private Vector fils; private Arbuste pere; public Arbuste(String info) { this.info = info; fils = new Vector(); pere = null; } public String getInfo() { return info; } public Arbuste getPere() { return pere; } public int nombreFils() { return fils.size(); } public Arbuste getFils(int i) { return (Arbuste) fils.elementAt(i); } public void ajouterFils(Arbuste unFils) { fils.add(unFils); unFils.pere = this; } public String toString() { return info; } } Voici un programme pour essayer cette classe. Lappel creerMots("", m , k ) construit larborescence des mots de k lettres form ees avec les m lettres a, b, c... public class Essai { public static Arbuste creerMots(String prefixe, int large, int profond) { Arbuste res = new Arbuste(prefixe); if (profond > 0) for (int i = 0; i < large; i++) res.ajouterFils(creerMots(prefixe + (char)(a + i), large, profond - 1)); return res; } public static void montrer(Arbuste arbre) { System.out.print(arbre + " "); int n = arbre.nombreFils(); for (int i = 0; i < n; i++) montrer(arbre.getFils(i)); } public static void main(String[] args) { Arbuste racine = creerMots("", 3, 4); montrer(racine); } } Voici (tronqu e) lachage produit par ce programme :
c H. Garreta, 2000-2013

139

11.9

Le mod` ele MVC (Mod` ele-Vue-Controleur)

11

INTERFACES GRAPHIQUES

a aa aaa aaaa aaab aba abaa abab abac acaa acab acac acb ccba ccbb ccbc ccc

aaac aab aaba aabb aabc aac aaca aacb aacc ab abb abba abbb abbc abc abca abcb abcc ac aca ... cbca cbcb cbcc cc cca ccaa ccab ccac ccb ccca cccb cccc

Vue arborescente, version 1. Pour acher notre arborescence nous allons cr eer un composant JTree. Un tel composant constitue une vue ; pour le cr eer il faut lui associer un mod` ele, qui doit etre une impl ementation de linterface TreeModel. Or il existe une impl ementation de TreeModel toute pr ete : la classe DefaultTreeModel, qui na besoin pour fonctionner que dune arborescence faite de nuds impl ementant linterface TreeNode. Notre premi` ere approche consiste donc ` a faire en sorte que nos objets Arbuste impl ementent linterface TreeNode. Pour cela il nous faut ajouter ` a notre classe Arbuste les m ethodes de linterface TreeNode (notez que certaines sont de simples renommages des m ethodes qui existent d ej` a dans notre classe) : import java.util.*; import javax.swing.tree.*; public class Arbuste implements TreeNode { ici apparaissent les membres de la version pr ec edente de Arbuste, auxquels il faut ajouter les m ethodes impos ees suivantes : public Enumeration children() { return fils.elements(); } public boolean getAllowsChildren() { return ! isLeaf(); } public TreeNode getChildAt(int childIndex) { return getFils(childIndex); } public int getChildCount() { return nombreFils(); } public int getIndex(TreeNode node) { return fils.indexOf(node); } public TreeNode getParent() { return pere; } public boolean isLeaf() { return fils.isEmpty(); } } Voici la nouvelle classe de test, elle ache le cadre repr esent e` a la gure 27 : import javax.swing.*; import javax.swing.tree.*; public class Essai { public static Arbuste creerMots(String prefixe, int large, int profond) { Arbuste res = new Arbuste(prefixe); if (profond > 0) for (int i = 0; i < large; i++) res.ajouterFils(creerMots(prefixe + (char)(a + i), large, profond - 1)); return res; } 140
c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.9

Le mod` ele MVC (Mod` ele-Vue-Controleur)

public static void main(String[] args) { JFrame cadre = new JFrame("Des mots..."); cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cadre.setSize(300, 500); Arbuste racine = creerMots("", 3, 4); JTree vue = new JTree(new DefaultTreeModel(racine)); cadre.getContentPane().add(new JScrollPane(vue)); cadre.setVisible(true); } } Note. Si nous avions envisag e que larbre puisse etre modi e` a la suite de son achage, par exemple en r eaction ` a des actions de lutilisateur, alors il aurait fallu que notre classe Arbuste impl emente linterface MutableTreeNode, une sous-interface de TreeNode qui sp ecie des m ethodes suppl ementaires pour ajouter et enlever des nuds aux arbres. Vue arborescente, version 2. Imaginons maintenant quil nous soit dicile ou impossible de modier la classe Arbuste pour en faire une impl ementation de TreeNode. Cela nous obligera ` a adopter une deuxi` eme mani` ere de construire la vue arborescente : ne pas utiliser un mod` ele par d efaut (classe DefaultTreeModel) mais un mod` ele que nous aurons d eni expr` es pour travailler avec des objets Arbuste. Cest notre classe ModeleArbuste, enti` erement faite de m ethodes impos ees par linterface TreeModel : import javax.swing.tree.*; import javax.swing.event.*; import java.util.*; public class ModeleArbuste implements TreeModel { private Arbuste racine; private Vector auditeurs; ModeleArbuste(Arbuste racine) { this.racine = racine; auditeurs = new Vector(); } public Object getRoot() { return racine; } public int getChildCount(Object parent) { return ((Arbuste) parent).nombreFils(); } public Object getChild(Object parent, int index) { return ((Arbuste) parent).getFils(index); } public int getIndexOfChild(Object parent, Object child) { int n = ((Arbuste) parent).nombreFils(); for (int i = 0; i < n; i++) if (((Arbuste) parent).getFils(i) == child) return i; return -1; } public boolean isLeaf(Object node) { return ((Arbuste) node).nombreFils() == 0; } public void addTreeModelListener(TreeModelListener l) { auditeurs.add(l); } public void removeTreeModelListener(TreeModelListener l) { auditeurs.remove(l); }
c H. Garreta, 2000-2013

141

11.9

Le mod` ele MVC (Mod` ele-Vue-Controleur)

11

INTERFACES GRAPHIQUES

public void valueForPathChanged(TreePath path, Object newValue) { /* Inutile */ } }

Une seule ligne de la nouvelle classe Essai di` ere davec la version pr ec edente. Pour construire la vue, au lieu de new JTree(new DefaultTreeModel(racine)) il faut faire : ... JTree vue = new JTree(new ModeleArbuste(racine)); ...

Vue arborescente, version 3. A loppos e de la pr ec edente, une autre mani` ere daborder ce probl` eme consiste ` a penser que des nuds aussi banals que les n otres peuvent etre r ealis es avec le mat eriel disponible dans la biblioth` eque, ce qui devrait nous dispenser d ecrire la classe Arbuste. En eet, si tout ce quon demande ` a un nud est de porter une information (peut importe son type, pourvu que ce soit un objet), davoir des ls et eventuellement davoir un p` ere, alors la classe DefaultMutableTreeNode convient parfaitement. Bien entendu, cela suppose que nous ayons le droit de renoncer ` a la classe Arbuste. Voici ce que devient, dans cette optique, la totalit e de notre programme (il est maintenant beaucoup plus court) : import javax.swing.*; import javax.swing.tree.*; public class Essai { public static DefaultMutableTreeNode creerMots(String prefixe, int large, int profond) { DefaultMutableTreeNode res = new DefaultMutableTreeNode(); res.setUserObject(prefixe); if (profond > 0) for (int i = 0; i < large; i++) res.insert(creerMots(prefixe + (char)(a + i), large, profond - 1), i); return res; } public static void main(String[] args) { JFrame cadre = new JFrame("Des mots..."); cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cadre.setSize(300, 500); DefaultMutableTreeNode racine = creerMots("", 3, 4); JTree vue = new JTree(new DefaultTreeModel(racine)); cadre.getContentPane().add(new JScrollPane(vue)); cadre.setVisible(true); } }

Vue arborescente, version 4. Il y a encore une autre mani` ere de traiter ce probl` eme ; elle consiste ` a examiner le mod` ele d eni ` a la version 2, cens e manipuler un arbre fait de nuds Arbuste, et se dire quun tel mod` ele pourrait aussi bien faire semblant de manipuler un arbre qui, en tant que structure de donn ees, nexiste pas. Voici la classe qui r ealise un tel mod` ele. Puisquil ny a pas darbre, les nuds se confondent avec les informations associ ees : 142
c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.10

Images

import javax.swing.tree.*; import javax.swing.event.*; import java.util.*; public class ModeleArbuste implements TreeModel { private int large; private int profond; private Vector auditeurs; ModeleArbuste(int large, int profond) { this.large = large; this.profond = profond; auditeurs = new Vector(); } public Object getRoot() { return ""; } public int getChildCount(Object parent) { if (((String) parent).length() < profond) return large; else return 0; } public Object getChild(Object parent, int index) { return ((String) parent) + (char)(a + index); } public int getIndexOfChild(Object parent, Object child) { String s = (String) child; return s.charAt(s.length() - 1) - a; } public boolean isLeaf(Object node) { return ! (((String) node).length() < profond); } public void addTreeModelListener(TreeModelListener l) { auditeurs.add(l); } public void removeTreeModelListener(TreeModelListener l) { auditeurs.remove(l); } public void valueForPathChanged(TreePath path, Object newValue) { /* inutile */ } }

11.10

Images

Dans les premi` eres versions de Java la manipulation des images ob eit ` a un mod` ele de production et consommation. Ayant pour objet premier les images provenant du Web, ce mod` ele suppose que lexploitation dune image est un processus, eventuellement de longue dur ee, impliquant un producteur, comme un chier sur un serveur eloign e, un consommateur, par exemple linterface graphique dune application qui ache limage, et un observateur , cest-` a-dire un objet qui supervise lop eration et qui re coit les notications concernant l etat davancement du transfert de limage. A c ot e de ce mod` ele, passablement complexe, l equipe de d eveloppement de Java fait maintenant la promotion dun mod` ele dit en mode imm ediat , centr e sur la notion dimage en m emoire : fondamentalement, on sint eresse moins au transfert de limage (pour lequel le mod` ele producteur/consommateur reste pertinent) qu` a ce quon peut faire avec limage lorsque, une fois transf er ee, elle est stock ee dans la m emoire du syst` eme.
c H. Garreta, 2000-2013

143

11.10

Images

11

INTERFACES GRAPHIQUES

11.10.1

Exemple : utiliser des ic ones

Figure 28 Six boutons et une (grande) etiquette d ecor es dic ones Les ic ones sont des images de taille xe, souvent petites, g en eralement utilis ees pour d ecorer certains composants comme les etiquettes et les boutons. Lapplication tr` es simple montr ee 105 ` a la gure 28 est faite dune grande etiquette portant un texte ( H otesse de lair ` a la Bardaf ) et une ic one (Natacha, un personnage de BD des ann ees 70). Le texte peut se placer ` a gauche, dans lalignement ou ` a droite de lic one, ainsi quen haut, ` a la m eme hauteur ou en bas de lic one (les composants etiquettes de Swing objets JLabel permettent de faire cela). Lapplication comporte en outre une barre doutils d etachable avec six boutons, dispos es en deux groupes de trois boutons mutuellement exclusifs, qui commandent la position du texte par rapport ` a lic one. Les boutons sont blancs quand ils sont au repos (non s electionn es) et rouges quand ils sont s electionn es. Ce programme utilise treize chiers contenant chacun une ic one : six ic ones de boutons blancs (chiers bhgauche.gif, bhcentre.gif, etc.), six ic ones de boutons rouges, dont les noms sont de l eg` eres alt erations des pr ec edents (chiers bhgaucheR.gif, bhcentreR.gif, etc.) et le dessin central (chier natacha.jpg). Tous ces chiers sont plac es dans un r epertoire ayant le nom relatif images. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Natacha extends JFrame implements ActionListener { JLabel etiquette; JToolBar barreOutils; static String chemin = "images/"; static String nomFic[] = { "bhgauche", "bhcentre", "bhdroite", "bvhaut", "bvcentre", "bvbas" }; static int position[] = { JLabel.LEFT, JLabel.CENTER, JLabel.RIGHT, JLabel.TOP, JLabel.CENTER, JLabel.BOTTOM };
105. Limperfection des moyens de reprographie habituellement inig es ` a ce genre de polycopi es nous dissuade de montrer ici de vraies photographies, qui auraient pourtant et e tout ` a fait adapt ees a ` lillustration de notre propos.

144

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.10

Images

Natacha() { super("Natacha"); creerBarreOutils(); creerEtiquette(); getContentPane().add(barreOutils, BorderLayout.NORTH); getContentPane().add(etiquette, BorderLayout.CENTER); pack(); setVisible(true); } void creerBarreOutils() { barreOutils = new JToolBar(); ButtonGroup[] groupe = { new ButtonGroup(), new ButtonGroup() }; for (int i = 0; i < 6; i++) { Icon iconeBoutonAuRepos = new ImageIcon(chemin + nomFic[i] + ".gif"); Icon iconeBoutonSelect = new ImageIcon(chemin + nomFic[i] + "R.gif"); JRadioButton radioBouton = new JRadioButton(iconeBoutonAuRepos); radioBouton.setSelectedIcon(iconeBoutonSelect); radioBouton.setActionCommand(nomFic[i]); radioBouton.addActionListener(this); groupe[i / 3].add(radioBouton); barreOutils.add(radioBouton); if (i == 1 || i == 3) radioBouton.setSelected(true); } } void creerEtiquette() { ImageIcon icone = new ImageIcon(chemin + "natacha.jpg"); etiquette = new JLabel("H^ otesse de lair ` a la Bardaf", icone, JLabel.CENTER); etiquette.setIconTextGap(20); etiquette.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); etiquette.setHorizontalTextPosition(JLabel.CENTER); etiquette.setVerticalTextPosition(JLabel.TOP); } public void actionPerformed(ActionEvent e) { for (int i = 0; i < 6; i++) if (e.getActionCommand().equals(nomFic[i])) break; if (i < 3) etiquette.setHorizontalTextPosition(position[i]); else etiquette.setVerticalTextPosition(position[i]); } public static void main(String[] args) { new Natacha(); } } Note. Dans lexemple ci-dessus, les boutons de la barre doutils nont pas un texte ach e. Il faut donc explicitement leur associer des cha nes action command an de pouvoir les distinguer dans la m ethode actionPerformed. Comme nimporte quel ensemble de six cha nes distinctes fait laaire, nous avons utilis e les noms des chiers images, qui ont le m erite dexister et d etre deux ` a deux di erents. 11.10.2 Exemple : charger une image depuis un chier

Apr` es les ic ones, qui sont des images simpli ees quon ne souhaite pas transformer, int eressons-nous aux images (quelconques) en m emoire, ou buered images. De telles images ont deux principales raisons d etre 106 : soit ce sont des images calcul ees , cest-` a106. Une bonne raison de sint eresser aux images en m emoire est le double buering. Lorsquon dessine directement sur l ecran

c H. Garreta, 2000-2013

145

11.10

Images

11

INTERFACES GRAPHIQUES

dire construites pixel ` a pixel par le programme (les fameuses images de synth` ese), soit ce sont des images trait ees , cest-` a-dire produites ` a lext erieur du programme (par exemple des photographies) mais devant subir des transformations g eom etriques, des modications des couleurs, etc. Bien entendu, dans un cas comme dans lautre, il est en g en eral n ecessaire que ces images, une fois construites en m emoire, puissent etre ach ees sur un ecran.

Figure 29 Acher une image

La gure 29 correspond ` a une application tr` es simple qui montre une premi` ere mani` ere dobtenir une image en m emoire : la charger depuis un chier (qui est nomm e 107 ici XGorce_020613.gif et est plac e dans un certain r epertoire images) : import java.awt.*; import javax.swing.*; public class AfficheurdImages extends JPanel { Image uneImage; AfficheurdImages() { uneImage = Toolkit.getDefaultToolkit().getImage("images/XGorce_020613.gif"); setPreferredSize(new Dimension(500, 150)); } public void paint(Graphics g) { super.paint(g); g.drawImage(uneImage, 5, 5, this); } public static void main(String[] args) { JFrame cadre = new JFrame("Afficher une image"); cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cadre.getContentPane().add(new AfficheurdImages()); cadre.pack(); cadre.setVisible(true); } } Dans la classe ci-dessus les m ethodes int eressantes sont le constructeur et la m ethode paint : le premier obtient limage a ` partir dun chier, la seconde lache. Remarque pointue. Ce programme fait ce quon lui demande de faire et il semble sans myst` ere car, ` a moins davoir une vue exceptionnelle, lutilisateur ne voit pas que d` es le d emarrage limage est (re-)dessin ee un grand nombre de fois. On peut sen apercevoir en ajoutant dans la m ethode paint la ligne System.out.println(compteur++);
une image tr` es complexe, les etapes de la construction sont perceptibles et lachage devient d esagr eable pour lutilisateur, particuli` erement dans le cas danimations. Le double buering est la technique consistant ` a dessiner non pas sur l ecran, mais sur une portion de m emoire quon met ` a l ecran en une seule op eration, donc de mani` ere instantan ee, lorsque le trac e est enti` erement ni. 107. Xavier Gorce dessine un strip quotidien dans LeMonde.fr, dans lequel les animaux de la for et et, plus r ecemment, les manchots de la banquise commentent lactualit e ou font des remarques philosophiques.

146

c H. Garreta, 2000-2013

11

INTERFACES GRAPHIQUES

11.10

Images

(compteur est une variable dinstance priv ee). Le programme ache limage et, en plus, il ache des nombres qui permettent de constater que paint a et e appel ee plus de vingt fois avant que le programme ne se calme ! Cela montre le caract` ere asynchrone du mod` ele producteur/consommateur, dont rel` eve la m ethode getImage de la classe Toolkit. Lappel qui en est fait dans le constructeur uneImage = Toolkit.getDefaultToolkit().getImage(nom de chier ); nattend pas la n du chargement de limage ; au lieu de cela, cet appel initie le processus et retourne imm ediatement, avant que les donn ees qui constituent limage ne soient acquises 108 . Par cons equent, lappel de paint qui est fait lors de lachage initial de linterface ne dessine pratiquement rien. Ce qui sauve ce programme est le quatri` eme argument (this) de lappel de drawImage : g.drawImage(uneImage, 5, 5, this); il indique que lobservateur de cette image est le panneau AfficherUneImage lui-m eme, qui devient ainsi le destinataire des notications concernant la progression du chargement. Chacune de ces notications provoque un appel de repaint, donc lachage dun nouvel etat de limage, jusqu` a ce que cette derni` ere soit enti` erement charg ee ; cela se passe assez vite et lutilisateur croit voir lachage en une fois dune image unique 109 . Charger une image rang ee avec les classes Dans lexemple pr ec edent on charge une image ` a partir dun chier sp eci e par son chemin dans un syst` eme de chiers donn e (probablement celui qui entoure le d eveloppement) : uneImage = Toolkit.getDefaultToolkit().getImage("images/XGorce.081102.gif"); Se pose alors la question : comment donner le chemin du chier image dans le cas le plus fr equent o` u lapplication doit sex ecuter dans un environnement inconnu, distinct de celui de son d eveloppement ? Si le chier de limage est un chier variable appartenant au syst` eme dans lequel lapplication sex ecute il ny a pas de probl` eme : le chemin sera saisi durant lex ecution, soit sous forme de texte, soit ` a laide dun FileChooser (cf. 11.8.4). Mais comment indiquer un chier constant , fourni par le d eveloppeur de lapplication, rang e avec les classes de celle-ci, par exemple dans larchive jar utilis ee pour distribuer lapplication ? La solution consiste a obtenir ladresse du chier par la m ` ethode getResource de la classe (nous disons bien la classe ) en cours dex ecution. Le travail est alors d el egu e` a lobjet class loader qui a charg e cette classe, en quelque sorte cela revient ` a chercher le chier l` a o` u on a trouv e la classe . Par exemple, si nous avons archiv e les classes de notre application avec un r epertoire images contenant le chier en question, il sura de remplacer la ligne montr ee pr ec edemment par : URL url = AfficheurdImages.class.getResource("images/XGorce.021108.gif"); uneImage = Toolkit.getDefaultToolkit().getImage(url); Note. Dans une m ethode dinstance (c.-` a-d. non statique), la premi` ere des lignes ci-dessus peut s ecrire egalement URL url = getClass().getResource("images/XGorce.021108.gif"); 11.10.3 Exemple : construire une image pixel par pixel

La m ethode createImage(ImageProducer producteur) de la classe java.awt.Component renvoie une image correspondant aux donn ees (les pixels ) fournies par lobjet producteur. Le type de limage (i.e. le mode de codage des pixels) est celui qui correspond ` a lenvironnement graphique utilis e, logiciel et mat eriel. Comme producteur on peut prendre un objet MemoryImageSource, consistant essentiellement en un tableau de nombres, chacun d ecrivant un pixel selon le codage RGB. Par exemple, le programme suivant dessine une image en noir et blanc calcul ee pixel par pixel (voyez la gure 30) : le centre de limage est blanc, puis les pixels sassombrissent au fur et ` a mesure quon s eloigne du centre, proportionnellement au carr e de la distance au centre :
108. Cest la raison pour laquelle, dans le constructeur, nous ne pouvons pas donner ` a notre panneau la taille eective requise par limage (ce qui aurait et e bien pratique !) mais uniquement une taille convenue comme 500 150. Cest que, imm ediatement apr` es lappel de createImage, limage nest quamorc ee et elle na pas de taille d enie. 109. Pour sen convaincre il sut de remplacer this par null dans lappel de drawImage : les notications sur lavancement du chargement seront perdues, il y aura un seul appel de paint et ce programme nachera presque rien.

c H. Garreta, 2000-2013

147

11.10

Images

11

INTERFACES GRAPHIQUES

Figure 30 Une image de synth` ese !

import java.awt.*; import javax.swing.*; import java.awt.image.*; class AfficheurdImages extends JPanel { static final int L = 400; static final int H = 250; Image uneImage; AfficheurdImages() { setPreferredSize(new Dimension(L, H)); int tabPixels[] = new int[L * H]; int i = 0; for (int y = 0; y < H; y++) { for (int x = 0; x < L; x++) { int dx = x - L / 2; int dy = y - H / 2; int r = Math.max(255 - (dx * dx + dy * dy) / 50, 0); tabPixels[i++] = (255 << 24) | (r << 16) | (r << 8) | r; } } uneImage = createImage(new MemoryImageSource(L, H, tabPixels, 0, L)); } public void paint(Graphics g) { super.paint(g); g.drawImage(uneImage, 0, 0, this); } public static void main(String[] args) { JFrame cadre = new JFrame("Afficher une image"); cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cadre.getContentPane().add(new AfficheurdImages()); cadre.pack(); cadre.setVisible(true); } }

148

c H. Garreta, 2000-2013

12

JAVA 5

12

Java 5

Si chaque version de Java a apport e au langage un lot d el ements nouveaux, Java 5 a et e une avanc ee particuli` erement signicative. Il y aurait beaucoup ` a dire ` a propos des nouveaut es de cette version, mais nous nous limiterons ici aux points susamment importants pour m eriter de gurer dans un polycopi e succinct comme celui-ci. Au moment o` u ce document est produit la version courante de Java est la version 7, ociellement d enomm ee JavaTM Platform Standard Edition 7 (ou, entre d eveloppeurs, JDK 1.7 ) mais les versions 5 et 1.4 sont encore tr` es r epandues. Vous pouvez sp ecier quelles extensions vous autorisez dans votre programme en lan cant la compilation avec loption -source : 1.4 1.5 ou 5 javac -source Classe .java 1.6 ou 6 1.7 ou 7 Par d efaut, la compilation se fait en accord avec la version 7. Si vous compilez avec loption -source 1.4 alors les extensions expliqu ees ci-apr` es ne seront pas admises ; cela peut sav erer utile, certaines prescriptions de la version 5 provoquant parfois des messages davertissement copieux et obscurs lors de la compilation de sources dorigine 1.4.

12.1

Types enum er es

On a souvent besoin densembles nis de donn ees conventionnelles, comme { nord, sud, est, ouest }, { lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche }, etc. Quel que soit le domaine dapplication, ces sortes de donn ees partagent certains traits caract eristiques : 1. Elles sont symboliques et naturellement munies de noms signicatifs. Cest pourquoi il est regrettable de les repr esenter ` a laide de simples nombres, comme on le fait quand on na pas dautre moyen : 0 pour nord, 1 pour sud, 2 pour est, etc. 2. Ce sont des donn ees atomiques comme des nombres , ce qui devrait permettre un faible encombrement et un traitement tr` es rapide. Cest pourquoi il est regrettable de les repr esenter par des cha nes de caract` eres, comme on le fait parfois : "nord" pour nord, "sud" pour sud, etc. 3. Ces donn ees constituent des ensembles nis, souvent de taille r eduite, ce qui devrait permettre certaines op erations et certaines optimisations par exemple, pour la repr esentation de leurs sous-ensembles auxquelles il faut renoncer si on repr esente ces donn ees par des nombres ou des cha nes de caract` eres. 4. Enn, et surtout, elles constituent des ensembles disjoints davec les autres types de donn ees : un point cardinal, par exemple, nest pas interchangeable avec un jour de la semaine ! Cela devrait permettre, de la part du compilateur, un puissant contr ole de type quon na pas si on repr esente ces donn ees par des nombres ou des cha nes. En Java, jusqu` a la version 1.4, on impl ementait presque toujours les donn ees symboliques par des suites de constantes num eriques : public public public public static static static static final final final final int int int int NORD = 0; SUD = 1; EST = 2; OUEST = 3;

Cette mani` ere de faire respecte les deux premi` eres caract eristiques ci-dessus, mais pas les deux suivantes. En eet, rien ne dit au compilateur que les constantes NORD, SUD, EST, OUEST constituent la totalit e dun type et, surtout, ces constantes ne forment m eme pas un type : le compilateur ne pourra pas nous aider si par inadvertance nous aectons la valeur NORD ` a une variable jourDeLaSemaine (dont les valeurs attendues LUNDI, MARDI, etc., sont egalement repr esent ees par des constantes enti` eres). Java 5 corrige ces d efauts en introduisant les nouveaux types enum er es ou enums, expliqu es ci-apr` es. 12.1.1 Enums

La d eclaration dun type enum er e se compose au moins des el ements suivants (cela senrichira par la suite) : qualieurs enum identicateur { identicateur , identicateur , ... identicateur } Deux exemples :
c H. Garreta, 2000-2013

149

12.1

Types enum er es

12

JAVA 5

public enum PointCardinal { NORD, SUD, EST, OUEST } public enum JourSemaine { LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE } Note. Les deux d eclarations pr ec edentes d enissant des types publics, elles doivent etre ecrites dans deux chiers s epar es, respectivement nomm es PointCardinal.java et JourSemaine.java. Exemples dutilisation ult erieure : PointCardinal direction = PointCardinal.NORD; ... JourSemaine jourDePresence = JourSemaine.MERCREDI; Notez bien que la d eclaration dun type enum nest pas quun artice pour donner des noms expressifs ` a une poign ee de nombres entiers. Les d eclarations pr ec edentes cr eent bien deux types nouveaux, PointCardinal et JourSemaine, distincts entre eux et distincts de tous les autres types, dont lemploi pourra etre nement contr ol e par le compilateur. Pour faire comprendre la nature des el ements dun type enum disons pour commencer (car en fait cest plus riche que cela) que la d eclaration public enum PointCardinal { NORD, SUD, EST, OUEST } a d ej` a tout leet quaurait eu la d eclaration suivante : public class PointCardinal { public static final PointCardinal public static final PointCardinal public static final PointCardinal public static final PointCardinal NORD = new PointCardinal(); SUD = new PointCardinal(); EST = new PointCardinal(); OUEST = new PointCardinal();

private PointCardinal() { } // ceci interdit la cr eation dautres instances } 12.1.2 M ethodes des types enum er es

Un type enum er e appara t donc comme une classe dont les seules instances sont les valeurs du type enum er e. En r ealit e, tout type enum er e est sous-classe de la classe java.lang.Enum, qui introduit quelques m ethodes bien utiles : String name(), String toString() Ces deux m ethodes renvoient la valeur en question, exprim ee sous forme de cha ne de caract` eres ; par exemple PointCardinal.NORD.name() est la cha ne "NORD". La seconde est plus int eressante car elle est implicitement appel ee par Java pour convertir une valeur en cha ne ; de plus, elle peut etre red enie. Cela s ecrit comme ceci : public enum PointCardinal { NORD, SUD, EST, OUEST; public String toString() { return "<" + super.toString().toLowerCase() + ">"; } } Dans ces conditions, linstruction System.out.println(PointCardinal.OUEST); produit lachage de <ouest> static enum eration valueOf(String nom) Renvoie la valeur du type enum er e dont le nom est donn e. Ce nom doit etre ecrit exactement comme dans la d enition du type enum er e. Par exemple, PointCardinal.valueOf("EST") vaut PointCardinal.EST. static enum eration [] values() Renvoie un tableau contenant toutes les valeurs du type enum er e. Par exemple, le code PointCardinal[] directions = PointCardinal.values(); for (int i = 0; i < directions.length; i++) System.out.print(directions[i] + " "); ache le texte NORD SUD EST OUEST . 150
c H. Garreta, 2000-2013

12

JAVA 5

12.1

Types enum er es

int ordinal() Renvoie un entier qui exprime le rang de la valeur dans le type : PointCardinal.NORD.ordinal() vaut 0, PointCardinal.SUD.ordinal() vaut 1, etc. La transformation r eciproque est facile ` a obtenir : PointCardinal.values()[0] vaut PointCardinal.NORD, PointCardinal.values()[1] vaut PointCardinal.SUD, etc. 12.1.3 Aiguillages command es par des types enum er es

Bien quelles ne soient pas des nombres ou des caract` eres, les valeurs des types enum er es peuvent servir a piloter des aiguillages. Par exemple, supposons avoir la d ` eclaration public enum CategorieVehicule { BERLINE, COUPE, FAMILIALE; } voici un tel aiguillage : ... CategorieVehicule categorie; ... switch (categorie) { case BERLINE: code correspondant au cas o` u categorie vaut CategorieVehicule.BERLINE break; case COUPE: code correspondant au cas o` u categorie vaut CategorieVehicule.COUPE break; case FAMILIALE: code correspondant au cas o` u categorie vaut CategorieVehicule.FAMILIALE break; default: throw new AssertionError("\nErreur de programmation: cas " + categorie + " non trait e dans switch"); } Notez que, puisque le switch est command e par une expression de type CategorieVehicule, ` a lint erieur de celui-ci le compilateur laisse ecrire BERLINE, COUPE ou FAMILIALE au lieu de CategorieVehicule.BERLINE, CategorieVehicule.COUPE ou CategorieVehicule.FAMILIALE. Notez egalement que lutilisation de la clause default, comme ci-dessus, est recommand ee. En proc edant ainsi, si plus tard on ajoute des valeurs au type enum er e en oubliant dajouter les case correspondants dans les switch concern es, on en sera pr evenu (h elas, on ne sera pr evenu qu` a lex ecution, on aurait sans doute pr ef er e l etre durant la compilation...). 12.1.4 Dictionnaires et ensembles bas es sur des types enum er es

Dictionnaires. Le nouveau type EnumMap (en r ealit e cest une classe param etr ee mais pour commencer nous passerons cet aspect sous silence voyez la n de cette section) a et e introduit pour permettre la construction de tables associatives dont les cl es sont les valeurs dun type enum er e, avec optimisation de lespace et du temps dacc` es. Cela semploie comme ceci : Map permanence = new EnumMap(JourSemaine.class); ... permanence.put(JourSemaine.MARDI, "M. Jack Palmer"); permanence.put(JourSemaine.JEUDI, "Mme Raymonde Bidochon"); ... JourSemaine jour; ... String qui = (String) permanence.get(jour); if (qui != null) System.out.println("le permanent de " + jour + " est " + qui); ...
c H. Garreta, 2000-2013

151

12.2

Emballage et d eballage automatiques

12

JAVA 5

Ensembles. De mani` ere analogue ` a EnumMap, le type EnumSet (encore une classe param etr ee, voyez la n de cette section) a et e introduit en vue de la d enition densembles compacts et ecaces 110 dont les el ements sont les valeurs dun type enum eration donn e. Les ensembles EnumSet supportent, comme toutes les collections, les op erations fondamentales contains (test dappartenance), add et remove (ajout et suppression dun el ement), plus quelques op erations de fabrication particuli` erement commodes : static EnumSet of(Object premierElement, Object... autresElements) Construction dun ensemble form e des el ements indiqu es (il sagit dune m ethode avec nombre variable darguments, cf. 12.3.3). static EnumSet allOf(Class typeElements) Construction dun ensemble form e de tous el ements du type enum er e indiqu e. static EnumSet complementOf(EnumSet s) Construction dun ensemble form e de tous les el ements du type enum er e en question qui ne sont pas dans lensemble indiqu e. Exemple : ... EnumSet joursDePresence = EnumSet.of(JourSemaine.LUNDI, JourSemaine.MERCREDI, JourSemaine.VENDREDI); ... joursDePresence.add(JourSemaine.MARDI); joursDePresence.remove(JourSemaine.VENDREDI); ... JourSemaine jour; ... if (joursDePresence.contains(jour)) System.out.println("ok pour " + jour); ... Note. Nous ne lavons pas fait appara tre dans les lignes pr ec edentes, pour ne pas les alourdir, mais en r ealit e EnumMap et EnumSet sont des classes param etr ees (cf. 12.5) et leurs d eclarations compl` etes prennent les formes assez troublantes suivantes : class EnumSet<E extends Enum<E>> { ... } class EnumMap<K extends Enum<K>, V> { ... }

12.2
12.2.1

Emballage et d eballage automatiques


Principe

En Java, les donn ees de types primitifs, byte, short, int, long, float, double, char et boolean, ne sont pas des objets. Cela est ainsi pour des raisons evidentes decacit e, car traiter ces types de donn ees comme le font les langages les plus simples permet dutiliser des op erations c abl ees (cest-` a-dire directement prises en charge par le mat eriel) extr emement optimis ees. Cependant, dun point de vue m ethodologique, ce nest pas satisfaisant : cest regrettable pour la clart e des id ees, car cela introduit deux poids et deux mesures (ce qui est vrai pour les objets ne lest pas forc ement pour les donn ees primitives, et r eciproquement), multiplie les cas particuliers, alourdit les sp ecications, etc., dun point de vue pratique cest encore plus regrettable, car cela interdit demployer sur des donn ees de types primitifs les puissants outils de la biblioth` eque Java comme les collections, qui ne travaillent quavec des objets. Ce second d efaut etant consid erable, il a bien fallu lui trouver un rem` ede. Cela a consist e (cf. 9.1.1) en la d enition de huit classes Byte, Short, Integer, Long, Float, Double, Character et Boolean, en correspondance avec les huit types primitifs ; chaque instance dune de ces classes se compose dune unique donn ee membre qui est une valeur du type primitif que linstance enveloppe . Lop eration consistant ` a construire un tel objet enveloppant une valeur v dun type primitif sappelle emballage de la valeur v ; lop eration r eciproque sappelle d eballage de la valeur v . Ainsi, par exemple, pour des valeurs de type int, ces op erations peuvent (et, jusqu` a Java 1.4, doivent ) s ecrire :
110. On nous assure que ces ensembles sont r ealis es avec des tables de bits, ils sont donc aussi peu encombrants et dun traitement aussi ecace que les ensembles quon peut r ealiser soi-m eme avec des el ements repr esent es par des puissances de 2 et les op erateurs de bits & et |.

152

c H. Garreta, 2000-2013

12

JAVA 5

12.2

Emballage et d eballage automatiques

int unInt; ... Integer unInteger = new Integer(unInt); ... unInt = unInteger.intValue();

// emballage de unInt // d eballage de unInt

La bonne nouvelle est quen Java 5 ces deux op erations sont devenues automatiques, cest-` a-dire ins er ees par le compilateur l` a o` u elles sont n ecessaires, sans que le programmeur nait ` a sen occuper explicitement. Plus pr ecis ement : dans un endroit o` u un objet est attendu on peut mettre une expression dun type primitif ; ` a lex ecution, sa valeur sera convertie en objet par construction dune instance de la classe enveloppe correspondant a ce type primitif, ` dans un endroit o` u une valeur dun type primitif est attendue on peut mettre une expression dont le type est la classe-enveloppe correspondante ; ` a lex ecution, lobjet sera converti dans le type primitif requis par appel de la m ethode type Value(), o` u type est le nom de ce type primitif. Exemple. Un important domaine dapplication de lemballage et d eballage automatiques est la mise en uvre de collections contenant des donn ees primitives. Par exemple, voici comment on peut r ealiser simplement une le dattente dentiers en Java 5 : D eclaration et cr eation : List file = new LinkedList(); // Op eration introduire un entier v dans la le (v file.add(v); // Op eration extraire un entier u de la le : int u = (Integer) file.remove(0); // ou Vector, ou toute autre impl ementation de List a et e d eclar ee int) : add ajoute ` a la n de la liste extraction de l el ement de t ete

Note. Avec les collections g en eriques expliqu ees plus loin (cf. 12.5) les op erations pr ec edentes deviennent encore plus simples et, surtout, plus ables : List<Integer> file = new LinkedList<Integer>(); ... file.add(v); // ici il est v erifi e que la conversion de v ... // donne un Integer int u = file.remove(0); // ce qui sort de la file est un Integer 12.2.2 Op erations d eriv ees et autres cons equences

Le m ecanisme de lemballage et d eballage automatiques est simple et puissant, mais il faut prendre garde quil a de nombreuses cons equences, dont certaines subtiles. tique. Par exemple, avec la d Arithme eclaration Integer nombre; le code suivant est l egitime nombre = nombre + 1; le compilateur le traduira en : nombre = new Integer(nombre.intValue() + 1); De m eme, il est possible d ecrire nombre++ cette expression ayant la valeur et leet quaurait lappel dune fonction ctive ressemblant ` a ceci : Integer nombre++ () { Integer tmp = nombre; nombre = new Integer(nombre.intValue() + 1); return tmp; } Comparaison. Integer a = Integer b = Integer c = Integer d = Le cas de la comparaison est plus d elicat. Donnons-nous la situation suivante : 123; 123; 12345; 12345;

c H. Garreta, 2000-2013

153

12.2

Emballage et d eballage automatiques

12

JAVA 5

et examinons lachage produit alors par les expressions suivantes : System.out.println( System.out.println( System.out.println( System.out.println( a c a c == == == == 123 ); 12345 ); b ); d );

Sans surprise, la quatri` eme expression (c == d) sache false. En eet, c et d sont des objets construits s epar ement et on a d ej` a expliqu e (cf. 3.6.3) que, pour les objets, == exprime lidentit e ( egalit e des r ef erences), non l equivalence. Pour tester l equivalence ( egalit e des valeurs) il aurait fallu ecrire c.equals(d). En revanche, on sera peut- etre etonn e en constatant que les trois autres expressions achent true. Pour les deux premi` eres (a == 123 et c == 12345) la question est la m eme : il sagit de savoir si la comparaison a == 123 porte sur deux valeurs primitives ([a converti en int] et 123) ou bien sur deux objets (a et [123 transform e en Integer]). Cest le premier qui se produit : la comparaison des valeurs etant en g en eral plus int eressante que la comparaison des r ef erences, le compilateur pr ef` ere travailler dans le type primitif. Do` u le r esultat true : a et c convertis en int sont bien respectivement egaux aux nombres auxquels on les compare. Il reste le troisi` eme cas, a == b, qui sache true faisant penser que, bien que construits s epar ement, a et b sont le m eme objet. Et cest bien ce qui se passe ! En eet, dans certains cas r eput es fr equents, avant de provoquer un appel de new, Java examine si la valeur en question na pas d ej` a et e emball ee, auquel cas lobjet-enveloppe pr ec edemment construit est r eutilis e. Ainsi, les deux lignes Integer a = 123; Integer b = 123; ont le m eme eet que Integer a = new Integer(123); Integer b = a; ce qui explique l egalit e trouv ee. Les cas r eput es fr equents , cest-` a-dire les valeurs pour lesquelles la machine cherche ` a savoir si elles ont d ej` a et e emball ees avant de cr eer un nouvel objet, sont les petites valeurs ; plus pr ecis ement : les bool eens false et true, les valeurs de type byte, short et int comprises entre -128 et 127, les caract` eres dont le code est compris entre \u0000 (0) et \u007F (127) 12.2.3 La r esolution de la surcharge en Java 5

Dans quelle mesure le m ecanisme de lemballage et d eballage automatiques complique-t-il celui de la r esolution de la surcharge que Java emploie par ailleurs ? Supposons, par exemple, disposer dune certaine m ethode traitement surcharg ee : void traitement(double x) { ... } ... void traitement(Integer y) { ... } a loccasion dun appel comme int z; ... traitement(z); laquelle des deux m ethodes doit-on activer ? Autrement dit, le type Integer est-il consid er e plus proche du type int que le type double, ou le contraire ? Les concepteurs de Java 5 ont d ecid e de privil egier une certaine forme de compatibilit e avec Java 1.4, ainsi la conversion vers le type primitif (ici double) est pr ef er ee. La r` egle pr ecise est la suivante : En Java 5 la r esolution de la surcharge se fait en trois temps : 1. Le compilateur cherche dabord ` a r esoudre lappel dune m ethode surcharg ee sans utiliser lemballage et d eballage automatiques ni les arguments variables (cf. 12.3.3). Si lappel peut etre r esolu ainsi, alors les r` egles appliqu ees auront et e les m eme quen Java 1.4. 2. Si la premi` ere etape a echou e, alors le compilateur cherche ` a r esoudre lappel en se permettant des emballages et des d eballages, mais sans consid erer les m ethodes avec des arguments variables. 3. Enn, si l etape 2 a echou e aussi, alors le compilateur cherche ` a r esoudre lappel en consid erant les m ethodes avec des arguments variables. 154
c H. Garreta, 2000-2013

12

JAVA 5

12.3

Quelques outils pour simplier la vie du programmeur

12.3
12.3.1

Quelques outils pour simplier la vie du programmeur


Importation de membres statiques

Ou : comment raccourcir encore les noms de certaines entit es ? La directive import que nous connaissons permet de mentionner une classe publique sans avoir ` a pr exer son nom par celui de son paquetage. Cest bien, mais cela nemp eche pas que les autres entit es manipul ees dans les programmes, comme les membres des classes, ont tendance ` a avoir des noms ` a rallonges. Ne pourrait-on pas faire dautres simplications du m eme genre ? Pour les membres ordinaires non statiques on ne peut pas grand chose : ils doivent etre pr ex es par un objet car cela est dans leur nature m eme de membres dinstance, cest-` a-dire n ecessairement li es ` a un objet. Seule simplication, bien connue : quand cet objet est this, la plupart du temps il peut etre omis. Il nen est pas de m eme pour les membres de classe (membres quali es static), cela a permis de simplier leur emploi en Java 5. Jusqu` a Java 1.4, ces membres doivent etre ecrits pr ex es par le nom de leur classe ; il sagit d eviter d eventuelles collisions de noms, ce qui est un risque potentiel qui nest pas toujours eectif : les membres de classes di erentes ont une petite tendance ` a avoir des noms di erents. Ne pourrait-on pas, lorsquil ny a pas de collision, permettre que les noms des membres statiques soient utilis es sans pr exe ? Cest la nouvelle directive import static qui rend ce service. Elle semploie sous deux formes : import static nomCompletDeClasse .nomDeMembreStatique ; import static nomCompletDeClasse .*; Dans la premi` ere forme, le nom du membre statique indiqu e pourra etre utilis e seul, cest-` a-dire non prex e par le nom de la classe. Dans la deuxi` eme forme, tous les membres statiques de la classe indiqu ee pourront etre utilis es seuls. Exemple. Le programme Sinus ache le sinus dun angle donn e en degr es. Version traditionnelle : public class Sinus { public static void main(String[] args) { double x = Double.parseDouble(args[0]) * Math.PI / 180; double y = Math.sin(x); System.out.println("sin(" + x + ") = " + y); } } La version avec des membres statiques import es est plus l eg` ere (en faisant abstraction des directives import) : import static java.lang.Math.*; import static java.lang.Double.parseDouble; import static java.lang.System.out; public class Sinus { public static void main(String[] args) { double x = parseDouble(args[0]) * PI / 180; double y = sin(x); out.println("sin(" + x + ") = " + y); } } Note 1. La directive import static se r ev` ele pr ecieuse pour simplier lemploi des types enum er es (cf. 12.1.1), puisque les valeurs de ces derniers sont des membres (implicitement) statiques. Par exemple, etant donn e le type public enum JourSemaine { LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE } dans un programme o` u on doit utiliser ces valeurs, l ecriture de la directive import static JourSemaine.*; permettra d ecrire LUNDI, MARDI, etc. au lieu de JourSemaine.LUNDI, JourSemaine.MARDI, etc. Note 2. Bien entendu, lemploi de import static fait r eappara tre le risque de conits de noms que l ecriture explicite des noms des classes cherchait ` a eviter. Il faut signaler cependant que ce risque est minimis e par le fait que le compilateur ne se d eclare en situation de conit que lorsquil est eectivement plac e devant un acc` es ` a une variable ou un appel de m ethode repr esentant pour lui une ambigu t e insoluble. Pour illustrer cette bonne volont e du compilateur, imaginez deux classes A et B ainsi d enies
c H. Garreta, 2000-2013

155

12.3

Quelques outils pour simplier la vie du programmeur

12

JAVA 5

public class A { public static void fon(int i) { ... } ... } public class B { public static void fon(float x) { ... } ... } Il est remarquable de constater que dans un chier qui comporte les deux lignes suivantes import static A.fon; // ou import static A.* import static B.fon; // ou import static B.* ... la m ethode fon sera trait ee comme une m ethode surcharg ee ordinaire : sur la rencontre dun appel comme fon(u), lune ou lautre d enition sera choisie selon le type de u. 12.3.2 Boucle for am elior ee

Une nouvelle construction, dite boucle for am elior ee , a et e ajout ee au langage dans le but dall eger l ecriture de deux sortes de boucles extr emement fr equentes : le parcours dun tableau et le parcours dune collection. 1 Si tableau est un tableau d el ements dun certain type TypeElement, qui peut etre un type primitif, un tableau ou une classe, la boucle for (int i = 0; i < tableau.length; i++) exploiter( tableau[i] ) peut s ecrire plus simplement : for (TypeElement elt : tableau) exploiter( elt ) 2 Si liste est une structure de donn ees susceptible d etre parcourue au moyen dun it erateur cest-` adire si liste impl emente la nouvelle interface java.lang.Iterable la boucle for (Iterator iter = liste.iterator(); iter.hasNext(); ) exploiter( (TypeElement )iter.next() ) peut s ecrire plus simplement : for (TypeElement elt : liste) exploiter( elt) Exemple 1. Pour illustrer le parcours dun tableau, voici un bout de code qui ache une matrice : double[][] matrice = new double[NL][NC]; ... acquisition des valeurs de la matrice ... for (double[] ligne : matrice) { for (double x : ligne) System.out.print(x + " "); // ou, plus malin : System.out.printf("%8.3f ", x); System.out.println(); } Exemple 2. Pour illustrer le parcours dune collection, voici un bout de code qui eectue un certain traitement sur chaque el ement dun vecteur donn e, en prenant soin de parcourir non pas le vecteur en question mais le r esultat du clonage 111 de ce dernier (notez que la sp ecication de la boucle for am elior ee garantit que lop eration v.clone() sera eectu ee une seule fois, en commen cant la boucle) : Vector v = new Vector(); ... for (Object o : (Vector) v.clone()) traitement(o);
111. Parcourir un clone au lieu de parcourir la structure elle-m eme para t bizarre, mais cest ce quon doit faire sil est possible que le traitement modie le vecteur par exemple, en lui ajoutant ou en lui supprimant des el ements.

156

c H. Garreta, 2000-2013

12

JAVA 5

12.3

Quelques outils pour simplier la vie du programmeur

Mise en garde. On peut trouver beaucoup de qualit es ` a la nouvelle boucle for am elior ee, mais il faut r ealiser quelle ne peut pas remplacer en toute circonstance la boucle for ordinaire, tout simplement parce quelle nore pas un acc` es (indice, pointeur, etc.) ` a la position dans la structure de l el ement en cours dexploitation. Ainsi, un code aussi simple que le suivant ne gagne pas en concision ni en ecacit e lorsquon le transforme an de l ecrire en utilisant la boucle for am elior ee : int i; ... for (i = 0; i < tab.length; i++) if ( condition( tab[i] ) ) break; utilisation de la valeur de i Objets it erables Peut-on parcourir ses propres structures avec la nouvelle boucle for am elior ee ? Autrement dit, quelle propri et e doit avoir un objet U pour pouvoir gurer dans une expression for ( d eclaration : U ) ? La r eponse est simple, il sut que notre objet impl emente linterface java.lang.Iterable : public interface Iterable<T> { Iterator<T> iterator(); } Par exemple, voici la d enition dune classe Intervalle 112 dont les instances repr esentent des intervalles de nombres entiers et peuvent, ` a ce titre, etre utilis ees dans des boucles for am elior ees 113 : public class Intervalle implements Iterable<Integer> { private int inf, sup; public Intervalle(int inf, int sup) { this.inf = inf; this.sup = sup; } public Iterator<Integer> iterator() { return new Iterator<Integer>() { private int pos = inf; public boolean hasNext() { return pos <= sup; } public Integer next() { return pos++; // emballage automatique } public void remove() { } }; } } Exemple demploi 114 (notez quil y a d eballage automatique des valeurs successivement produites par lit erateur, puisque i est d eclar ee int) : ... Intervalle plageDeNombres = new Intervalle(-5, 15); for (int i : plageDeNombres) System.out.print(i + " "); ... Achage obtenu : -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
112. Les amateurs de serpents reconna tront lobjet xrange du langage Python 113. Nous utilisons ici les types g en eriques cf. 12.5 Iterable<Integer> et Iterator<Integer> qui, avec le d eballage automatique quils induisent, rendent cet exemple plus int eressant. 114. Il sagit ici dun exemple purement d emonstratif. Pour parcourir les entiers compris entre deux bornes inf et sup il est sans doute plus ecace dutiliser une boucle for classique : for (int i = inf; i <= sup; i++) ...

c H. Garreta, 2000-2013

157

12.3

Quelques outils pour simplier la vie du programmeur

12

JAVA 5

12.3.3

M ethodes avec une liste variable darguments

Java 5 permet dappeler une m eme m ethode 115 avec un nombre darguments eectifs qui varie dun appel a un autre. Ces arguments variables doivent partager un type commun, qui peut ` etre une super-classe de leurs types eectifs. Dans la d eclaration de la m ethode, ce type commun doit appara tre suivi de trois points ... et un identicateur. Exemple : void afficherScores(int dossard, String nom, Number... scores) { corps de la m ethode } A lint erieur de la m ethode, lidenticateur associ e aux arguments variables (ici scores) est le nom dun tableau dont les el ements sont les arguments eectifs gurant dans lappel. Voici une ecriture possible de afficherScores : void afficherScores(int dossard, String nom, Number... scores) { System.out.println(nom + " dossard n " + dossard); for (int i = 0; i < scores.length; i++) System.out.println(" " + scores[i] + " points"); } Cette m ethode devra etre appel ee avec pour arguments un entier, une cha ne de caract` eres et un nombre quelconque dinstances de sous-classes de la classe Number. Par exemple : afficherScores(100, "Durand", new Integer(10)); afficherScores(101, "Dupond", new Integer(10), new Integer(15)); afficherScores(102, "Dubois", new Integer(10), new Long(15), new Double(20.5)); On peut ecrire les appels de cette m ethode plus simplement, en mettant ` a prot lemballage automatique (cf. 12.2) : afficherScores(102, "Dubois", 10, 15, 20.5); Dautre part, ce m ecanisme peut aussi etre utilis e avec des listes variables darguments de types primitifs. La d eclaration de la m ethode afficherScores aurait pu etre void afficherScores(int dossard, String nom, double... scores) { le corps de la m ethode reste le m eme } Remarque 1. Quand une m ethode comporte une liste variable darguments elle peut etre appel ee de deux mani` eres : en faisant correspondre ` a largument variable un certain nombre darguments individuels distincts (ayant des types compatibles avec la d eclaration), en faisant correspondre ` a largument variable un unique tableau (d el ements ayant un type compatible). Ainsi, les deux appels suivants sont equivalents : int[] tab = { 10, 20, 30, 25, 15 }; ... afficherScores(102, "Dubois", 10, 20, 30, 25, 15); afficherScores(102, "Dubois", tab); A lint erieur de la m ethode, rien ne permet de distinguer le premier appel du second. Remarque 2. La possibilit e davoir des listes variables darguments interf` ere manifestement avec le m ecanisme de la surcharge. Imaginez deux m ethodes distinctes avec les prototypes suivants : void calcul(int x, int y) { ... } void calcul(int... z) { ... } La question est : comment est r esolu un appel tel que que calcul(a, b) ? La r eponse ` a et e donn ee au 12.2.3 : le compilateur essaie dabord de r esoudre la surcharge sans prendre en compte les m ethodes avec liste variable darguments ; il ne consid` ere ces m ethodes que lorsquune telle r esolution echoue. Ici, lappel calcul(a, b) activera donc la premi` ere m ethode, tandis que des appels comme calcul(a) ou calcul(a, b, c) activeraient la deuxi` eme.
115. Attention, nous ne parlons pas ici de surcharge, cest-` a-dire de la possibilit e dappeler des m ethodes distinctes ayant le m eme nom, mais bien dappeler une m eme m ethode avec un nombre darguments qui di` ere dun appel ` a un autre.

158

c H. Garreta, 2000-2013

12

JAVA 5

12.3

Quelques outils pour simplier la vie du programmeur

12.3.4

Entr ees-sorties simpli ees : printf et Scanner

La m ethode printf Les vieux routiers de la programmation en C nen croiront pas leurs yeux : ` a loccasion de la version 5 on a incorpor e` a Java leur ch` ere fonction printf ! Mais oui ! Exemple (inutile mais d emonstratif) : ... double x = 123456; for (int i = 0; i < 8; i++) { System.out.printf("%03d | %12.4f |%n", i, x); x /= 10; } ... Achage obtenu : 000 001 002 003 004 005 006 007 | | | | | | | | 123456,0000 12345,6000 1234,5600 123,4560 12,3456 1,2346 0,1235 0,0123 | | | | | | | |

La m ethode printf appartient aux classes PrintStream (ux doctets en sortie repr esentant des donn ees mises en forme) et PrintWriter (ux de caract` eres en sortie repr esentant des donn ees mises en forme). Dans les deux cas il y en a deux versions : public uxEnQuestion printf(Locale locale, String format, Object... args); public uxEnQuestion printf(String format, Object... args); La premi` ere forme permet de pr eciser quelles particularit es locales doivent etre employ ees, la deuxi` eme utilise les particularit es locales courantes. Dans tous les cas la m ethode renvoie comme r esultat le ux sur lequel elle a et e appel ee (cela permet les cascades, genre : ux .printf(...).printf(...)). Largument format est une cha ne compos ee de caract` eres ordinaires, qui seront simplement recopi es dans le ux de sortie, parmi lesquels se trouvent un certain nombre de sp ecications de format qui indiquent comment faut-il mettre en forme les donn ees, repr esent ees par largument variable args, plac ees ` a la suite de largument format. Les sp ecications de format se pr esentent ainsi (les crochets expriment le caract` ere facultatif de ce quils encadrent) : %[drapeau ][largeur ][.precision ]type Les principaux drapeaux sont - : commande le cadrage ` a gauche, + : pr ecise que les donn ees num eriques doivent toujours avoir un signe, espace : indique que les nombres positifs doivent etre pr ec ed es dun blanc, 0 : sp ecie que les espaces libres pr ec edant les nombres doivent etre remplis avec 0, Largeur et pr ecision sont des entiers : le premier pr ecise le nombre total de caract` eres que la donn ee doit occuper une fois mise en forme ; le second le nombre de chires apr` es la virgule. Les principales indications de type sont : %% : pour indiquer le caract` ere % %b, %B : pour acher un bool een sous la forme false, true [resp. FALSE, TRUE]. %c, %C : pour acher un caract` ere dont la donn ee correspondante (qui doit etre de type Byte, Short, Character ou Integer) exprime le code interne. %d : pour acher un entier ecrit en base 10. %e, %E : pour acher un nombre ottant en notation exponentielle. %f : pour acher un nombre ottant sans utiliser la notation exponentielle. %g, %G : pour acher un nombre ottant avec la notation qui convient le mieux ` a sa valeur. %n : pour acher lindicateur de n de ligne de la plate-forme utilis ee (cest plus able que \n).
c H. Garreta, 2000-2013

159

12.3

Quelques outils pour simplier la vie du programmeur

12

JAVA 5

%s, %S : pour acher une cha ne de caract` eres. %x, %X : pour acher un nombre en hexad ecimal. Il y a aussi de nombreuses pas moins de 32 ! sp ecications de format concernant la date et lheure. Vous trouverez toutes les informations sur la m ethode printf dans la documentation de lAPI, ` a loccasion de la classe java.util.Formatter. La classe Scanner La classe java.util.Scanner est faite de m ethodes pour lire simplement un ux de donn ees format ees. Ensemble, ces m ethodes rendent le m eme genre de services que la fonction scanf bien connue des programmeurs C. On construit un objet Scanner au-dessus dun ux doctets ou de caract` eres pr ealablement ouvert ; dans le cas le plus simple de la lecture ` a la console, ce ux est System.in. Les m ethodes de la classe Scanner les plus int eressantes sont certainement : byte nextByte() Lecture de la prochaine valeur de type byte (cest-` a-dire : consommation de tous les caract` eres se pr esentant dans le ux dentr ee qui peuvent faire partie dune donn ees de ce type, construction et renvoi de la valeur correspondante). short nextShort() Lecture de la prochaine valeur de type short. int nextInt() Lecture de la prochaine valeur de type int. long nextLong() Lecture de la prochaine valeur de type long. float nextFloat() Lecture de la prochaine valeur de type float. double nextDouble() Lecture de la prochaine valeur de type double. String nextLine() Lecture de tous les caract` eres se pr esentant dans le ux dentr ee jusqu` a une marque de n de ligne et renvoi de la cha ne ainsi construite. La marque de n de ligne est consomm ee, mais nest pas incorpor ee a la cha ` ne produite. BigInteger nextBigInteger() Lecture du prochain grand entier. BigDecimal nextBigDecimal() Lecture du prochain grand d ecimal. Exemple tr` es simple : public class TestScanner { public static void main(String[] args) { Scanner entree = new Scanner(System.in); System.out.print("nom et pr enom? "); String nom = entree.nextLine(); System.out.print("^ age? "); int age = entree.nextInt(); System.out.print("taille (en m)? "); float taille = entree.nextFloat(); System.out.println("lu: " + nom + ", " + age + " ans, " + taille + " m"); } } Ex ecution de ce programme : 160
c H. Garreta, 2000-2013

12

JAVA 5

12.4

Annotations

nom et pr enom? Tombal Pierre age? 32 ^ taille (en m)? 1,72 lu: Tombal Pierre, 32 ans, 1.72 m Erreurs de lecture. Les erreurs lors de la lecture de donn ees sont des fautes que le programmeur ne peut pas eviter, quel que soit le soin apport e` a la conception de son programme. Il doit donc se contenter de faire le n ecessaire pour les d etecter lors de lex ecution et y r eagir en cons equence. En Java cela passe par le m ecanisme des exceptions : ... double x = 0; for (;;) { System.out.print("Donnez x: "); try { x = entree.nextDouble(); break; } catch (InputMismatchException ime) { entree.nextLine(); System.out.println("Erreur de lecture - Recommencez"); } } System.out.print("x = " + x); ... Remarquez, dans lexemple pr ec edent, comment dans le cas dune erreur de lecture il convient de nettoyer le tampon dentr ee (cest le r ole de linstruction entree.nextLine();) an que la tentative suivante puisse se faire avec un tampon vide. sence de donne es. La classe Scanner ore aussi toute une s Tests de pre erie de m ethodes bool eennes pour tester le type de la prochaine donn ee disponible, sans lire cette derni` ere : boolean hasNext() Y a-t-il une donn ee disponible pour la lecture ? boolean hasNextLine() Y a-t-il une ligne disponible pour la lecture ? boolean hasNextByte() La prochaine donn ee ` a lire est-elle de type byte ? boolean hasNextShort() La prochaine donn ee ` a lire est-elle de type short ? boolean hasNextInt() La prochaine donn ee ` a lire est-elle de type int ? boolean hasNextLong() La prochaine donn ee ` a lire est-elle de type long ? boolean hasNextFloat() La prochaine donn ee ` a lire est-elle de type float ? boolean hasNextDouble() La prochaine donn ee ` a lire est-elle de type double ? boolean hasNextBigInteger() La prochaine donn ee ` a lire est-elle un grand entier ? boolean hasNextBigDecimal() La prochaine donn ee ` a lire est-elle un grand d ecimal ?

12.4
12.4.1

Annotations
Principe

Les annotations , on dit aussi m eta-donn ees, sont un m ecanisme permettant daccrocher des informations p eriph eriques aux classes et m ethodes. Ces informations ne modient pas la s emantique des programmes, mais sadressent ` a des outils qui auraient ` a manipuler ces derniers. Pour cette raison, les annotations ne disparaissent pas lors de la compilation 116 ; au contraire, elles sont reconnues et trait ees par le compilateur
116. Cela est une di erence notable entre les annotations et, par exemple, les commentaires de documentation (adress es a ` loutil javadoc) dont il ne reste aucune trace apr` es la compilation.

c H. Garreta, 2000-2013

161

12.4

Annotations

12

JAVA 5

et sont conserv ees avec les classes produites sauf instruction contraire. En contrepartie, cela les oblige ` a ob eir ` a une syntaxe aussi contraignante que celle des programmes. Pour pouvoir etre utilis ees, les annotations doivent dabord etre d eclar ees par un texte, d enissant ce quon appelle un type annotation, qui est bizarrement voisin dune d eclaration dinterface : public @interface nomTypeAnnotation { d eclaration des el ements de lannotation } Les el ements dune annotation sont des donn ees, analogues ` a des variables nales (i.e. des constantes), mais il faut les d eclarer par des expressions qui ressemblent ` a des d eclarations de m ethodes : type nomElement (); avec la particularit e quon peut indiquer une valeur par d efaut : type nomElement () default valeur ; Par exemple, voici un type annotation ` a quatre el ements destin ee ` a signaler les m ethodes dune classe dont on estime quelles peuvent etre am elior ees : public @interface AmeliorationRequise { int identification(); String synopsis(); String auteur() default "(plusieurs)"; String date() default "non indiqu ee"; } Lorsquun type annotation a un seul el ement, celui-ci doit se nommer value : public @interface Copyright { String value(); } Enn, un type annotation peut aussi navoir aucun el ement ; elle est alors dite annotation de marquage (marker annotation ) : public @interface Test { } Voici une classe dont les m ethodes ont et e annot ees en utilisant les trois types annotations pr ec edents. Notez que dans le cas dune annotation ` a un seul el ement, on peut ecrire annotation (valeur ) au lieu de annotation (value = valeur ) dans le cas dune annotation sans el ements, on peut ecrire annotation au lieu de annotation () public class ObjetAnnote { @Test public void unePremiereMethode(arguments ) { corps de la m ethode } @Copyright("Editions Dupuis, 2004") public void uneAutreMethode(arguments ) { corps de la m ethode } @AmeliorationRequise(identification = 80091, synopsis = "Devrait ^ etre interruptible", date = "11/09/2004") // ici auteur aura la valeur "(plusieurs)" public void uneTroisiemeMethode(arguments ) { corps de la m ethode } autres m ethodes }

162

c H. Garreta, 2000-2013

12

JAVA 5

12.4

Annotations

12.4.2

Exploitation des annotations

A lex ecution, lacc` es aux annotations port ees par un ex ecutable (ensemble de classes) se fait ` a travers les m ethodes de linterface java.lang.AnnotatedElement, dont voici une d enition succincte : package java.lang.reflect; public interface AnnotatedElement { // renvoie un tableau contenant toutes les annotations port ees par cet el ement : Annotation[] getAnnotations(); // renvoie le tableau des annotations faites directement (non h erit ees) sur cet el ement : Annotation[] getDeclaredAnnotations(); // renvoie true si et seulement si cet el ement porte une annotation ayant le type indiqu e: boolean isAnnotationPresent(Class<? extends Annotation> annotationType); // renvoie lannotation de cet el ement ayant le type indiqu e, ou null si elle nexiste pas <T extends Annotation> T getAnnotation(Class<T> annotationType); } Bien entendu, cette interface est d esormais impl ement ee par la plupart des classes qui constituent le m ecanisme de la r eexion de Java (cf. 9.3) : Class, Constructor, Field, Method, Package, etc. Un exemple est montr e` a la n de la section 12.4.1. Voyons cela ` a travers deux exemples simples : Exemple 1. Le programme suivant essaie toutes les m ethodes portant lannotation Test dans une classe quelconque, donn ee par son nom (en supposant que toutes ces m ethodes sont statiques et sans argument) ; le point important dans cet exemple est la m ethode isAnnotationPresent : import java.lang.reflect.*; public class ExecuterTests { public static void main(String[] args) throws ClassNotFoundException { int nbrSucces = 0; int nbrEchecs = 0; for (Method uneMethode : Class.forName(args[0]).getMethods()) { if (uneMethode.isAnnotationPresent(Test.class)) { try { uneMethode.invoke(null); nbrSucces++; } catch (Throwable ex) { System.out.println("Test " + uneMethode + " echec: " + ex.getCause()); nbrEchecs++; } } } System.out.println(nbrSucces + " succ` es et " + nbrEchecs + " echecs"); } }

Exemple 2. Le programme suivant ache les valeurs de toutes les propri et es de toutes les annotations attach ees ` a toutes les m ethodes dune classe donn ee par son nom : import java.lang.annotation.Annotation; import java.lang.reflect.Method;

c H. Garreta, 2000-2013

163

12.4

Annotations

12

JAVA 5

public class MethodesAnnotees { public static void main(String[] args) throws Exception { Method[] methodes = Class.forName(args[0]).getMethods(); for (Method uneMethode : methodes) { Annotation[] annotations = uneMethode.getAnnotations(); if (annotations.length > 0) { System.out.println(uneMethode.getName()); for (Annotation uneAnnotation : annotations) { Class type = uneAnnotation.annotationType(); System.out.println(" " + type.getName()); for (Method propr : type.getDeclaredMethods()) System.out.println(" " + propr.getName() + " : " + propr.invoke(uneAnnotation)); } } } } } Par exemple, sil etait appel e avec pour argument le nom de la classe ObjetAnnote montr ee ` a la page 162, ce programme acherait : unePremiereMethode Test uneAutreMethode Copyright value : Editions Dupuis, 2004 uneTroisiemeMethode AmeliorationRequise identification : 80091 synopsis : Devrait ^ etre interruptible auteur : (plusieurs) date : 11/09/2004 12.4.3 Annotations pr ed enies

Un petit nombre (appel e` a grandir ?) dannotations sont pr ed enies et peuvent etre utilis ees sans autre pr ecaution : @Deprecated Le compilateur achera un avertissement lors de tout emploi dun membre ainsi annot e 117 . @Override Indique que la m ethode ainsi annot ee doit red enir une m ethode h erit ee : si tel nest pas le cas, un message derreur sera produit par le compilateur. @SuppressWarnings("type davertissement ") Demande au compilateur de ne pas produire une certaine sorte de messages davertissement durant la compilation de l el ement de code ainsi annot e. Par exemple, cette annotation permet que le clonage dun vecteur g en erique puisse se faire en silence 118 : Vector<String> a = new Vector<String>(); ... @SuppressWarnings("unchecked") Vector<String> b = (Vector<String>) a.clone(); ...

12.4.4

M eta-annotations

Les annotations d enies par lutilisateur peuvent etre annot ees ` a leur tour, par des annotations appel ees alors m eta-annotations. Les types des m eta-annotations sont pr ed enis ; ` a lheure actuelle il y en a quatre :
117. Lannotation @Deprecated rend donc un service qui etait assur e pr ec edemment par la marque @deprecated ecrite dans un commentaire /** ... */ ` a ladresse de loutil javadoc. 118. A propos des conversions unchecked voir lexplication des types bruts ` a la section 12.5.2

164

c H. Garreta, 2000-2013

12

JAVA 5

12.5

G en ericit e

@Documented Indique que lannotation que cette m eta-annotation annote doit etre prise en compte par loutil javadoc et dautres outils similaires, comme cela est fait pour les autres el ements (classes, interfaces, etc.) qui composent le programme source. @Inherited Indique que lannotation concern ee est automatiquement h erit ee. Si un membre est ainsi annot e et ses descendants (sous-classes, m ethodes red enies, etc.) ne le sont pas, alors ces derniers prendront automatiquement cette annotation. @Retention Indique jusqu` a quel point du processus de d eveloppement lannotation concern ee doit etre conserv ee. Les valeurs possibles sont RetentionPolicy.SOURCE : lannotation sera elimin ee par le compilateur (lequel aura cependant vu lannotation, contrairement ` a ce qui arrive pour un commentaire), RetentionPolicy.CLASS : le compilateur laissera lannotation dans la classe compil ee mais la machine virtuelle l eliminera lors du chargement de la classe, RetentionPolicy.RUNTIME : lannotation sera conserv ee dans la classe compil ee et retenue par la machine virtuelle, si bien quelle sera accessible par les m ecanisme de la r eexion pendant lex ecution du programme. La valeur par d efaut est RetentionPolicy.CLASS. @Target Indique sur quel type d el ement lannotation porte. Plusieurs types peuvent etre indiqu es en m eme temps (la valeur de cette m eta-annotation est un tableau de tels types). Les types possibles sont ElementType.ANNOTATION_TYPE : type annotation, ElementType.CONSTRUCTOR : constructeur, ElementType.FIELD : champ (variable dinstance), ElementType.LOCAL_VARIABLE : variable locale, ElementType.METHOD : m ethode, ElementType.PACKAGE : paquetage, ElementType.PARAMETER : param` etre dune m ethode, ElementType.TYPE : classe, interface ou type enum eration (enum). La valeur par d efaut est tous les types.

12.5

G en ericit e

Embl ematique de Java 5, la g en ericit e est peut- etre la plus importante des extensions du langage faites ` loccasion de cette version. Il sagit dobtenir en Java rien moins que les services que rendent les templates a en C++, cest-` a-dire la possibilit e de d enir et demployer des classes et des m ethodes param etr ees par des types qui interviennent dans leur d enition. Par exemple, une classe Truc etant d enie par ailleurs, cela nous permettra de d eclarer une collection v comme etant de type liste de trucs (cela s ecrira List<Truc>) au lieu du simple type List, cest-` a-dire liste dobjets quelconques. Les b en eces obtenus sont faciles ` a entrevoir : lors dajouts d el ements ` a v, la v erication que ceux-ci sont bien de type Truc, lors dacc` es ` a des el ements de v, la certitude que les objets obtenus sont de type Truc. Voici ` a quoi cela ressemblera : // d eclaration et cr eation de la liste List<Truc> liste = new Vector<Truc>(); ... // remplissage de la liste for (int i = 0; i < n; i++) { liste.add(expression ); // ici il est contr ol e que expression est un Truc } ... // exploitation des el ements de la liste for (int i = liste.size() - 1; i >= 0; i--) { Truc q = liste.get(i); // pas besoin de conversion, ce qui sort de la liste // est connu comme etant de type Truc exploitation du truc q } En permettant aux compilateurs deectuer des contr oles de type nombreux et ns, la g en ericit e augmente signicativement la qualit e et la abilit e des programmes. H elas, dans certains langages elle en augmente aussi la complication, parfois de mani` ere consid erable. On apprendra donc avec soulagement quen Java :
c H. Garreta, 2000-2013

165

12.5

G en ericit e

12

JAVA 5

la g en ericit e est totalement prise en charge au moment de la compilation et nentra ne aucune modication de la machine java, la g en ericit e est totalement compatible avec le langage pr eexistant : l` a o` u un objet ` a lancienne est attendu on peut mettre une instance dune classe g en erique, et r eciproquement 119 . 12.5.1 Classes et types param etr es

Pour commencer il nous faut trois nouveaux concepts : 1 Une classe param etr ee est une d eclaration de classe dans laquelle le nom de la classe est suivi des signes < > encadrant une liste de types param` etres ( eventuellement) contraints s epar es, lorsquil y en a plusieurs, par des virgules. Exemple : class Machin<A, B extends Number, C extends Collection & Cloneable> { ... } Comme on le devine ci-dessus, les contraintes, lorsquelles existent, sont de la forme (les crochets signalent le caract` ere facultatif de ce quils encadrent) : extends classeOuInterface [ & interface ... & interface ] cette expression doit etre comprise, selon que classseOuInterface est une classe ou une interface, respectivement comme extends classe implements interface, ... interface ou bien comme implements interface, interface, ... interface 2 Les types variables (ou types param` etres ) sont les identicateurs constituant la liste des types param` etres dune classe param etr ee (A, B et C 120 dans lexemple pr ec edent). A lint erieur de la classe, cest-` a-dire dans les d enitions de ses membres, ces identicateurs jouent le r ole de types. Exemple : public class Machin<A, B extends Number, C extends Collection & Cloneable > { A descripteur; B valeur; C listeTransactions; public Machin(A descripteur, B valeur) { this.descripteur = descripteur; this.valeur = valeur; ... } ... } 3 Un type param etr e est le nom dune classe param etr ee suivi des signes < > encadrant une liste de vrais types. Cela repr esente donc le choix dun el ement dans lensemble (inni) de types d eni par la classe param etr ee. De telles formules apparaissent le plus souvent dans des d eclarations de variables et de m ethodes. Exemple 121 : Machin<String, Integer, Vector<Truc>> unMachin = new Machin<String, Integer, Vector<Truc>>("un exemple", 100); Attention. Lop eration consistant ` a produire un type param etr e` a partir dune classe param etr ee (en rempla cant les types param` etres par des types eectifs) est souvent appel ee instanciation de la classe param etr ee. On prendra garde ` a lambigu t e ainsi introduite, ce terme d esignant aussi la cr eation dun objet ` a partir [dun constructeur] de sa classe :
119. Assez souvent cela entra nera un avertissement de la part du compilateur (il vous dira que votre programme uses unchecked or unsafe operations ), mais pas un diagnostic derreur. 120. La recommandation ocielle est de donner ` a ces types param` etres des noms tr` es courts, en majuscules et sans signication : A, B, C ou T1, T2, T3, etc. Cela an qu` a lint erieur dune classe param etr ee on puisse distinguer du premier coup dil les types param` etres des vrais types, qui ont g en eralement des noms signicatifs, et des membres, qui sont ecrits plut ot en minuscules. 121. Les programmeurs C++ noteront avec plaisir que le compilateur Java ne prend pas toujours deux > cons ecutifs pour une occurrence de lop erateur >>. Mais oui, lhumanit e progresse !

166

c H. Garreta, 2000-2013

12

JAVA 5

12.5

G en ericit e

new Integer(1000) : instanciation de la classe Integer ; le r esultat est un objet, Vector<Integer> : instanciation de la classe param etr ee Vector<E> ; le r esultat est une classe. Ce discours devient critique lorsque ces deux op erations sont invoqu ees dans la m eme expression : new Vector<Integer>() : instanciation de la classe param etr ee Vector<E> et instanciation de la classe ainsi obtenue. Utilisation des classes param etr ees On laura compris, le plus beau domaine dutilisation des classes et types param etr es est celui des collections. On ne s etonnera donc pas, en consultant la documentation de lAPI, de d ecouvrir que toutes les interfaces et les classes collections de la biblioth` eque ont et e remplac ees par une nouvelle forme param etr ee, Collection<E>, Vector<E>, Iterator<E>, etc. Ces nouvelles classes se combinent tr` es bien avec lemballage/d eballage automatiques (cf. section 12.2) et permettent l ecriture de programmes plus simples et plus ables que par le pass e. Voici un exemple que nous avons d ej` a montr e : le programme suivant compte le nombre dapparitions de chaque mot donn e dans la ligne de commande. En introduisant une table associative (objet Map) dont les cl es sont n ecessairement des cha nes de caract` eres et les valeurs n ecessairement des Integer le programmer augmente sensiblement la abilit e de son programme : import java.util.*; public class Frequence { public static void main(String[] args) { Map<String, Integer> tableAssoc = new TreeMap<String, Integer>(); for (String mot : args) { Integer freq = tableAssoc.get(mot); tableAssoc.put(mot, freq == null ? 1 : freq + 1); } System.out.println(tableAssoc); } } Pour montrer la d enition dune classe param etr ee, voici celle de la classe Paire dont les instances repr esentent des paires de choses : public class Paire<P, S> { private P premier; private S second; public Paire(P premier, S second) { this.premier = premier; this.second = second; } public P getPremier() { return premier; } public S getSecond() { return second; } public String toString() { return "<" + premier + "," + second + ">"; } public Paire<S, P> swap() { return new Paire<S, P>(second, premier); }

c H. Garreta, 2000-2013

167

12.5

G en ericit e

12

JAVA 5

public static <A, B> Paire<A, B> makeInstance(A premier, B second) { return new Paire<A, B>(premier, second); } ... } 12.5.2 Types bruts

Comme il a et e dit, pour ce qui est de la g en ericit e, Java 5 est compatible avec les versions pr ec edentes du langage. Il faut donc que les nouvelles classes param etr ees puissent etre utilis ees par des programmes qui ne pratiquent pas la g en ericit e et, inversement, il faut que danciennes classes d ej` a ecrites puissent etre employ ees dans des programmes qui exploitent massivement la g en ericit e. Cest pourquoi toute classe param etr ee est consid er ee par le compilateur comme compatible avec sa version sans param` etres, appel ee le type brut (raw type ) correspondant ` a la classe param etr ee. Par exemple, Paire est le type brut associ e` a la classe param etr ee Paire<P, S>. Ainsi, avec la classe d enie ci-dessus, les quatre lignes suivantes sont accept ees par le compilateur ... Paire<String, Number> p1 = new Paire<String, Number>("un", 1); Paire<String, Number> p2 = new Paire("deux", 2); Paire p3 = new Paire<String, Number>("trois", 3); Paire p4 = new Paire("quatre", 4); ... A lessai on constate que les lignes concernant p2 et p4 donnent lieu ` a un avertissement signalant un appel sans contr ole du constructeur de la classe Paire<P, S>. Dans le cas de p2, le compilateur est egalement chagrin e en constatant une aectation sans contr ole 122 de p2 (d eclar e de type Paire<P, S>) par un objet du type brut Paire. On peut supprimer ces messages davertissement (apr` es avoir acquis la certitude quils ne signalent pas une erreur) en utilisant une annotation @SuppressWarnings comme expliqu e` a la section 12.4 : ... @SuppressWarnings("unchecked") Paire<String, Number> p2 = new Paire("deux", 2); ... Note. A lex ecution tous les types param etr es construits au-dessus dun m eme type brut sont consid er es comme d enissant la m eme classe. Par exemple, le code suivant ache true : ... Paire<String, Number> a = new Paire<String, Number>(...); Paire<Point, Rectangle> b = new Paire<Point, Rectangle>(...); ... System.out.println(a.getClass() == b.getClass()); ... 12.5.3 Types param etr es et jokers

La g en ericit e est une notion plus complexe quil ny para t, il faut de la prudence y compris dans des situations qui paraissent pourtant evidentes. Par exemple, si la classe Chat est une sous-classe de la classe Mammifere, il semble naturel de penser que List<Chat> est une sous-classe de List<Mammifere> (si un chat est une sorte de mammif` ere alors une liste de chats est une sorte de liste de mammif` eres, cela para t clair !). Cest pourtant compl` etement erron e. Pour le voir il sut de se rappeler que A sous-classe de B signie tout ce quon peut demander ` a un B on peut le demander ` a un A . Or, il y a des choses quon peut demander ` a une liste de mammif` eres et pas ` a une liste de chats : par exemple, linsertion dun chien. Pour etre plus pr ecis, supposons que des classes Animal, Mammifere, Chat et Chien aient et e d enies, avec les relations dh eritage que leurs noms sugg` erent : class Animal { ... }
122. Cette aectation est sans contr ole parce que les concepteurs de Java 5 ont voulu que la g en ericit e soit trait ee durant la compilation et quelle ne modie ni le code produit ni la machine virtuelle. Si la g en ericit e avait et e trait ee ` a lex ecution il aurait et e facile de contr oler de telles op erations.

168

c H. Garreta, 2000-2013

12

JAVA 5

12.5

G en ericit e

class Mammifere extends Animal { ... } class Chat extends Mammifere { ... } class Chien extends Mammifere { ... } Consid erons dautre part une m ethode qui prend pour argument une liste de mammif` eres : void uneMethode(List<Mammifere> menagerie) { ... } et envisageons divers appels possibles de cette m ethode : void uneAutreMethode() { List<Animal> listeAnimaux = new Vector<Animal>(); List<Mammifere> listeMammiferes = new Vector<Mammifere>(); List<Chat> listeChats = new Vector<Chat>(); code qui ins` ere des el ements dans les listes pr ec edentes uneMethode(listeMammiferes); uneMethode(listeAnimaux); uneMethode(listeChats); } Lappel (a) est correct. Lappel (b) est erron e et ce nest pas une surprise : une liste danimaux pouvant contenir des poissons ou des oiseaux ne peut pas prendre la place dune liste de mammif` eres. Ce qui est peut- etre surprenant est que lappel (c) soit incorrect egalement : pour comprendre pourquoi il sut de r ealiser que uneMethode peut contenir linstruction (l egitime, dapr` es la d eclaration de menagerie) : menagerie.add(new Chien()); Ce serait tout ` a fait incoh erent de laisser faire lajout dun chien dans une liste de chats ! Jokers Bon, daccord, une liste de chats nest pas une liste de mammif` eres. Mais alors, comment faire pour quune m ethode puisse prendre pour argument aussi bien une liste de mammif` eres quune liste de chats, ou une liste de chiens, etc. ? Ou bien, comment signier que largument dune m ethode est, par exemple, une liste dune sorte de mammif` eres ? Les syntaxes nouvelles ? (signiant une classe quelconque) et ? extends uneClasse (signiant une sous-classe quelconque de uneClasse ) ont et e introduites ` a cet eet. Exemple : void uneMethode(List<? extends Mammifere> menagerie) { ... } Maintenant, lappel (c) qui posait probl` eme est devenu l egal : void uneAutreMethode() { ... uneMethode(listeMammiferes); uneMethode(listeAnimaux); uneMethode(listeChats); ... } (a) (b) (c) OK ERREUR ERREUR

// OK // ERREUR // OK

Evidemment, si lappel ci-dessus est accept e cest que la notation <? extends Mammifere> impose des contraintes additionnelles. Ainsi, ` a lint erieur de uneMethode, la liste menagerie sera consid er ee comme un objet en lecture seule et toute modication de la liste sera interdite :

c H. Garreta, 2000-2013

169

12.5

G en ericit e

12

JAVA 5

void uneMethode(List<? extends Mammifere> menagerie) { ... Mammifere mam = menagerie.get(i); // Pas de probl` eme : ce qui sort de la liste peut ... // certainemnt etre vu comme un Mammifere menagerie.add(new Chien()); ... } Sym etrique de la pr ec edente, la syntaxe nouvelle ? super uneClasse (signiant une super-classe quelconque de uneClasse ) permet, par exemple, de d enir des listes quon pourra modier ` a laide dobjets de type uneClasse : void uneTroisiemeMethode(List<? super Mammifere> menagerie) { ... } Les appels l egitimes ne seront pas les m emes que pr ec edemment : void uneAutreMethode() { ... uneTroisiemeMethode(listeMammiferes); uneTroisiemeMethode(listeAnimaux); uneTroisiemeMethode(listeChats); ... } // ERREUR (ben oui, menagerie est peut- etre // une liste de chats... !)

// OK // OK // ERREUR

Ce quil est permis de faire ` a lint erieur de la m ethode change aussi : void uneTroisiemeMethode(List<? super Mammifere> menagerie) { ... Mammifere mam = menagerie.get(i); // ERREUR ( menagerie est peut- etre ... // une liste de simples animaux) ... menagerie.add(new Chien()); // Pas de probl` eme : un chien peut certainement ... // prendre la place dun el ement de menagerie } 12.5.4 Limitations de la g en ericit e

Cette section obscure et incertaine peut etre ignor ee en premi` ere lecture. Contrairement ` a dautres langages, comme C++, o` u les classes g en eriques sont instanci ees dabord et compil ees ensuite, en Java les classes g en eriques sont compil ees dabord et pour autant que cela veuille dire quelque chose instanci ees plus tard. Dautre part, on nous assure que la machine virtuelle Java na pas subi la moindre modication lors de lintroduction de la g en ericit e dans le langage. Cela explique pourquoi certaines op erations impliquant des types param` etres sont possibles, et dautres non. Pour le dire simplement : un type param` etre T ne peut etre employ e que pour ecrire des expressions qui peuvent etre compil ees sans conna tre les d etails pr ecis (structure, taille, m ethodes...) du type que T repr esente 123 . Ainsi, un type param` etre peut etre utilis e: dans des d eclarations de membres, de variables locales ou darguments formels, dans des conversions de type (casts ). En revanche, un type param` etre ne peut pas etre employ e en repr esentation dun type primitif, comme type des el ements dans la d enition dun tableau, intervenant dans la d enition dun membre statique, en position de constructeur dune classe, comme dans new T() , dans une comparaison comme T == une classe dans le r ole dun objet (instance de la classe Class), comme dans T.getName() A titre dexemple, voici quelques bons et mauvais usages des types param` etres :
123. Si cela vous aide, dites-vous que le code produit par la compilation dune classe param etr ee est le m eme que celui quon aurait obtenu si on avait remplac e tous les types param` etres par Object en faisant abstraction des avertissements et erreurs ` a propos des types que cela aurait soulev e.

170

c H. Garreta, 2000-2013

12

JAVA 5

12.5

G en ericit e

public class Zarbi<T> { T x; static T y; Zarbi<Integer> z; Zarbi<int> t; public T getX() { return x; } public Zarbi(Object o) { x = (T) o; } public Zarbi() { x = new T(); } public boolean estOk(Object x) { return x.getClass() == T; } } // Pas de probl` eme // *** ERREUR *** // OK // *** ERREUR *** // Tr` es bien

// Parfait (du moins pour la compilation)

// *** ERREUR ***

// *** ERREUR ***

12.5.5

M ethodes g en eriques

Comme les classes param etr ees, les m ethodes peuvent elles aussi d ependre dune liste de types param` etres. Ces param` etres, encadr es par les signes < >, doivent etre plac es imm ediatement devant le type du r esultat de la m ethode, selon le sch ema suivant : qualieurs < types-param` etres > type-du-r esultat nom-m ethode ( arguments ) Par exemple, la m ethode suivante prend pour arguments une liste dobjets dun certain type T, un type inconnu durant la compilation, et renvoie l el ement qui est au milieu de la liste ; largument est donc de type List<T> et le r esultat de type T :

public static <T> T elementCentral(List<T> liste) { int n = liste.size(); if (n > 0) return liste.get(n / 2); else return null; } Tr` es souvent 124 , les types param` etres des m ethodes g en eriques apparaissent dans les types de leurs arguments formels (cest le cas dans la m ethode ci-dessus). Elles ont alors cette particularit e : pour les instancier il sut de les appeler ; le compilateur d eduit les types param` etres des arguments eectifs gurant dans lappel. Exemples dappels de la m ethode pr ec edente (les variables i et s ont et e d eclar ees par ailleurs) :

124. Il nest pas formellement requis que les types param` etres dune m ethode param etr ee apparaissent dans les d eclarations des arguments. Cependant, ` a lusage, on saper coit que cela est une obligation de fait pour obtenir des m ethodes correctes et utiles.

c H. Garreta, 2000-2013

171

12.5

G en ericit e

12

JAVA 5

Vector<Integer> v = new Vector<Integer>(); LinkedList<String> ll = new LinkedList<String>(); ... ajout de valeurs aux listes v et ll ... i = elementCentral(v); s = elementCentral(ll); ... Sans quil ait fallu lindiquer explicitement, lors du premier appel de la m ethode elementCentral le compilateur aura pris T Integer et, lors du deuxi` eme, T String. Un autre exemple de m ethode g en erique a et e donn ee par la m ethode makeInstance de la classe Paire (cf. page 167) : public class Paire<P, S> { private P premier; private S second; public Paire(P premier, S second) { this.premier = premier; this.second = second; } public static <A, B> Paire<A, B> makeInstance(A premier, B second) { return new Paire<A, B>(premier, second); } ... } Avec cela, nous avons deux mani` eres de construire des paires dobjets : soit en explicitant les types des membres de la paire (la variable p a et e d eclar ee par ailleurs) : p = new Paire<Double, String>(246.5, "Km"); soit en laissant le compilateur d eduire ces types des arguments dun appel de makeInstance : p = Paire.makeInstance(246.5, "Km");

172

c H. Garreta, 2000-2013

Index
+ (concat enation de cha nes), 22 .TYPE, 74 .class, 74 = (copie supercielle), 18 == (comparaison supercielle), 21 abs, 63 abstract, 52, 53 AbstractCollection, 67 AbstractList, 67 AbstractMap, 68 AbstractSequentialList, 67 AbstractSet, 68 AbstractTableModel, 135 abstraite (classe), 53 abstraite (m ethode), 52 acos, 64 ActionListener, 112 actionPerformed, 112 Adaptateurs, 109 add, 71 addActionListener, 127 addMouseListener, 108 AdjustmentListener, 114 adjustmentValueChanged, 114 aiguillage et type enum er e, 151 algorithme, 71 analyse lexicale, 82 annotations, 161 anonyme (classe), 40 anonyme (tableau), 16 appendReplacement, 93 appendTail, 93 arguments variables, 158 Array, 74 ArrayIndexOutOfBoundsException, 14 ArrayList, 67, 73 Arrays, 73 asin, 64 asList, 73 assert, 60 AssertionError, 60 atan, 64 atan2, 64 auditeur d ev enements, 107 AWT, 100 base (classe de), 42 BigDecimal, 65 BigInteger, 64 binarySearch, 7274 bo te de dialogue, 102 bool enne (constante), 10 Boolean, 63 boolean, 11 BorderFactory, 125 BorderLayout, 122 boucle for am elior ee, 156 break, 24 brut (type), 168 buered image, 145 BufferedInputStream, 76 BufferedOutputStream, 76 BufferedReader, 77 BufferedWriter, 78 Byte, 62 byte, 11 ByteArrayInputStream, 76 ByteArrayOutputStream, 76 caract` ere, 10 case, 151 catch, 57 ceil, 63 CENTER, 122 cha ne de caract` eres (constante), 22 char, 11 Character, 63 CharArrayReader, 77 CharArrayWriter, 78 class, 29 classe, 29 classe d eriv ee, 42 classe de base, 42 clearRect, 116 clonage, 18 clone, 18 Cloneable, 19 CloneNotSupportedException, 19 Collection, 53, 66, 70 Collections, 71 commentaire, 9 Comparable, 71 comparaison dobjets, 21 Comparator, 71 compare, 71 compareTo, 71 compile, 90, 92 Component, 101 concat enation de cha nes, 22 constant (membre), 37 constante (litt erale), 10 constante de classe, 37 constructeur, 36, 45 Constructor, 74 Container, 101 contains, 70 containsKey, 71 containsValue, 71 contr ol ee (exception), 59 conversion (entre objets), 16, 47 conversion (entre types primitifs), 11 copie dobjet, 18 copy, 73 copyArea, 116 cos, 64

INDEX

INDEX

create, 116 createImage, 147 DataInputStream, 76 DataOutputStream, 76 Date, 87 DateFormat, 87 d eballage automatique, 153 DecimalFormat, 84 DecimalFormatSymbols, 84 DefaultMutableTreeNode, 142 Deprecated, 164 Dialog, 102 directe (sous-classe ou super-classe), 42 DO NOTHING ON CLOSE, 114 Documented, 165 Double, 63 double, 11 double buering, 145 drawArc, 117 drawImage, 117 drawLine, 117 drawOval, 117 drawRect, 117 drawRoundRect, 117 drawString, 117 dynamique (liaison), 43 dynamique (type), 16 E, 63 EAST, 122 emballage automatique, 153 enableassertions, 61 encapsulation, 29 end, 92 enti` ere (constante), 10 entr ees-sorties, 76 enum, 149 Enumeration, 70 EnumMap, 151, 152 EnumSet, 152 equals, 21, 23, 74 Error, 58 etiquette, 24 ev enement, 101, 106 ev enements (thread de traitement), 105 event-dispatching thread, 105 ex ecutable (classe), 26 Exception, 58 exception, 57 exception contr ol ee, 59 EXIT ON CLOSE, 104 exp, 63 expression r eguli` ere, 90 extends, 169 extends, 42 false, 10 chier binaire, 79 chier compil e, 25 chier de texte, 80 174

chier source, 25, 26 Field, 74 File, 79 FileDescriptor, 79 FileInputStream, 76 FileOutputStream, 76 FileReader, 77 FileWriter, 78 fill, 73, 74 FilterInputStream, 76 FilterOutputStream, 76 FilterReader, 77 FilterWriter, 78 final, 37, 51, 52 nal (membre), 37 nale (classe), 52 nale (m ethode), 51 finalize, 38 finally, 57 find, 92 Float, 62 float, 11 floor, 63 ottante (constante), 10 FlowLayout, 121 focusGained, 112 FocusListener, 112 focusLost, 112 for (boucle for am elior ee), 156 Format, 84 formatage de donn ees, 84 forName, 75 Frame, 102 g en eralisation, 47 g en erique (classe), 166 g en erique (m ethode), 171 gestionnaire de disposition, 102, 120 get, 71 getActionCommand, 112, 128 getAnnotations, 163 getBounds, 101 getClass, 75 getContentPane, 103, 104 getDeclaredAnnotations, 163 getDefaultToolkit, 146 getImage, 146 getResource, 147 goto, 24 Graphics, 116 Graphics2D, 116 GregorianCalendar, 87 GridBagConstraints, 123 GridBagLayout, 123 GridLayout, 122 HashMap, 68 HashSet, 68 hasMoreElements, 70 hasNext, 69, 161 hasNextBigDecimal, 161
c H. Garreta, 2000-2013

INDEX

INDEX

hasNextBigInteger, 161 hasNextByte, 161 hasNextDouble, 161 hasNextFloat, 161 hasNextInt, 161 hasNextLine, 161 hasNextLong, 161 hasNextShort, 161 h eritage, 41, 42 ic one, 144 identicateur, 9 IdentityHashMap, 69 image, 143 ImageIcon, 145 implements, 53 import, 25, 26 import static, 155 indexOfSubList, 72 Inherited, 165 initialisation dun objet, 35 initialisation dun tableau, 15 InputStream, 76 InputStreamReader, 77 instance, 29 int, 11 Integer, 26, 62 interface, 53, 162 interface-utilisateur graphique, 100 intern, 23 interne (classe), 39 InterruptedException, 95, 98 introspection, 74 intValue, 62 invokeLater, 106 IOException, 58 isAnnotationPresent, 163 isEmpty, 70 ItemListener, 114 itemStateChanged, 114 Iterable, 157 Iterator, 66, 69 jar, 28 jar (chier), 28 java.awt, 100 java.lang, 26 java.lang.AnnotatedElement, 163 java.lang.Class, 74 java.lang.reflect, 74 java.math, 64 java.text, 84 java.util, 65 javadoc, 9 javax.swing, 100 JButton, 129 JCheckBox, 129 JDialog, 129 JFC, 100 JFileChooser, 133 JFrame, 103, 104
c H. Garreta, 2000-2013

JMenu, 127 JMenuBar, 127 JMenuItem, 127 jokers (dans les types param etr es), 168 JOptionPane, 131 JRadioButton, 129 JTable, 135 JTextArea, 129 JTextField, 129 JTree, 138 KeyListener, 111 keyPressed, 111 keyReleased, 111 keyTyped, 111 lang, 26 lastIndexOfSubList, 72 layout manager, 102, 120 length, 14 liaison dynamique, 43 liaison statique, 43 LineNumberReader, 77 LinkedHashMap, 69 LinkedHashSet, 68 LinkedList, 67 List, 66, 71 list, 73 listener, 101, 107 Long, 62 long, 11 main, 26 MANIFEST.MF, 28 manifeste (chier), 28 Map, 66, 71 masquage dun membre, 43 Matcher, 90 matcher, 91, 92 matches, 91 Math, 26, 63 max, 63, 72 membre dinstance, 30 message, 29 m eta-donn ees, 161 Method, 74 m ethode, 29 m ethode dinstance, 30 m ethode de classe, 32 m ethode virtuelle, 49 min, 63, 72 mod` ele-vue-contr oleur, 137 modale (bo te de dialogue), 103 mode imm ediat (mod` ele), 143 MouseAdapter, 109 mouseClicked, 108, 111 mouseDragged, 111 mouseEntered, 108, 111 mouseExited, 108, 111 MouseListener, 108, 110 MouseMotionListener, 111 175

INDEX

INDEX

mouseMoved, 111 mousePressed, 108, 111 mouseReleased, 108, 111 MutableTreeNode, 141 name, 150 nCopies, 73 new, 12, 13, 15, 36 next, 69 nextBigDecimal, 160 nextBigInteger, 160 nextByte, 160 nextDouble, 160 nextElement, 70 nextFloat, 160 nextInt, 160 nextLine, 160 nextLong, 160 nextShort, 160 NORTH, 122 notifyAll, 98 null, 13 NullPointerException, 14 NumberFormat, 84 Object, 43 Object (classe), 26 ObjectInputStream, 76 ObjectOutputStream, 76 objet, 29 observateur dune image, 143 ordinal, 150 OutputStream, 76 OutputStreamWriter, 78 Override, 164 pack, 104, 105 package, 25, 26 paint, 101, 116 paquet de classes, 25 paquets et r epertoires, 27 param etr e (type), 166 param etr ee (classe), 166 param` etre (type), 166 parseInt, 26, 62 particularisation, 47 passage par r ef erence, 13 passage par valeur, 13 Pattern, 90 PI, 63 PipedInputStream, 76 PipedOutputStream, 76 PipedReader, 77 PipedWriter, 78 Pixel, 42 Point, 42 polymorphisme, 47 pow, 64 primitif (type), 11 printf, 159 PrintStream, 76 176

PrintWriter, 78 priv e (membre), 34 private, 34 processus l eger, 94 producteur-consommateur, 98 prot eg e (membre), 34 protected, 34, 46 public, 26, 30, 34 public (membre), 34 publique (classe), 26 PushbackInputStream, 76 PushbackReader, 77 put, 71 random, 63 RandomAccessFile, 79 Reader, 77 recherche (algorithme), 72 recherche des m ethodes, 43 red enition des m ethodes, 33, 44 red enition et surcharge, 33, 44 r ef erence, 12 r` egle du thread unique, 105 r eguli` ere (expression), 90 relation dordre, 71 remove, 71 r epertoires et paquets, 27 replaceAll, 73, 93 Retention, 165 reverse, 73 reverseOrder, 72 rint, 63 rotate, 73 round, 63 run, 94 Runnable, 94 RuntimeException, 58 Scanner, 160 s emantique des r ef erences, 12 s emantique des valeurs, 12 SequenceInputStream, 76 s erialisation, 88 Set, 66, 71 set, 71 setBorder, 125 setDefaultCloseOperation, 104 setJMenuBar, 127 setLayout, 121 setResizable, 121 setSize, 101, 103, 104 setVisible, 102105 Short, 62 short, 11 show, 105 shuffle, 73 sin, 64 singleton, 73 singletonList, 73 singletonMap, 73 size, 70
c H. Garreta, 2000-2013

INDEX

INDEX

sleep, 95 sort, 72, 74 SortedMap, 67 SortedSet, 66 sous-classe, 42 SOUTH, 122 split, 90 Stack, 68 start, 92, 94, 99 static, 31 statique (liaison), 43 statique (type), 16 stop, 96 StreamTokenizer, 79 String, 22, 26 StringBuffer, 22 StringReader, 77 StringWriter, 78 super, 43, 170 super(), 45 super-classe, 42 SuppressWarnings, 164 surcharge dun membre, 43 surcharge des m ethodes, 33 surcharge et red enition, 33 swap, 73 Swing, 100 SwingUtilities, 106 switch, 151 symboliques, donn ees, 149 synchronized, 97 synchronizedCollection, 73 synchronizedList, 73 synchronizedMap, 73 System, 26 tableau, 13 tan, 64 Target, 165 TextListener, 114 textValueChanged, 114 this, 31, 36, 37 this(), 37 Thread, 94 thread, 94 thread safe (m ethode), 105 throw, 58 Throwable, 58 throws, 58 Toolkit, 146 toString, 22, 44, 49 transient, 88 translate, 118 TreeMap, 69 TreeModel, 141 TreeNode, 140 TreeSet, 68 tri (algorithme), 72 true, 10 try, 57 type primitif, 11
c H. Garreta, 2000-2013

Unicode, 9 unit e de compilation, 25 unmodifiableMap, 73 unmodifiableCollection, 73 unmodifiableList, 73 UnsupportedOperationException, 70 valueOf, 22, 62, 63, 150 values, 150 variable (type), 166 variable dinstance, 29, 30 variable de classe, 32 variables (listes darguents), 158 Vector, 67 virtuelle (m ethode), 49 wait, 98 WeakHashMap, 69 WEST, 122 Window, 102 windowActivated, 114 windowClosed, 114 windowClosing, 114 windowDeactivated, 114 windowDeiconified, 114 windowIconified, 114 WindowListener, 114 windowOpened, 114 Writer, 78

177