You are on page 1of 176

Universit de la Mditerrane e e e Facult des Sciences de Luminy e

Le langage Java
Master CCI, MINT, I2A, BBSG, etc.

Henri Garreta Dpartement dInformatique LIF e

c H. Garreta, 2000-2010

` TABLE DES MATIERES

` TABLE DES MATIERES

Le langage Java
Henri Garreta
Universit de la Mditerrane, Facult des Sciences de Luminy e e e e Table des mati`res e
1 Introduction 1.1 Pratique eective de Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Considrations lexicales e 2.1 Jeu de caract`res . . . e 2.2 Commentaires . . . . . 2.3 Identicateurs . . . . . 2.4 Constantes littrales . e 7 7 8 8 8 8 9 10 10 10 11 11 12 12 12 12 13 13 14 15 16 17 18 20 21 21 22

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

3 Types 3.1 Les types de donnes de Java . . . . . . . . . . . . . . . . . e 3.2 Conversions entre types primitifs . . . . . . . . . . . . . . . 3.3 Rfrences . . . . . . . . . . . . . . . . . . . . . . . . . . . . ee 3.3.1 Smantique des valeurs et smantique des rfrences e e ee 3.3.2 Rfrence sur rien . . . . . . . . . . . . . . . . . . ee 3.3.3 Cas des param`tres des mthodes . . . . . . . . . . . e e 3.4 Tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.1 Dclaration et initialisation . . . . . . . . . . . . . . e 3.4.2 Acc`s aux lments . . . . . . . . . . . . . . . . . . . e ee 3.4.3 Tableaux ` plusieurs indices . . . . . . . . . . . . . . a 3.4.4 Tableaux initialiss et tableaux anonymes. . . . . . . e 3.5 Conversions entre types tableaux ou classes . . . . . . . . . 3.6 Copie et comparaison des objets . . . . . . . . . . . . . . . 3.6.1 Copie . . . . . . . . . . . . . . . . . . . . . . . . . . 3.6.2 Dnir la mthode clone . . . . . . . . . . . . . . . e e 3.6.3 Comparaison . . . . . . . . . . . . . . . . . . . . . . 3.7 Cha nes de caract`res . . . . . . . . . . . . . . . . . . . . . e 3.7.1 Les classes String et StringBuffer . . . . . . . . . 3.7.2 Copie et comparaison des cha nes . . . . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4 Expressions et instructions 23 4.1 Rupture tiquete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 e e


c H. Garreta, 2000-2010

` TABLE DES MATIERES

` TABLE DES MATIERES

5 Classes, paquets, chiers et rpertoires e 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 rpertoires . . . . . . . . . . . . . . e 5.2.1 Classes publiques et non publiques . . . . . . . 5.2.2 Point dentre dun programme. . . . . . . . . e 5.2.3 O` placer les chiers des classes ? . . . . . . . . u 5.2.4 Comment distribuer une application Java ? . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

24 24 24 24 25 25 25 26 27 28 28 28 28 29 30 32 33 33 33 34 35 36 37 37 38 38 39 40 40 41 41 42 42 42 43 44 45 46 46 48 50 51 51 52 52 56 56 57 57 57 59 61 61 61 62 63 64

6 Les objets 6.1 Introduction : les langages orients objets . . . . . . . . . . . . . . e 6.2 Classes, variables et mthodes . . . . . . . . . . . . . . . . . . . . . . e 6.2.1 Dclaration des classes et des objets, instanciation des classes e 6.2.2 Instances et membres dinstance . . . . . . . . . . . . . . . . 6.2.3 Membres de classe (membres statiques) . . . . . . . . . . . . 6.3 Surcharge des noms . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4 Contrle de laccessibilit . . . . . . . . . . . . . . . . . . . . . . . . o e 6.4.1 Membres privs, protgs, publics . . . . . . . . . . . . . . . e e e 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 Hritage e 7.1 Introduction : raner, abstraire . . . . . . . 7.2 Sous-classes et super-classes . . . . . . . . . . . 7.2.1 Dnition de sous-classe . . . . . . . . . e 7.2.2 Larbre de toutes les classes . . . . . 7.3 Rednition des mthodes . . . . . . . . . . . . e e 7.3.1 Surcharge et masquage . . . . . . . . . . 7.3.2 Rednition des mthodes . . . . . . . . e e 7.4 Hritage et constructeurs . . . . . . . . . . . . e 7.5 Membres protgs . . . . . . . . . . . . . . . . e e 7.6 Le polymorphisme . . . . . . . . . . . . . . . 7.6.1 Gnralisation et particularisation . . . e e 7.6.2 Les mthodes rednies sont virtuelles e e 7.6.3 Mthodes et classes nales . . . . . . . . e 7.7 Abstraction . . . . . . . . . . . . . . . . . . . 7.7.1 Mthodes abstraites . . . . . . . . . . . e 7.7.2 Classes abstraites . . . . . . . . . . . . . 7.7.3 Interfaces . . . . . . . . . . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

8 Exceptions 8.1 Interception des exceptions . . . . . . . . . . . . . . . . . . 8.2 Lancement des exceptions . . . . . . . . . . . . . . . . . . . 8.2.1 Hirarchie des exceptions . . . . . . . . . . . . . . . e 8.2.2 Dclaration des exceptions lances par une mthode e e e 8.3 Assert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Quelques classes utiles 9.1 Nombres et outils mathmatiques . . . . . . . e 9.1.1 Classes-enveloppes des types primitifs 9.1.2 Fonctions mathmatiques . . . . . . . e 9.1.3 Nombres en prcision innie . . . . . . e 9.2 Collections et algorithmes . . . . . . . . . . . 4

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

c H. Garreta, 2000-2010

` TABLE DES MATIERES

` TABLE DES MATIERES

9.3 9.4

9.5

9.2.1 Collections et tables associatives . 9.2.2 Itrateurs . . . . . . . . . . . . . . e 9.2.3 Quelques mthodes des collections e 9.2.4 Algorithmes pour les collections . . 9.2.5 Algorithmes pour les tableaux . . . Rexion et manipulation des types . . . e Entres-sorties . . . . . . . . . . . . . . . e 9.4.1 Les classes de ux . . . . . . . . . 9.4.2 Exemples . . . . . . . . . . . . . . 9.4.3 Analyse lexicale . . . . . . . . . . . 9.4.4 Mise en forme de donnes . . . . . e 9.4.5 Reprsentation des dates . . . . . e 9.4.6 La srialisation . . . . . . . . . . . e Expressions rguli`res . . . . . . . . . . . e e 9.5.1 Principe . . . . . . . . . . . . . . . 9.5.2 Exemples . . . . . . . . . . . . . .

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

64 68 69 70 72 73 75 75 78 81 83 86 87 89 89 89 93 93 93 95 95 96 97 99 99 100 102 104 105 106 108 109 113 114 114 115 117 118 119 120 121 121 122 122 124 124 124 125 127 130 132 133 135 136 137 142 143 144 146 5

10 Threads 10.1 Cration et cycle de vie dun thread . . . . . . . . . e 10.1.1 Dclaration, cration et lancement de threads e e 10.1.2 Terminaison dun thread . . . . . . . . . . . . 10.2 Synchronisation . . . . . . . . . . . . . . . . . . . . . 10.2.1 Sections critiques . . . . . . . . . . . . . . . . 10.2.2 Mthodes synchronises . . . . . . . . . . . . e e

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

11 Interfaces graphiques 11.1 JFC = AWT + Swing . . . . . . . . . . . . . . . . . . . . . 11.2 Le haut de la hirarchie . . . . . . . . . . . . . . . . . . . . . e 11.3 Le point de dpart : JFrame et une application minimale. . . e 11.4 Le thread de gestion des vnements . . . . . . . . . . . . . . e e e 11.5 Evnements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.5.1 Exemple : dtecter les clics de la souris. . . . . . . . . e 11.5.2 Adaptateurs et classes anonymes . . . . . . . . . . . . 11.5.3 Principaux types dvnements . . . . . . . . . . . . . e e 11.5.4 Exemple : fermeture prudente du cadre principal . . 11.6 Peindre et repeindre . . . . . . . . . . . . . . . . . . . . . . . 11.6.1 La mthode paint . . . . . . . . . . . . . . . . . . . . e 11.6.2 Les classes Graphics et Graphics2D . . . . . . . . . . 11.6.3 Exemple : la mauvaise mani`re de dessiner . . . . . . e 11.6.4 Exemple : la bonne mani`re de dessiner. . . . . . . . . e 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 prdnis . . . . . . . . . . . . . . . . . . . . . . e e 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 donnes . . . . . . . . . . . . . . . e 11.8.4 Exemple : choisir un chier . . . . . . . . . . . . . . . 11.8.5 Exemple : une table pour acher des donnes . . . . . e 11.8.6 Exemple : slection et modication dans une table . . e 11.9 Le mod`le MVC (Mod`le-Vue-Controleur) . . . . . . . . . . . e e 11.9.1 Exemple : les vues arborescentes (JTree) . . . . . . . 11.10Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.10.1 Exemple : utiliser des icnes . . . . . . . . . . . . . . . o 11.10.2 Exemple : charger une image depuis un chier . . . . 11.10.3 Exemple : construire une image pixel par pixel . . . .
c H. Garreta, 2000-2010

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

` TABLE DES MATIERES

` TABLE DES MATIERES

12 Java 5 12.1 Types numrs . . . . . . . . . . . . . . . . . . . . . . . . . . . e ee 12.1.1 Enums . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.1.2 Mthodes des types numrs . . . . . . . . . . . . . . . e e ee 12.1.3 Aiguillages commands par des types numrs . . . . . e e ee 12.1.4 Dictionnaires et ensembles bass sur des types numrs e e ee 12.2 Emballage et dballage automatiques . . . . . . . . . . . . . . . e 12.2.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2.2 Oprations drives et autres consquences . . . . . . . e e e e 12.2.3 La rsolution de la surcharge en Java 5 . . . . . . . . . e 12.3 Quelques outils pour simplier la vie du programmeur . . . . . 12.3.1 Importation de membres statiques . . . . . . . . . . . . 12.3.2 Boucle for amliore . . . . . . . . . . . . . . . . . . . . e e 12.3.3 Mthodes avec une liste variable darguments . . . . . . e 12.3.4 Entres-sorties simplies : printf et Scanner . . . . . e e 12.4 Annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.4.1 Principe . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.4.2 Exploitation des annotations . . . . . . . . . . . . . . . 12.4.3 Annotations prdnies . . . . . . . . . . . . . . . . . . e e 12.4.4 Mta-annotations . . . . . . . . . . . . . . . . . . . . . . e 12.5 Gnricit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . e e e 12.5.1 Classes et types paramtrs . . . . . . . . . . . . . . . . e e 12.5.2 Types bruts . . . . . . . . . . . . . . . . . . . . . . . . . 12.5.3 Types paramtrs et jokers . . . . . . . . . . . . . . . . e e 12.5.4 Limitations de la gnricit . . . . . . . . . . . . . . . . e e e 12.5.5 Mthodes gnriques . . . . . . . . . . . . . . . . . . . . e e e Index

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

148 148 148 149 150 150 151 151 152 153 154 154 155 157 158 160 160 162 163 163 164 165 167 167 169 170 172

Ce poly est en chantier, cest son tat normal. e Ceci est la version du 15 fvrier 2010 (premi`re publication janvier 2000). e e

Henri.Garreta@univmed.fr

La derni`re version de ce document est ` ladresse e a http://www.dil.univ-mrs.fr/~garreta/Polys/PolyJava.pdf

c H. Garreta, 2000-2010

INTRODUCTION

Introduction

Ce polycopi est le support de plusieurs cours de Java donns ` la Facult des Sciences de Luminy. Tr`s e e a e e succinct, il ne remplace pas la consultation douvrages plus approfondis et illustrs, parmi lesquels : e pour dbuter : e Patrick Niemeyer & Jonathan Knudsen Introduction ` Java, 2 eme dition a e OReilly, 2002 deuxi`me lecture : e Ian Darwin Java en action OReilly, 2002

Ce texte sadresse ` des lecteurs connaissant le langage C. De nombreux lments importants de Java, a ee comme les expressions, les instructions, lappel des fonctions, etc., ne sont pas expliqus ici, tout simplement e parce quils sont raliss en Java comme en C. En outre, lexpos nest pas progressif : chaque notion est e e e introduite comme si les autres concepts du langage avaient dj` t traits. Cela rend la lecture initiale de eaee e ce document plus prouvante, mais la consultation ultrieure plus ecace. e e Ces notes traitent de la version courante de la plate-forme Java (le langage et ses biblioth`ques ocielles) e et de son environnement de dveloppement, appels dsormais respectivement JavaTM Platform Standard e e e Edition 6 et JavaTM SE Development Kit 6 (le numro de version 1.6.x appara parfois ` la place de 6). e t a Cependant, pour la clart des ides, nous avons introduit la plupart des lments comme il convenait de le faire e e ee a e ` lpoque de Java 1.4 (par exemple, lhritage et le polymorphisme sont dabord expliqus sans mentionner e e ni la gnricit ni lemballage automatique). Les principales nouveauts introduites lors du passage de Java e e e e 1.4 ` Java 5 sont prsentes ` la section 12. a e e a 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 ` propos de tous les paquets, interfaces, classes, variables et mthodes de la plate-forme Java. On peut a e le consulter en ligne et le tlcharger ` ladresse http://java.sun.com/javase/6/docs/api/ ee a Enn, un excellent document pour apprendre Java est le tutoriel ociel, quon peut consulter en ligne ou tlcharger ` ladresse http://java.sun.com/tutorial/ ee a

1.1

Pratique eective de Java

Dans cette section nous supposons que vous travaillez sur un syst`me Windows, Linux, Solaris ou e Mac OS X. Certains des produits mentionns ici ont galement des versions pour des syst`mes plus cone e e dentiels. Pour pratiquer le langage Java, cest-`-dire pour saisir, compiler et excuter vos programmes, il vous faut a e un environnement de dveloppement Java, comportant un compilateur, une machine Java et des biblioth`ques e e au moins la biblioth`que standard. Vous obtenez tout cela en installant le JDK (Java Development Kit), e que vous pouvez tlcharger gratuitement depuis le site de Sun, ` ladresse http://java.sun.com/javase/ ee a downloads. Vous pouvez utiliser nimporte quel diteur de textes pour saisir vos programmes. Supposons que vous e ayez tap le texte de la cl`bre classe Bonjour : e ee public class Bonjour { public static void main(String[] args) { System.out.println("Bonjour ` tous!"); a } } Le chier dans lequel vous avez enregistr ce texte doit sappeler Bonjour.java. Vous en obtenez la e compilation en tapant la commande javac Bonjour.java Si le programme est correct, la compilation se droule sans produire aucun message. Vous lancez alors e lexcution de votre programme (pour obtenir lachage du texte Bonjour ` tous ! ) en tapant la commande e a java Bonjour Notez bien qu` la commande javac on donne un nom de chier (Bonjour.java), tandis qu` la commande a a java on doit donner un nom de classe (Bonjour ). Quel que soit le syst`me dexploitation que vous utilisez, vous pouvez vous constituer un environnement e de travail plus agrable en installant le JDK puis un petit diteur de textes orient Java. Vous en trouverez e e e plusieurs sur le web, par exemple Jext, ` ladresse http://www.jext.org/. a
c H. Garreta, 2000-2010

CONSIDERATIONS LEXICALES

Vous obtenez un confort incomparablement suprieur si, apr`s JDK, vous installez Eclipse, un puise e sant IDE (environnement de dveloppement intgr) avec de nombreuses fonctionnalits pour aider ` la e e e e a programmation en Java, telles que la compltion automatique des expressions tapes, la compilation au fur e e et ` mesure de la frappe, la suggestion de la mani`re de corriger les erreurs, etc. Vous pouvez librement a e tlcharger Eclipse ` ladresse http://www.eclipse.org/ ee a Enn, si vous voulez programmer des interfaces graphiques rien quen jouant de la souris 1 vous pouvez gratuitement installer NetBeans de Sun (http://www.netbeans.org/) ou JBuilder Foundation de Borland (http://www.borland.fr/jbuilder/).

2
2.1

Considrations lexicales e
Jeu de caract`res e

Java utilise le codage des caract`res UTF-16, une implmentation de la norme Unicode, dans laquelle e e chaque caract`re est reprsent par un entier de 16 bits, ce qui ore 65 536 possibilits au lieu des 128 (ASCII) e e e e ou 256 (Latin-1) imposs par dautres langages de programmation. Il y a donc de la place pour la plupart e des alphabets nationaux ; en particulier, tous les caract`res franais y sont reprsents sans crer de conit e c e e e avec des caract`res dautres langues. e Cela vaut pour les donnes manipules par les programmes (caract`res et cha e e e nes) et aussi pour les programmes eux-mmes. Il est donc possible en Java de donner aux variables et aux mthodes des noms e e accentus. Mais on ne vous conseille pas dutiliser cette possibilit, car vous ntes jamais ` labri de devoir e e e a un jour consulter ou modier votre programme ` laide dun diteur de textes qui ne supporte pas les accents. a e

2.2

Commentaires
int nbLignes; // nombre de variables du syst`me e

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 stendre sur plusieurs lignes : e /* Recherche de lindice ik du "pivot maximum" c.-`-d. tel que k <= ik < nl et a a[ik][k] = max { |a[k][k]|, ... |a[nl - 1][k]| } */ Enn, cas particulier du prcdent, un texte compris entre /** et */ est appel commentaire de documene e e tation et est destin ` loutil javadoc qui lexploite pour fabriquer la documentation dune classe ` partir de ea a son texte source 2 . Cela ressemble ` ceci (un tel commentaire est associ ` llment, ici une mthode, quil a ea ee e prc`de) : e e /** * Rsolution dun syst`me linaire e e e * * @param a Matrice du syst`me e * @param x Vecteur solution du syst`me e * @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`gles de formation des identicateurs sont les mmes que dans le langage C, compte tenu des e e remarques du 2.1. La note Java Code Conventions 3 fait les recommandations suivantes ` propos de la a mani`re de nommer les entits des programmes : e e
1. Si vous dbutez en Java nous vous dconseillons de commencer par l`. e e a 2. Par exemple, la documentation en ligne de lAPI, ce gigantesque document hypertexte qui est le compagnon insparable e de tout programmeur Java, est automatiquement produit au moyen de javadoc ` partir des chiers sources de la biblioth`que a e standard. 3. On peut tlcharger cette note depuis le site http://java.sun.com/docs/codeconv/ ee

c H. Garreta, 2000-2010

CONSIDERATIONS LEXICALES

2.4

Constantes littrales e

1. Les dirents identicateurs, spars par des points, qui forment un nom de paquet sont crits princie e e e palement 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 concatnation de plusieurs mots. Chae cun commence par une majuscule, y compris le premier : Point, AbstractListModel, ListeDeNombres, etc. 3. Les noms des mthodes commencent par une minuscule. Lorsquils sont forms par concatnation de e e e mots, chacun sauf le premier commence par une majuscule : toString(), vitesseDuVent(...), etc. 4. La mme r`gle vaut pour les noms des variables, aussi bien les variables de classe et dinstance que les e e arguments et les variables locales des mthodes : i, nombreDeMembres, etc. e 5. Enn, les constantes de classe (cest-`-dire les variables static final) sont crites de prfrence en a e ee majuscules : Integer.MAX_VALUE, TextField.LEFT_ALIGNMENT, etc.

2.4

Constantes littrales e

Les r`gles pour lcriture des constantes sont les mmes quen C, avec les additions suivantes : e e e 1. Caract`res. Les caract`res non imprimables peuvent tre reprsents aussi par la squence \uxxxx, o` e e e e e e u xxxx sont les quatre chires hexadcimaux du code numrique du caract`re. Par exemple, la cha e e e ne suivante comporte les quatre caract`res A, espace (code 32, ou 20 en hexadcimal), B et ~ (code 241, e e n ou F1 en hexadcimal) : e "A\u0020B\u00F1" // la cha^ne de quatre caract`res "A B~" e n 2. Entiers. Une constante littrale enti`re est suppose tre du type int, cest-`-dire code sur 32 bits, e e e e a e sauf si elle est trop grande pour tre reprsente dans ce type ; elle appartient alors au type long. La e e e lettre L ou l indique que la constante doit tre considre comme appartenant au type long et code e ee e sur 64 bits, mme si sa valeur est petite. Exemple : e 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`re e automatiquement la conversion ncessaire. On peut alors se demander dans quelle circonstance on est e gn par le fait quune valeur enti`re soit considre int au lieu de long. Le probl`me rside le plus e e e ee e e souvent dans lincapacit de reprsenter les rsultats des oprations. Par exemple, laectation e e e e long u = 4000000 * 6000000; // ERREUR (dbordement de la muliplication) e est certainement incorrecte, car 4000000 et 6000000 seront considrs de type int, et donc la multiee plication et son rsultat aussi ; or ce rsultat ne peut pas tre reprsent dans les 32 bits dun entier e e e e e (voyez le tableau 1, page 10). Bien entendu, que ce rsultat soit ensuite aect ` une variable de type e ea long ne le rend pas juste. De plus, sagissant dun dbordement en arithmtique enti`re, aucune erreur e e e ne sera signale ni ` la compilation ni ` lexcution (mais le rsultat sera faux). e a a e e Pour corriger ce probl`me il sut placer lopration et son rsultat dans le type long ; ` cause de la e e e a r`gle du plus fort 4 , il sut pour cela quun des oprandes le soit : e e long u = 4000000L * 6000000; // OK 3. Flottants. Une constante ottante (cest-`-dire un nombre comportant un point et/ou un exposant, a comme 1.5, 2e-12 ou -0.54321E3) reprsente une valeur du type double. Les suxes f ou F peuvent e tre utiliss pour prciser le type de ce qui est crit. e e e e Ainsi, une simple aectation telle que float x = 1.5; // ERREUR (discordance de types) est signale comme une erreur. Correction : e float x = 1.5f; On peut aussi laisser la constante tre du type float et en demander explicitement la conversion : e float x = (float) 1.5; 4. Boolens. Le type boolean comporte deux valeurs, reprsentes par les constantes littrales suivantes, e e e e qui sont aussi des mots rservs : e e false // la valeur boolenne faux e true // la valeur boolenne vrai e
4. Grosso modo cette r`gle dit que si les deux oprandes dune opration ne sont pas de mme type alors le plus fort e e e e (c.-`-d. le plus tendu, ou le plus prcis, ou un ottant face ` un entier, etc.) provoque la conversion vers son type de lautre a e e a oprande et le placement dans ce type de lopration et de son rsultat. Cette r`gle sapplique dans la grande majorit des e e e e e oprations binaires. e

c H. Garreta, 2000-2010

TYPES

3
3.1

Types
Les types de donnes de Java e
Les types des donnes manipules par les programmes Java se rpartissent en deux catgories : e e e e les types primitifs, les objets, cest-`-dire les tableaux et les classes. a La table 1 rcapitule ce quil faut savoir sur les huit types primitifs. e 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 ` 127 a 16 bits de 32 768 ` 32 767 a 32 bits de 2 147 483 648 ` 2 147 483 647 a 64 bits de 263 ` 263 1 a Nombres ottants de 3, 402823510+38 ` 1, 41045 , a 32 bits 0 et de 1, 41045 ` 3, 402823510+38 a 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`res Unicode e 1 bit false, true val. init.

float

Flottant simple prcision e

0.0

double

Flottant double prcision e

char boolean

Caract`re e Valeur boolenne e

\u0000 false

On notera que : tous les types entiers sont signs (cest-`-dire reprsentent des ensembles contenant des nombres e a e positifs et ngatifs), e portabilit oblige, on na pas reproduit en Java la bourde consistant ` laisser la taille des int ` e a a lapprciation de chaque compilateur. e

3.2

Conversions entre types primitifs

La question de la compatibilit et de la convertibilit entre expressions de types primitifs est rgle en e e e e Java selon un petit nombre de principes simples : 1. Toute valeur dun type numrique est convertible vers tout autre type numrique, selon les modalits e e e expliques ci-apr`s. e e 2. Les conversions entre types numriques sans risque de perte dinformation (cest-`-dire : entier ou e a caract`re vers entier de taille suprieure, ottant vers ottant de taille suprieure, entier ou caract`re e e e e vers ottant) sont faites, ` la compilation et ` lexcution, sans requrir aucune indication particuli`re. a a e e e Par exemple, si les variables qui y gurent ont les types que leurs noms sugg`rent, les aectations e suivantes ne soul`vent le moindre probl`me, ni ` la compilation ni ` lexcution : e e a a e unInt = unChar; unDouble = unFloat; unFloat = unInt; 3. Les conversions avec risque de perte dinformation (cest-`-dire : entier vers entier de taille infrieure, a e ottant vers ottant de taille infrieure, ottant vers entier) sont refuses par le compilateur : e e unByte = unInt; // ERREUR

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

Attention. Une expression comme la prcdente est place sous la responsabilit du programmeur, e e e e seul capable de garantir que la valeur de unInt pourra, au moment de laectation ci-dessus, tre e reprsente dans une variable de type byte. Cette condition ne peut pas tre vrie ` la compilation e e e e e a 10
c H. Garreta, 2000-2010

TYPES

3.3

Rfrences ee

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

4. Puisque les caract`res sont reprsents par des nombres, le type char est considr comme numrique, e e e ee e pour ce qui nous occupe ici. Cependant, la conversion de nimporte quel type numrique vers le type e char est considre comme susceptible dentra ee ner une perte de prcision ; cela oblige le programmeur e a ` utiliser loprateur de transtypage. e 5. La conversion dune expression boolenne vers un type numrique, ou rciproquement, est illgale et e e e e rejete par le compilateur. Les expressions ` la mode de C suivantes sont donc errones en Java : e a e if (unInt) ... unInt = (x < y); // ERREUR (ncessite une conversion int boolean) e // ERREUR (ncessite une conversion boolean int) e

Bien entendu, ces conversions peuvent tre obtenues facilement : e conversion boolen entier : e (unBooleen ? 1 : 0) conversion nombre boolen : (unNombre != 0) e

3.3
3.3.1

Rfrences ee
Smantique des valeurs et smantique des rfrences e e ee

Les expressions de types primitifs ont la smantique des valeurs. Cela signie que si e est une expression e dun type primitif T, alors ` tout endroit 5 o` elle gure e reprsente une valeur du type T. Par exemple, a u e si unInt est une variable enti`re contenant la valeur 12, alors les trois expressions 12, unInt et unInt/4 + 9 e ont la mme signication : la valeur enti`re 12. e e Notez que des trois expressions 12, unInt et unInt/4 + 9, une seule est associe ` un emplacement dans e a la mmoire (la seconde). Si une expression a la smantique des valeurs elle nest pas forcment un renvoi ` e e e a un objet existant dans la mmoire. e Tous les autres types de Java, cest-`-dire les tableaux et les classes, ont la smantique des rfrences. a e ee Cela veut dire quune expression dun type tableau ou classe est, en toute circonstance, une rfrence sur un ee objet existant dans la mmoire 6 . e
unInt 12 unPoint 10 20

Figure 1 Smantique des valeurs et smantique des rfrences e e ee On peut voir une rfrence comme un pointeur 7 gr de mani`re interne par Java. Par exemple, si Point ee ee e est une classe forme de deux entiers x et y (les coordonnes dun point) : e e class Point { int x, y; ... } et si unPoint est une variable de type Point correctement initialise : e Point unPoint = new Point(10, 20); alors il convient de se reprsenter la variable unPoint et sa valeur comme le montre la gure 1. e Bien noter quen Java aucun signe ne rappelle, lors de lemploi dune expression de type rfrence, quil ee sagit dune sorte de pointeur (cest-`-dire, on nutilise pas les oprateurs * ou -> de C). Puisque les objets a e sont toujours accds par rfrence, une expression comme e e ee
5. Comme dans tous les langages qui ont la notion daectation, il y a une exception : place au membre gauche dune e aectation, une expression ne reprsente pas une valeur mais un emplacement de la mmoire. e e 6. Plus prcisment, les rfrences sont des renvois a la heap, cest-`-dire la partie de la mmoire dans laquelle se font les e e ee ` a e allocations dynamiques (par new, le moyen de crer un tableau ou un objet). e 7. Attention, abus de langage ! Imaginer un pointeur est sans doute une bonne mani`re dapprhender une rfrence, mais il e e ee ne faut pas oublier quen Java on sinterdit de parler de pointeurs, car le programmeur nest pas cens conna e tre les dtails du e procd par lequel Java dsigne de mani`re interne les objets quil cre dans la mmoire. e e e e e e

c H. Garreta, 2000-2010

11

3.4

Tableaux

TYPES

unPoint.x est sans ambigu e ; elle signie : le champ x de lobjet rfrenc par unPoint. t ee e 3.3.2 Rfrence sur rien ee

La valeur particuli`re null indique quune variable dun type rfrence nest pas une rfrence ` un objet e ee ee a valide. Cest la valeur quil convient de donner ` une telle variable lorsque lobjet rfrenc nexiste pas a ee e encore, ou bien lorsque la variable a cess dtre utile en tant que rfrence sur un objet : e e ee Point unPoint = null; // ... // unPoint = new Point(10, 20); ... // unPoint = null; ... // dclaration et initialisation de unPoint e ici, unPoint ne reprsente pas un objet valide e ici on peut travailler avec lobjet unPoint a ` nouveau, unPoint nest pas un objet valide

Le compilateur se charge dinitialiser ` null les variables dinstance et de classe dun type objet qui nont a pas dinitialisation explicite. Les variables locales ne sont pas initialises 8 . e 3.3.3 Cas des param`tres des mthodes e e

Les explications prcdentes sont valables pour toutes sortes dexpressions, quels que soient les contextes e e o` elles apparaissent (sauf les membres gauches des aectations, qui chappent ` cette discussion). Cela vaut u e a en particulier pour les param`tres eectifs des appels des mthodes ; par consquent : e e e un param`tre dun type primitif est pass par valeur : lors de lappel de la mthode, la valeur du e e e param`tre eectif est copie dans le param`tre formel correspondant, qui est une variable locale de la e e e mthode ; en particulier, si un tel param`tre eectif est une variable, lappel de la mthode ne pourra e e e pas en changer la valeur, quoi quelle fasse au param`tre formel correspondant ; e un param`tre dun type tableau ou classe est pass par rfrence 9 : lors de lappel de la mthode, le e e ee e param`tre formel est initialis avec une rfrence sur le tableau ou lobjet que reprsente le param`tre e e ee e e eectif ; il en dcoule que le tableau ou lobjet en question pourra tre rellement modi par les actions e e e e que la mthode fera sur le param`tre formel. e e

3.4
3.4.1

Tableaux
Dclaration et initialisation e

Tous les tableaux utiliss en Java sont des tableaux dynamiques. Cela veut dire que le nombre dlments : e ee nest pas un lment constitutif du type du tableau et na pas besoin dappara dans sa dclaration, ee tre e nest pris en compte quau moment de lexcution du programme, mme sil est connu pendant la e e compilation. Il y a deux syntaxes rigoureusement quivalentes pour dclarer un tableau tab dont les lments sont, e e ee par exemple, des int : int tab[]; et int[] tab; // tab dsigne un tableau de int e Dans lun et lautre cas, la variable tab ainsi dclare est une rfrence et, pour le moment, elle ne e e ee rfrence rien. Si les expressions prcdentes sont la dclaration dune variable dinstance ou de classe, tab ee e e e aura t initialise avec la valeur null. Sil sagit de la dclaration dune variable locale, tab est indtermine ee e e e e et il aurait probablement t plus sage de la complter par une initialisation explicite, comme : ee e int[] tab = null; // tab dsigne un tableau de int e // tab dsigne un tableau de int e

Le tableau lui-mme commence eectivement ` exister lors de lappel de loprateur new : e a e tab = new int[nombreDeComposantes];
8. Les variables locales ne sont pas initialises mais toute utilisation dune variable locale susceptible de ne pas avoir t e e e initialise est dtecte par le compilateur et signale comme une erreur. e e e e 9. En toute rigueur on peut dire que le passage dun objet ou dun tableau comme param`tre dune mthode se traduit par e e le passage par valeur de la rfrence ` lobjet ou au tableau en question. ee a

12

c H. Garreta, 2000-2010

TYPES

3.4

Tableaux

o` nombreDeComposantes est une expression, dun type entier, qui dnit la taille du tableau. u e Note. On peut joindre dans la mme expression la dclaration de la variable et la cration du tableau e e e correspondant : int[] tab = new int[nombreDeComposantes]; cela est plus commode, car il y a moins de choses ` crire, et plus able, car on limine la priode pendant ae e e laquelle la variable existe sans rfrencer un tableau. En gnral cest faisable, car Java permet dcrire les ee e e e dclarations l` o` on veut. e a u 3.4.2 Acc`s aux lments e ee

Une fois le tableau cr, on acc`de ` ses composantes en utilisant la mme notation quen C : ee e a e tab[i ] o` i est une expression de type entier 10 . Pour que lexpression ci-dessus soit lgitime il faut et il sut que u e 0 i < nombreDeComposantes. Autrement dit, les lments du tableau prcdent sont ee e e t[0], t[1], ... t[nombreDeComposantes1] Le schma de la gure 2 est la bonne mani`re de se reprsenter lacc`s tab[i ] : e e e e

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

Figure 2 Un tableau de N lments ee Taille effective dun tableau. Lexpression unTableau.length permet de conna le nombre dltre ee ments dun tableau. Cela est bien utile pour crire des traitements de tableaux dont la taille est inaccessible e lors de la compilation. Par exemple, le programme suivant ache les arguments crits sur la ligne de come mande (` la suite des deux mots java ArgumentsLigneCommande) quel que soit leur nombre : a class ArgumentsLigneCommande { public static void main(String[] args) { for (int i = 0; i < args.length; i++) System.out.println(args[i]); } } Controle de lindice. Lors de lacc`s ` un lment dun tableau, Java contrle toujours la validit de e a ee o e lindice. Autrement dit, lors de lvaluation dune expression comme tab[i] les deux erreurs possibles les e plus frquentes sont dtectes et dclenchent une exception : e e e e NullPointerException, pour indiquer que tab = null, cest-`-dire que la variable tab nest pas a une rfrence valide (en clair, le plus souvent : la variable tab a bien t dclare, mais le tableau ee ee e e correspondant na pas encore t cr), e e ee ArrayIndexOutOfBoundsException, pour indiquer que la condition 0 i < tab.length nest pas satisfaite. 3.4.3 Tableaux ` plusieurs indices a

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

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

c H. Garreta, 2000-2010

13

3.4

Tableaux

TYPES

mat = new int[NL][NC]; o` NL et NC sont des expressions enti`res dnissant le nombre de lignes et de colonnes de la matrice souhaite. u e e e Linstruction prcdente a le mme eet que le code suivant : e e e mat = new int[NL][]; for (int i = 0; i < NL; i++) mat[i] = new int[NC]; // un tableau de NL [rfrences de] tableaux e e // un tableau de NC int

Lacc`s aux lments dun tableau ` deux indices se fait comme en C : e ee a mat[i][j] Lvaluation de cette expression dclenchera la vrication successive des conditions : e e e 1 2 3 4 mat = null 0 i < mat.length mat[i] = null 0 j < mat[i].length

Ainsi, un tableau ` deux indices dont les lments sont par exemple des int est ralis en Java comme a ee e e un tableau ` un indice dont les lments sont des [rfrences sur des] tableaux ` un indice dont les lments a ee ee a ee sont des int. La gure 3 reprsente cette conguration. e
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`s ` m[i][j], m tant une matrice ` NL lignes et NC colonnes e a e a Note. Java permet de manipuler, sous la mme syntaxe, des tableaux rectangulaires et des tableaux qui e ne le sont pas ; il sut pour cela de faire soi-mme linitialisation des lignes. Par exemple, le code suivant e cre une matrice triangulaire infrieure de dimension N dans laquelle chaque ligne a la longueur requise par e e son rang : float[][] mt = new float[N][]; for (int i = 0; i < N; i++) mt[i] = new float[i + 1]; 3.4.4 Tableaux initialiss et tableaux anonymes. e

Deux syntaxes permettent dindiquer un ensemble de valeurs devant remplir un tableau. Dans lune comme dans lautre, le nombre de valeurs fournies dtermine la taille du tableau. Dans la premi`re forme, e e analogue ` celle qui existe en C, on initialise le tableau au moment de sa dclaration : a e int[] tab = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; La deuxi`me forme permet de crer un tableau garni de valeurs, mais pas forcment ` lendroit de la dclae e e a e ration du tableau : 14
c H. Garreta, 2000-2010

TYPES

3.5

Conversions entre types tableaux ou classes

int[] tab; ... tab = new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; En fait, cette deuxi`me syntaxe permet de crer des tableaux garnis anonymes, ce qui est bien utile e e lorsquun tableau ne sert quune seule fois. Par exemple, si la variable tab avait t dclare et construite ee e e dans lunique but de gurer dans lappel dune mthode (cela arrive) comme dans : e int tab[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; traiter(tab); alors il aurait t plus simple de ne pas dclarer de variable tab : ee e traiter(new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }); Cas des matrices. Les mmes mcanismes permettent de crer des tableaux multidimensionnels garnis, e e e y compris lorsque leurs lignes ne sont pas de mme longueur : e int[][] mat = { { 11, 12, 13, 14, 15 }, { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 }, { }, null, { 51, 52, 53 } }; Notez la dirence entre la troisi`me et la quatri`me ligne du tableau prcdent : la troisi`me existe mais est e e e e e e vide (cest un tableau de 0 lments), tandis que la quatri`me nexiste pas. ee e Note. Contrairement ` ce qui se passe dans dautres langages, en Java linitialisation des tableaux se a fait pendant lexcution du programme, non pendant la compilation. Premi`re consquence : initialiser un e e e tableau par une liste de constantes est plus commode, mais pas notablement plus ecace, que la collection daectations qui aurait le mme eet. Par exemple, la dclaration e e int[] tab = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; a le mme eet mais est plus agrable ` crire et ` lire que la squence e e ae a e int[] tab = new int[10]; tab[0] = 1; tab[1] = 2; ... tab[9] = 10; Deuxi`me consquence : les expressions avec lesquelles on initialise des tableaux nont pas ` tre ncessaie e ae e rement des constantes. Des expressions quelconques, values pendant lexcution du programme, peuvent y e e e 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 les notions de tre classe et dhritage. e Le type statique dune expression E est dtermin par les dclarations des variables apparaissant dans e e e E, ainsi que par les constantes, oprateurs et mthodes qui forment E. Par exemple, avec la dclaration e e e Object e = "Bonjour"; le type statique de e est Object. Le type dynamique dune expression E est celui qui rsulte des valeurs eectives des variables intervee nant dans E, ainsi que des constantes, oprateurs et mthodes constituant E. Par exemple, avec la mme e e e dclaration ci-dessus, le type dynamique de e est String. e Dans ces conditions, soit E une expression, Ts son type statique, Td son type dynamique ` un instant a donn et Tf un deuxi`me type. Nous nous intressons ` la conversion de la valeur de E vers le type Tf , e e e a 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 rciproquement. e Dans les points suivants on suppose donc que Ts et Tf sont tous les deux des types tableaux ou classes.
c H. Garreta, 2000-2010

15

3.6

Copie et comparaison des objets

TYPES

2. La conversion de la valeur de E vers le type Tf , lorsquelle est lgitime, est une conversion sans travail : e elle se rduit ` considrer lobjet dsign par E comme ayant le type Tf , sans que cet objet subisse la e a e e e moindre modication (ne pas oublier que E ne reprsente quune rfrence sur un objet). e ee 3. Sauf le cas particulier examin au point 7, la conversion de E vers le type Tf nest accepte ` la e e a compilation que si Ts et Tf sont des classes apparentes, cest-`-dire des classes dont lune est souse a classe, directe ou indirecte, de lautre (autrement dit, Ts et Tf sont sur une mme branche de larbre e dhritage). e 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`re. On peut appeler cela une gnralisation du type de E. e e e Par exemple, si la classe Article est une super-classe de la classe ArticleSportif, elle-mme supere classe de Velo, qui est super-classe de VTT, alors laectation suivante est correcte (elle contient la conversion dun objet de type Velo vers le type Article) : Article unArticle = new Velo( ...caractristiques dun vlo... ); e e Lobjet Velo cr ci-dessus nest en rien modi par son aectation ` la variable unArticle mais, aussi ee e a longtemps quil est accd ` travers cette variable, il est considr comme un Article, non comme une e ea ee Velo (Article est un concept plus gnral que Velo). e e 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 accepte ` la compilation que si on utilise explicitement loprateur de transtypage. Exemple : e a e Article unArticle; Velo unVelo; ... unVelo = unArticle; unVelo = (Velo) unArticle;

// Erreur ` la compilation a // Ok (pour la compilation)

nest correcte, ` lexcution, que si Td est une sous-classe, directe ou indirecte, de Tf . Exemple : a e unArticle = new VTT( ... caractristiques dun VTT ... ); e ... unVelo = (Velo) unArticle; // Ok, un VTT peut ^tre vu comme une Velo e dclenche lorsquelle est incorrecte, ` lexcution, lexception ClassCastException. Exemple : e a e unArticle = new BallonDeBasket( ... caractristiques dun ballon ... ); e ... unVelo = (Velo) unArticle; // dclenche ClassCastException (un ballon e // ne peut pas ^tre vu comme un vlo) e e 6. Aucune conversion nest accepte entre types tableaux dirents (mais noubliez pas que le nombre e e dlments dun tableau ne fait pas partie de la dnition de son type : pour Java, un tableau de 10 ee e entiers et un tableau de 20 entiers ont exactement le mme type). e 7. Enn, les seules conversions correctes entre une classe et un tableau concernent ncessairement la classe e 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`s le type dynamique de unObjet) e En resume. Lessentiel ` retenir des r`gles prcdentes : a e e e ` la compilation, la conversion dune expression de type objet ou tableau est accepte sauf si on a e peut prdire avec certitude quelle chouera ` lexcution ; elle requiert parfois lemploi explicite de e e a e loprateur de transtypage ; e ` lexcution, la conversion du type dun objet est toujours contrle ; elle nest accepte que si elle a e oe e correspond ` une gnralisation du type dynamique de lobjet. a e e

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 expliques qu` la section 7. e a 16
c H. Garreta, 2000-2010

TYPES

3.6

Copie et comparaison des objets

3.6.1

Copie

Une consquence du fait que les objets et les tableaux sont toujours manipuls ` travers des rfrences e e a ee 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 rfrence (ce quon appelle parfois une copie ee supercielle). Par exemple, considrons : e Point p = Point(10, 20); Point q = p; A la suite de laectation prcdente on peut penser quon a dans q un duplicata de p. Il nen est rien, il e e ny a pas deux points, mais un seul point rfrenc par deux variables distinctes, comme le montre la gure 4. ee e Dans certaines situations cette mani`re de copier est susante, mais elle prsente un inconvnient vident : e e e e chaque modication de la valeur de p se rpercute automatiquement sur celle de q. e

10 20

Figure 4 Copie de la rfrence sans duplication de lobjet (copie supercielle) ee

Pour obtenir la duplication eective dun objet, il faut appeler sa mthode clone. Tous les objets sont e censs possder une telle mthode 11 car elle est dclare dans la classe Object, la super-classe de toutes les e e e e e classes. Il appartient ` chaque classe de rednir la mthode clone, pour en donner une version adapte au a e e e rle et aux dtails internes de ses instances. o e La mthode clone rend un rsultat de type Object 12 , il faut donc lutiliser comme suit (la nature mme e e e de la mthode clone garantit que la conversion du rsultat de p.clone() vers le type Point est lgitime) : e e e Point q = (Point) p.clone();

10 20

10 20

Figure 5 Duplication eective dun objet (copie profonde)

Si clone a t correctement dnie (dans la classe Point) lexpression prcdente aecte ` q une copie ee e e e a profonde de lobjet qui est la valeur de p, comme montr sur la gure 5. e Il appartient au programmeur dune classe de dnir ce quil entend par copie profonde, notamment e lorsque les objects ont pour membres dautres objets. Sauf indication contraire on suppose que le clone dun objet est un deuxi`me objet nayant avec le premier aucun bout de mmoire en commun (comme les points e e montrs ci-dessus), mais ce nest pas une obligation. Par exemple, on verra ` la section suivante que le clone e a ociel dun tableau dobjets nest pas disjoint du tableau original.
11. La mthode clone existe dans tous les objets mais, si le programmeur na pas pris certaines prcautions (consistent e e soit ` dnir explicitement la mthode clone, soit ` dclarer que la classe implmente linterface Cloneable), une exception a e e a e e CloneNotSupportedException sera lance a lexcution. e ` e 12. Cest regrettable mais ncessaire, car la dnition initiale de clone, dans la classe Object, ne peut tre dclare rendant e e e e e autre chose quun Object ; ensuite les rdnitions de clone dans les sous-classes doivent rendre strictement le mme rsultat, e e e e cest une contrainte du mcanisme de la rednition des mthodes. e e e

c H. Garreta, 2000-2010

17

3.6

Copie et comparaison des objets

TYPES

Cas des tableaux La mthode clone fonctionne en particulier dans le cas des tableaux : si t est un tableau, le rsultat e e de t.clone() est un tableau de mme type et mme taille que t dont les lments ont t initialiss par e e ee ee e aectation de ceux de t. Par exemple, les instructions suivantes crent deux tableaux distincts, lun rfrenc par les variables e ee e tab1 et tab2 et lautre rfrenc par tab3 : ee e 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 rsultat rendu par t.clone() est un tableau nouvellement cr, de mme type et mme e ee e e taille que t, dont les lments sont initialiss par aectation, non par clonage, de ceux de t. Autrement dit, ee e la mthode clone des tableaux neectue pas une duplication profonde, mais seulement une duplication ` e a un niveau : si les lments du tableau sont des objets 13 le tableau initial et son clone ne sont pas disjoints ee car ils partagent les mmes lments. Il faut se demander si cest cela quon voulait obtenir. Cette question e ee est reprise dans la section suivante. Note Java 5. La mthode clone tant introduite au niveau de la classe Object, elle est dclare comme e e e e rendant un rsultat de type Object ce qui, dans le cas des tableaux, obligeait jusqu` Java 1.4 ` lutiliser e a a 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 rserve un traitement e spcial ` lappel de clone sur un tableau de mani`re ` rendre correctes des expressions comme : e a e a Point[] t = new Point[n]; ... Point[] q = t.clone(); 3.6.2 Dnir la mthode clone e e

La mthode clone doit tre rednie dans chaque classe o` cela est utile ; elle doit tre public. Exemple : e e e u e 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 crire la mthode clone ` partir de rien, comme ci-dessus, mais on peut aussi allger ce travail e e a e et utilisant la mthode Object.clone() hrite de la classe Object. Pour cela, la classe quon crit doit e e e e comporter lnonc implements Cloneable; 14 sans quoi lexception CloneNotSupportedException sera e e lance ` lexcution. Exemple : e a e 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 rduit ` e a } // la version hrite de la classe Object e e }
13. Cas particulier remarquable : les matrices, qui sont des tableaux de tableaux. Puisque les tableaux sont des objets, il en rsulte que la mthode clone ne duplique pas les coecients des matrices, mme lorsque ceux-ci sont dun type primitif. e e e 14. Linterface Cloneable est enti`rement vide, lnonc implements Cloneable nest quune marque par laquelle le programe e e meur saccorde le permis dutiliser la mthode hrite Object.clone() . e e e

18

c H. Garreta, 2000-2010

TYPES

3.6

Copie et comparaison des objets

Leet de la mthode hrite Object.clone() est la cration dun objet de mme type que celui quon e e e e e clone, puis linitialisation de chacune des variables dinstance de lobjet cr par aectation de la variable ee dinstance correspondante de lobjet original. Cest donc une copie ` un niveau , moins supercielle que a la copie des rfrences, mais ce nest pas la vraie copie en profondeur : si des membres sont ` leur tour des ee a objets cette sorte de copie ne sut pas pour faire que lobjet clon soit enti`rement spar de lobjet original. e e e e Par exemple, la gure 6 montre ` quoi ressemblerait le couple form par un objet de la classe Rectangle, a e dnie ci-dessus, et son clone, crs par les instructions suivantes : e ee 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 ` un niveau que fait Object.clone() a Pour avoir une duplication compl`te la mthode clone aurait d tre crite comme ceci : e e ue e 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 mthode clone hrite de la classe Object soit alourdie e e e par la ncessit dattraper ou dclarer CloneNotSupportedException, puisque cette exception est susceptible e e e dtre lance, mme lorsque, comme ici, il est certain quelle ne sera pas lance (puisque lnonc implements e e e e e e Cloneable a bien t crit dans la dclaration de la classe). eee e Dans lexemple ci-dessus, cette exception a t dclare. On aurait pu aussi bien lattraper et la faire ee e e dispara (puisque que de toute faon elle ne sera pass lance) en crivant clone de cette mani`re : tre c e e e class Rectangle implements Cloneable { ... public Object clone() { try { // notre version de clone se rduit ` e a return super.clone(); // la version hrite de la classe Object e e } catch (CloneNotSupportedException e) { return null; } } ... }
c H. Garreta, 2000-2010

19

3.6

Copie et comparaison des objets

TYPES

3.6.3

Comparaison

Des remarques analogues aux prcdentes peuvent tre faites au sujet de loprateur de comparaison. Si e e e e a et b sont dun type classe ou tableau, la condition a == b ne traduit pas lgalit des valeurs de a et b, e e mais lgalit des rfrences. Autrement dit, cette condition est vraie non pas lorsque a et b sont des objets e e ee gaux, mais lorsque a et b sont le mme objet. e e Dans beaucoup de situations une telle notion dgalit est trop restrictive. Cest pourquoi tous les objets e e sont censs possder la mthode equals qui implmente une notion dgalit plus utile. e e e e e e 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 t bien dnie) ee e

La mthode equals est dnie une premi`re fois au niveau de la classe Object, o` elle nest rien de plus e e e u que lgalit des rfrences : e e ee class Object { ... public boolean equals(Object o) { return this == o; } } mais chaque classe peut la rednir pour en donner une version adapte au rle et aux dtails internes de e e o e ses instances. Pour notre classe Point voici une premi`re version, pas tr`s juste : e e class Point { ... public boolean equals(Point o) { return x == o.x && y == o.y; } }

// VERSION ERRONE !!! E

Bien que rpondant en partie aux besoins, cette version de Point.equals est errone car, ` cause du e e a type de largument, elle ne constitue pas une rednition de la mthode Object.equals(Object o) 15 . Voici e e 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 mthode ci-dessus est une vraie rednition de Object.equals, mais elle nest pas encore e e parfaite. Il faut savoir, en eet, que x instanceof K ne signie pas forcment que x est instance de K ( x e 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), ` la suite de a 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`me : e class Point { ... public boolean equals(Object o) {
15. Il nest pas lmentaire de comprendre pourquoi cette version simple de equals nest pas correcte. Il faut imaginer la ee condition p.equals(q) lorsque les valeurs de p et q sont des objets Point alors que la variable q est dclare de type Object (une e e telle situation se produit, par exemple, chaque fois quon consid`re une Collection dont les lments sont des objets Point). e ee Si q est dclare de type Object, p.equals(q) nutilisera pas notre mthode Point.equals(Point p), mais Obe e e ject.equals(Object o) qui nest pas rednie dans la classe Point. e

20

c H. Garreta, 2000-2010

TYPES

3.7

Cha nes de caract`res e

return o != null && o.getClass() == Point.class && ((Point) o).x == x && ((Point) o).y == y; } } Toute surcharge de la mthode Object.equals(Object o) doit tre une relation dquivalence (cest-`e e e a dire une relation binaire rexive, symtrique et transitive) telle que si x = null alors x.equals(null) est e e 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`res e


Les classes String et StringBuffer

Deux classes permettent de reprsenter les cha e nes de caract`res : e les instances de la classe String sont invariables ; une fois cres, les caract`res dont elles sont formes ee e e ne peuvent plus tre modis, e e les instances de la classe StringBuffer, au contraire, sont destines ` subir des oprations qui modient e a e les caract`res dont elles sont faites (remplacements, ajouts, suppressions, etc.). e Les dtails de lutilisation de ces deux classes, extrmement utiles lune et lautre, sont dcrits dans e e e la documentation de lAPI Java. Limitons-nous ici ` signaler certains privil`ges tout ` fait originaux et a e a intressants de la classe String : e 1. Il existe une notation spcique pour les constantes littrales : toute suite de caract`res encadre par e e e e des guillemets produit une instance de la classe String : String nom = "Gaston Lagaffe"; 2. Lopration de concatnation (mise bout ` bout) de deux cha e e a nes se note par loprateur 16 + : e String formule = "Monsieur " + nom; // vaut "Monsieur Gaston Lagaffe" 3. Toutes les classes poss`dent la mthode String toString(), qui renvoie une expression dun objet e e sous forme de cha de caract`res. La classe Object fournit une version minimale de cette mthode, ne e e chaque classe peut en donner une dnition plus adapte. Exemple : e e class Point { int x, y; ... public String toString() { return "(" + x + "," + y + ")"; } } 4. Loprateur +, lorsquun de ses oprandes est une cha e e ne, provoque la conversion de lautre oprande e vers le type cha Cette conversion est eectue ne. e dans le cas dun type primitif, par lappel dune des mthodes statiques valueOf de la classe String, e dans le cas dun objet, par lappel de sa mthode toString e Par exemple, si p est un objet Point (voir ci-dessus), lexpression "rsultat: " + p e quivaut ` lexpression e a "rsultat: " + p.toString() e dont la valeur est, par exemple, la cha "rsultat: (10,20)". ne e 5. La conversion vers le type cha est pratique galement par certaines mthodes dintrt gnral. Par ne e e e ee e e exemple, les mthodes print et println de la classe PrintStream (la classe de lobjet System.out) ont e des dnitions spciques pour les cas o` leur argument est dun type primitif ou String et rcup`rent e e u e e tous les autres cas ` laide de la mthode toString. Par exemple, on peut imaginer print(Object o) a e ainsi crite : e public void print(Object o) { print(o.toString()); } // print(Object) est ramene ` print(String) e a

16. Les programmeurs C++ noteront que cet emploi du + est le seul cas de surcharge dun oprateur en Java. e

c H. Garreta, 2000-2010

21

3.7

Cha nes de caract`res e

TYPES

3.7.2

Copie et comparaison des cha nes

1. Clone. La classe String ne comporte pas de mthode clone : puisque les instances de cette classe e sont immuables, il nest jamais ncessaire de les cloner. e 2. Equals. La classe String ore une version de la mthode equals dont il est facile dimaginer ce e quelle fait : parcourir les deux cha nes en comparant les caract`res correspondants. Deux cha e nes construites sparment lune de lautre doivent tre compares ` laide de cette mthode. Par exemple, si reponse est e e e e a e de type String, lexpression reponse == "oui" vaut souvent false indpendamment de la valeur de reponse et na donc aucun intrt. Il faut crire ` la e ee e a place reponse.equals("oui") ou bien "oui".equals(reponse).

3. Intern. La mthode equals est utile mais relativement onreuse, puisquelle doit examiner les deux e e cha nes en comparant les caract`re homologues. Les programmes qui comportent des comparaisons frquentes e e entre des cha nes (en nombre raisonnable) peuvent tirer avantage de la mthode intern() qui renvoie une e cha ayant les mmes caract`res que la cha donne, mais appartenant ` un ensemble de cha ne e e ne e a nes sans rptition, au sein duquel deux cha e e nes gales sont forcment la mme cha Lorsquune cha appartient e e e ne. ne a ` cet ensemble on dira quelle a t internalise. ee e Ainsi, par exemple, tant donnes deux variables s1 et s2 de type String, quelles que soient les valeurs e e des cha nes t1 et t2, ` la suite de a s1 = t1.intern(); s2 = t2.intern(); les conditions s1.equals(s2) et s1 == s2 sont quivalents (mais lvaluation de la deuxi`me est e e e videmment plus rapide). e Note. Les cha nes de caract`res constantes crites dans le programme source sont garanties internalises, e e e contrairement aux cha nes construites pendant lexcution (chaque appel de new doit produire la cration e e 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));

22

c H. Garreta, 2000-2010

EXPRESSIONS ET INSTRUCTIONS

Expressions et instructions

Cette section ridiculement courte est consacre aux dirences notables existant entre les expressions 17 e e et instructions de Java et celles de C. Bonne nouvelle : pour lessentiel, ce sont les mmes. Les expressions e sont formes avec les mmes oprateurs, les instructions emploient les mmes mots-cls, les unes et les autres e e e e e sont soumises aux mmes r`gles de syntaxe, renvoient les mmes valeurs et ont les mmes eets. e e e e Exceptions : deux mcanismes sont ralises de mani`re originale en Java et mritent dtre expliques, e e e e e e e mme dans un polycopi succinct comme celui-ci : e e linstruction de rupture tiquete, explique ci-dessous, e e e la boucle for amliore explique ` la section 12.3.2. e e e a

4.1

Rupture tiquete e e

Linstruction goto de certains langages nexiste pas ici. Cependant, an de bncier dun service impore e tant que cette instruction rend parfois, la ma trise de labandon des boucles imbriques, on a ajout ceci ` e e a Java : les instructions, et notamment les boucles (for, while, do...while, etc.), peuvent tre tiquetes, e e e linstruction break peut tre suivie dune tiquette an de provoquer labandon de plusieurs boucles e e imbriques au lieu dune seule. e Une tiquette est un identicateur quil nest pas ncessaire de dclarer ; il sut de lcrire, suivi de : , e e e e devant une instruction, pour quil soit connu ` lintrieur de celle-ci et inconnu ` lextrieur. a e a e Par exemple, le code purement dmonstratif suivant ache les dates comprises entre le 1er janvier e 2000 et le 30 dcembre 2005, en supposant que tous les mois ont 30 jours. A chaque achage, un entier e pseudo-alatoire de lintervalle [ 0, 100 [ est tir : si cest un multiple de 3, le mois en cours est abandonn e e e (on passe au 1er du mois suivant) ; si cest un multiple de 13, lanne en cours est abandonne (on passe au e e 1er janvier de lanne suivante) ; si le nombre est 0, le travail est abandonn : e 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 dtre dit ` propos de linstruction break tiquete sapplique mutatis mutandis ` linstruce a e e a tion continue qui peut, elle aussi, tre tiquete. Par exemple, voici une rdaction quivalente du bout de e e e e e programme prcdent : e e ... 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; } ...
17. Nous voulons parler ici des expressions ne mettant en jeu que des types primitifs

c H. Garreta, 2000-2010

23

CLASSES, PAQUETS, FICHIERS ET REPERTOIRES

Classes, paquets, chiers et rpertoires e

Lunit de compilation en Java est la classe. Un chier source se compose ncessairement de quelques e e classes compl`tes, souvent une seule, et le compilateur produit un chier compil (chier dextension .class) e e pour chaque classe rencontre dans le chier source, ft-elle une classe interne ou anonyme. e u La syntaxe de la dnition des classes est explique ` partir de la section 6.2. Ici nous nous intressons e e a e au regroupement des classes en paquets, et au rangement des classes et des paquets dans les chiers et les rpertoires. e

5.1

Paquets et classes

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

Quon le veuille on non, chaque classe appartient ` un paquet. Si on ne sest occup de rien, il sagit du a e paquet sans nom (unnamed package), qui contient toutes les classes pour lesquelles on na pas donn un nom e de paquet explicite. On peut changer cela ` laide de linstruction package, qui doit tre la premi`re instruction utile (i.e. a e e autre quun commentaire) du chier source : package nomDuPaquet; Toutes les classes dnies dans un chier commenant par la ligne prcdente appartiennent ipso facto e c e e au paquet nomm nomDuPaquet. Dautres chiers peuvent comporter cette mme instruction ; les classes e e quils dnissent appartiennent alors ` ce mme paquet. e a e Un nom de paquet est un identicateur ou une suite didenticateurs, chacun spar du suivant par un e e point. Trois exemples : monprojet, java.awt.event et fr.univ_mrs.dil.henri.outils. Les noms commenant par java. sont rservs aux paquets contenant les classes de la biblioth`que c e e e standard. Seul Sun Microsystems a le droit de les utiliser. Si vous crivez des programmes dun intrt vraiment gnral, vous devez pouvoir garantir que les noms e ee e e de vos paquets sont uniques dans le monde entier. Le syst`me propos par Sun pour nommer ces paquets ` e e a vocation plantaire consiste ` utiliser les lments de votre nom de domaine Internet, placs ` lenvers. e a ee e a Par exemple, si votre domaine est dil.univ-mrs.fr alors vos paquets pourront tre nomms comme e e ceci 18 : package fr.univ_mrs.dil.unProjet.outils; 5.1.2 Les noms des classes et linstruction import

Chaque classe poss`de un nom court, qui est un identicateur, et un nom long form en prxant le nom e e e 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 tre dsigne 19 par son nom long. Elle peut en outre tre dsigne par son nom e e e e e e court : depuis [toute mthode de] toute classe du mme paquet ; e e depuis [toute mthode de] toute classe crite dans un chier qui comporte linstruction : e e 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 ` la formule prcdente plus deet quelle nen a : unPaquet.* signie a e e les classes du paquet unPaquet, cela ninclut pas les classes des ventuels sous-paquets (les paquets dont e les noms commencent par unPaquet). Ainsi, les deux directives suivantes, dun usage frquent, ne sont pas e redondantes, la premi`re nimplique pas la deuxi`me : e e import java.awt.*; import java.awt.event.*; // les classes du paquet java.awt // les classes du paquet java.awt.event

18. Les lments dun nom de paquet doivent tre des identicateurs. Cest la raison pour laquelle les ventuels tirets - doivent ee e e tre remplacs, comme ici, par des blancs souligns _. e e e 19. Quune classe puisse ou doive tre dsigne par tel ou tel nom ne prjuge en rien du fait quon ait on non le droit daccder e e e e e ` ses membres ; cela dpend du contexte et de r`gles expliques ` la section 6.4. a e e e a

24

c H. Garreta, 2000-2010

CLASSES, PAQUETS, FICHIERS ET REPERTOIRES

5.2

Classes, chiers et rpertoires e

Note 2. Dans certains cas lutilisation des noms longs des classes reste ncessaire pour viter des ambie e gu es. Par exemple, List est une classe du paquet java.awt et une interface du paquet java.util. Dans t un chier o` les deux sont employes (ce nest pas rare), on ne peut pas utiliser le nom court dans les deux u e cas. Note 3. On entend parfois : il faut crire telle instruction import pour avoir le droit dutiliser telle e classe . Cela nest jamais vrai : linstruction import ne sert pas ` rendre visibles des classes (toutes les a classes qui se trouvent dans des chiers et rpertoires que la machine Java peut atteindre sont visibles 20 ) ni e a ` vous donner le droit dacc`s ` des classes (cela se pilote ` travers les qualications public, private, etc., e a a 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, dsigner par son nom long. e Note 4. Le paquet java.lang est spcial : ses classes peuvent tre dsignes par leur nom court sans quil e e e e soit ncessaire dcrire import java.lang.* en tte du chier. Ce paquet est fait de classes fondamentales, e e e qui font partie de la dnition du langage Java lui-mme : Object, String, Math, System, Integer, etc. Sil e e fallait crire import java.lang.* pour les utiliser, alors il faudrait lcrire dans tous les chiers. e e

5.2
5.2.1

Classes, chiers et rpertoires e


Classes publiques et non publiques

La dclaration dune classe peut tre prcde ou non du qualieur public. Si ce nest pas le cas, la e e e e e classe est dite non publique et elle nest accessible que depuis les [mthodes des] autres classes du mme e e paquet 21 . Si la dclaration dune classe est prcde du qualieur public alors la classe est dite publique ; elle est e e e e accessible depuis [les mthodes de] toutes les classes de tous les paquets. e Si un chier source contient une classe publique, le nom du chier doit tre le nom de cette classe, e complt par lextension .java . Par exemple, un chier contenant le texte ee public class Point { ... dnition de la classe Point e ... } doit se nommer Point.java. Il en dcoule quun chier source ne peut pas contenir plus dune classe publique. e En rsum, mis ` part les commentaires, un chier source est donc compos des lments suivants, dans e e a e ee lordre indiqu : e ventuellement, une instruction package ; e ventuellement, une ou plusieurs instructions import ; e une ou plusieurs classes, dont au plus une est publique ; elle impose alors son nom au chier. 5.2.2 Point dentre dun programme. e

Une classe est dite excutable si, et seulement si elle comporte une mthode de signature e e public static void main(String[] args) (chaque mot de lexpression prcdente est impos strictement, sauf args). Le lancement de lexcution dune e e e e application Java quivaut ` lappel de la mthode main dune classe excutable ; si on travaille ` une console, e a e e a cela se fait par la commande java NomDeLaClasse argum1 . . . argumk Largument args de main est un tableau dont les lments sont les cha ee nes argum1 . . . argumk qui gurent dans la commande qui a lanc le programme. Par exemple, voici un programme qui ache n fois un certain e mot m, n et m tant donns lors du lancement. Fichier Radotage.java : e e
20. Linstruction import nest donc pas lhomologue en Java de la directive #include du langage C 21. Les classes non publiques reprsentent donc des services oerts aux autres classes du mme paquet, non des fonctionnalits e e e universelles dont nimporte quel utilisateur peut avoir besoin (cela est le rle des classes publiques). o

c H. Garreta, 2000-2010

25

5.2

Classes, chiers et rpertoires e

CLASSES, PAQUETS, FICHIERS ET REPERTOIRES

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 excution de ce programme (dans le cas dexcution prsent ici, args[0] est la cha e e e e ne "5" et args[1] la cha "bonsoir") : ne > javac Radotage.java > java Radotage 5 bonsoir bonsoir bonsoir bonsoir bonsoir bonsoir > 5.2.3 O` placer les chiers des classes ? u

Un procd, qui dpend plus ou moins du syst`me dexploitation sous-jacent, associe ` chaque paquet e e e e a un rpertoire dans lequel doivent se trouver les chiers compils (chiers dextension .class) des classes du e e paquet ; il consiste ` utiliser la structure hirarchique du syst`me de chiers pour reproduire la structure a e e hirarchique des noms des paquets. e Ainsi, par exemple, les chiers des classes des paquets java.awt.event et monprojet.outils doivent tre placs, respectivement, dans des rpertoires nomms, sur Unix, java/awt/event/ et monprojet/mese e e e outils/. Sur Windows, ces rpertoires seraient java\awt\event\ et monprojet\mesoutils\. e Ces chemins sont relatifs 22 aux rpertoires suivants : e par dfaut, le rpertoire courant (nomm gnralement . ), e e e e e chacun des rpertoires de la liste dnie par la valeur de la variable denvironnement CLASSPATH, lorsque e e cette variable est dnie 23 (le cas par dfaut nest alors pas considr), e e ee chacun des rpertoires de la liste dnie par la valeur de largument -cp ou -classpath, si cet argument e e a t spci lors du lancement de la machine java (lventuelle valeur de la variable CLASSPATH et le ee e e e cas par dfaut sont alors ignors). e e Note. Parfois les classes intervenant dans une compilation ou une excution sont prises dans un chier e .jar. Il faut savoir que, fondamentalement, un tel chier nest que la forme zippe dune arborescence e de rpertoires et les indications prcdentes sappliquent pratiquement telles quelles, le chier .jar jouant e e e le rle de rpertoire de base. o e Pour obtenir que le compilateur place les chiers compils dans un certain rpertoires, en le crant sil e e e nexiste pas, il faut lancer la compilation avec loption -d rpertoireDeBase . Par exemple, si on souhaite e que les noms des paquets correspondent ` des chemins relatifs au rpertoire courant (dsign par . ) il a e e e faut activer le compilateur par la commande : javac -d . MaClasse.java Ainsi, si le chier MaClasse.java contient une classe nomme MaClasse et commence par linstruction e package monPaquet la commande prcdente produira un chier appel MaClasse.class plac dans un e e e e sous-rpertoire monPaquet du rpertoire courant . e e Si MaClasse est une classe excutable, on la lancera alors depuis le rpertoire courant par lune ou lautre e e des commandes : java monPaquet/MaClasse (sur UNIX) ou java monPaquet\MaClasse (sur Windows) ou java monPaquet.MaClasse (indpendamment du syst`me) e e ` Ou placer les fichiers sources ? Il est conseill de suivre la mme r`gle pour le placement des e e e chiers sources (chiers .java). Si on veut que la compilation dune classe C produise la compilation des
22. Si r est un rpertoire dni par un chemin absolu (i.e. partant de la racine du syst`me de chiers) A, on dit quun chemin e e e B est relatif a r pour indiquer que B reprsente le chemin absolu obtenu en concatnant A et B. ` e e Par exemple, si le chemin monProjet/mesOutils/ est relatif au rpertoire /home/henri/ alors il dnit le chemin absolu e e /home/henri/monProjet/mesOutils/. 23. Dans les versions rcentes du SDK, sauf besoin spcique il vaut mieux ne pas jouer avec la variable CLASSPATH. Sils ont e e t bien installs, le compilateur et la machine Java acc`dent normalement a toutes les biblioth`ques de classes dont ils ont e e e e ` e besoin dans le cadre dune utilisation normale de Java.

26

c H. Garreta, 2000-2010

CLASSES, PAQUETS, FICHIERS ET REPERTOIRES

5.2

Classes, chiers et rpertoires e

classes dont C dpend 24 , ces derni`res doivent se trouver dans les rpertoires qui correspondent ` leurs e e e a paquets. Par exemple, si le chier MaClasse.java commence par linstruction package monPaquet; alors il vaut mieux placer ce chier dans le rpertoire monPaquet. Sa compilation sera alors provoque e e 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 prcdente on a expliqu o` placer les classes pour que lexcution dun programme se e e e u e passe bien, du moins lorsquelle a lieu sur la machine sur laquelle on a fait le dveloppement. Mais que se e passe-t-il lorsquun programme dvelopp sur une machine doit tre excut sur une autre ? e e e e e Dans le cas gnral, la compilation dune application produit de nombreux chiers classes, ventuellement e e e rangs dans dirents rpertoires (autant de rpertoires que de paquetages en jeu). Il en rsulte que, alors e e e e e que pour dautres langages une application correspond ` un chier executable, en Java une application se a prsente comme une pluralit de chiers et de rpertoires ; une telle organisation rend complexe et risque e e e e la distribution des applications. Cest pourquoi les excutables Java sont distribus sous la forme darchives e e zip ou, plutt, jar 25 , quil faut savoir fabriquer. Expliquons cela sur un exemple : o Imaginons quune application se compose des classes Principale, Moteur, Fenetres, etc., le point dentre cest-`-dire la mthode par laquelle lexcution doit commencer 26 tant dans la classe Principale. e a e e e La compilation de ces classes a produit les chiers Principale.class, Moteur.class, Fenetres.class, etc. Avec un diteur de textes quelconque, composez un chier nomm MANIFEST.MF comportant lunique e e 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 rpertoire de travail, e vous pouvez taper la commande prcdente sous la forme e e jar -cvfm Appli.jar MANIFEST.MF *.class Cela produit un chier nomm Appli.jar que, si vous tes curieux, vous pouvez examiner avec nimporte e e quel outil comprenant le format zip : vous y trouverez tous vos chiers .class et un rpertoire nomm e 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 excuter votre application pourra e le faire en tapant la commande 27 java -jar Appli.jar ou bien java -classpath Appli.jar Principale Dans ce dernier cas, lapplication sexcuterait correctement mme si larchive ne contenait pas de chier e e manifeste, voire si au lieu de Appli.jar on avait utilis une archive Appli.zip tout ` fait ordinaire. e a

24. En principe, la compilation dune classe C produit la compilation des classes que C mentionne, pour lesquelles cela est utile, cest-`-dire celles qui ont t modies depuis leur derni`re compilation. Cest un mcanisme proche de la commande a e e e e e make de Unix mais lexprience montre quil y a parfois des rats (des classes qui le devraient ne sont pas recompiles). e e e 25. En ralit une archive jar est la mme chose quune archive zip, sauf quune archive jar est cense contenir sans que la e e e e chose soit rdhibitoire un chier manifest. e 26. Le point dentre est la premi`re instruction dune mthode qui doit avoir le prototype public static void e e e main(String[] args), mais que rien nempche que des mthodes ayant ce prototype existent aussi dans plusieurs autres e e classes de lapplication. 27. Sur un syst`me Windows correctement congur, on pourra mme excuter lapplication en double-cliquant sur licne du e e e e o chier jar. Dans ce cas, il y a intrt ` ce quil sagisse dune application qui cre sa propre interface-utilisateur (par exemple, e e a e graphique) car autrement les entres-sorties seront perdues, faute de console. e

c H. Garreta, 2000-2010

27

LES OBJETS

6
6.1

Les objets
Introduction : les langages orients objets e

Java est un langage orient objets. Pour xer les ides, voici une prsentation tr`s sommaire dune partie e e e e du jargon et des concepts de base de cette famille de langages 28 . Objet. Les entits lmentaires qui composent les programmes sont les objets. Un objet est constitu par e ee e lassociation dune certaine quantit de mmoire, organise en champs quon appelle des variables dinstance, e e e et dun ensemble doprations (fonctions, procdures...) quon appelle des mthodes. e e e Contrle de laccessibilit. Les variables et les mthodes peuvent tre qualies publiques, cest-`-dire o e e e e a accessibles depuis nimporte quel point du programme, ou prives, cest-`-dire accessibles uniquement depuis e a les mthodes de lobjet en question. e Encapsulation. Un objet est vu par le reste du programme comme une entit opaque : on ne peut modier e son tat, cest-`-dire les valeurs de ses variables, autrement quen faisant faire la modication par une de ses e a mthodes publiques 29 . Lensemble des mthodes publiques dun objet sappelle son interface 30 . e e Limportante proprit suivante est ainsi garantie : un objet ne dpend pas des implmentations (cestee e e a `-dire les dtails internes) dautres objets, mais uniquement de leurs interfaces. e Message. Un message est une requte quon soumet ` un objet pour quil eectue une de ses oprations. e a e En pratique, cela se traduit par lappel dune mthode de lobjet. Le message spcie quelle opration doit e e e tre eectue, mais non comment elle doit ltre : il incombe ` lobjet rcepteur du message de conna les e e e a e tre modalits eectives que prend pour lui lexcution de lopration en question. e e e Appellation orient objets . Du point de vue du concepteur, toute procdure ou fonction appartient ` e e a un objet ; elle spcie comment un objet donn ragit ` un message donn. Dans la programmation oriente e e e a e e objets les entits les plus extrieures sont les objets, les actions sont dnies ` lintrieur des objets, comme e e e a e attributs de ces derniers. Cela soppose ` la programmation traditionnelle, ou oriente actions , o` les entits les plus extrieures a e u e e sont les actions (procdures, fonctions, routines, etc.) les objets se dnissant de mani`re subordonne aux e e e e actions (ils en sont les donnes, les rsultats, etc.). e e Classe. Une classe est la description des caractristiques communes ` tous les objets qui reprsentent e a e la mme sorte de chose. Vue de lextrieur, elle dnit donc leur interface commune, seul aspect public e e e des objets. Vue de lintrieur, cest-`-dire comme son concepteur la voit, la classe dnit la structure de la e a e mmoire prive de ces objets (les variables dinstance) et les rponses aux messages de leurs interfaces (les e e e corps des mthodes). e Instance 31 . Les objets individuels dcrits par une classe sont ses instances. Chaque objet est instance e dune classe. Il ny a pas dinconvnient ` identier la notion de classe avec celle de type, les instances e a sidentient alors avec les valeurs du type : la classe est le type de ses instances. Linstanciation est lopration par laquelle les objets sont crs. Cest une notion dynamique (mme dans e ee e les langages ` types statiques) : tout objet est cr (a) enti`rement garni et (b) ` un moment bien dtermin a ee e a e e de lexcution dun programme. e

6.2
6.2.1

Classes, variables et mthodes e


Dclaration des classes et des objets, instanciation des classes e

Fondamentalement, une classe est constitue par un ensemble de membres, qui reprsentent e e des donnes, on les appelle alors variables, champs, ou encore donnes membres, e e des traitements, on les appelle alors mthodes ou fonctions membres. e La syntaxe de la dclaration dune classe est la suivante : e
28. Nous traitons ici de laspect encapsulation des langages orients objets. On introduira plus loin les concepts lis ` lhritage. e e a e 29. En Java, la possibilit davoir des variables dinstance publiques temp`re cette armation. e e 30. Attention, en Java le mot interface a un sens technique bien prcis, voir la section 7.7.3 e 31. Le mot instance est tr`s souvent employ en programmation oriente objets, avec le sens expliqu ici (qui se rsume tout e e e e e entier dans lincantation chaque objet est une instance de sa classe ). Si ce mot vous pose un probl`me, ne cherchez pas de e laide parmi les sens quil a dans la langue franaise, aucun ne convient. Il a t emprunt par les p`res fondateurs de la POO c e e e e ` la langue anglaise, o` entre autres choses, instance signie cas, comme dans cas particulier. a u

28

c H. Garreta, 2000-2010

LES OBJETS

6.2

Classes, variables et mthodes e

visibilit class identicateur { e dclaration dun membre e ... dclaration dun membre e } ou visibilit est soit rien, soit le mot public (la classe est alors dite publique, voyez la section 5.2.1). e Les membres des classes se dclarent comme les variables et les fonctions en C, sauf quon peut les prxer e e par certains qualieurs, private, public, etc., expliqus plus loin. Exemple : e class Point { int x, y; // coordonnes cartsiennes e e 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 donnes : ` la suite dune dclaration comme la prcdente, on pourra dclarer e a e e e e des variables de type Point, cest-`-dire des variables dont les valeurs sont des instances de la classe Point a et ont la structure dnie par cette derni`re. Exemple : e e Point p; // dclaration dune variable Point e

Notez bien que la dclaration prcdente introduit une variable p qui pourra rfrencer des instances de e e e ee la classe Point, mais qui, pour le moment, ne rfrence rien. Selon son contexte, une dclaration comme la ee e prcdente donnera ` p : e e a soit la valeur null, dans le cas de la dclaration dune variable membre, e soit une valeur conventionnelle variable non initialise , dans le cas de la dclaration dune variable e e locale dune mthode. e On obtient que p soit une rfrence valide sur un objet soit en lui aectant une instance existante, soit ee en lui aectant une instance nouvellement cre, ce qui scrit : ee e p = new Point(); // cration dune nouvelle instance de la classe Point e

La justication des parenth`ses ci-dessus, et dautres informations importantes sur linstanciation et linitiae lisation des objets, sont donnes ` la section 6.5.1. e a Note. Etant donne une classe C, on dit indiremment instance de la classe C ou objet C. e e 6.2.2 Instances et membres dinstance

La dclaration donne en exemple ` la section prcdente introduit une classe Point, comportant pour e e a e e le moment deux variables dinstance, x et y, et deux mthodes dinstance, montre et distance. En disant e que ces lments sont des variables et des mthodes dinstance de la classe Point on veut dire que chaque ee e instance en a sa propre version , cest-`-dire : a pour les variables, quil en existe un jeu dirent dans chaque instance, disjoint de ceux des autres e instances : chaque objet Point a sa propre valeur de x et sa propre valeur de y, pour les mthodes, quelles sont lies ` un objet particulier : un appel de la mthode montre na de e e a e sens que sil est adress ` un objet Point (celui quil sagit de montrer). ea Ainsi, sauf dans quelques situations particuli`res que nous expliciterons plus loin, pour accder ` un e e a membre dinstance il faut indiquer linstance concerne. Cela se fait par la mme notation que lacc`s aux e e e champs des structures en C : p.x p.montre() : un acc`s ` la variable dinstance x de lobjet p e a : un appel de la mthode montre sur lobjet p e

Lexpression p.montre() est la version Java de la notion, fondamentale en programmation oriente objets, e envoyer le message montre ` lobjet p . A priori, le mme message pourrait tre envoy ` des objets a e e e a dirents. Il incombe ` chaque destinataire, ici p, de conna e a tre les dtails prcis que prend pour lui la e e raction au message montre. e
c H. Garreta, 2000-2010

29

6.2

Classes, variables et mthodes e

LES OBJETS

` ` Acces a ses propres membres. Ainsi, une mthode dinstance est ncessairement appele ` travers e e e a un objet, le destinataire du message que la mthode reprsente. Dans le corps de la mthode, cet objet est e e e implicitement rfrenc par toutes les expressions qui mentionnent des membres dinstance sans les associer ee e a ` un objet explicite. Par exemple, dans la mthode distance de la classe Point : e ... 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 dsignent les coordonnes de lobjet ` travers lequel on aura appel e e a e la mthode distance. Dautre part, les expressions p.x et p.y dsignent les coordonnes de lobjet qui aura e e e t mis comme argument de cet appel. ee Ainsi, ` loccasion dun appel de la forme (a et b sont des variables de type Point) : a a.distance(b); le corps de la mthode distance quivaut ` la suite dinstructions : e e a { int dx = a.x - b.x; int dy = a.y - b.y; return Math.sqrt(dx * dx + dy * dy); } ` ` Acces a soi-meme. A lintrieur dune mthode dinstance, lidenticateur this dsigne lobjet ` travers e e e a lequel la mthode a t appele. Par exemple, la mthode distance prcdente peut aussi scrire, mais ici e ee e e e e e cela na gu`re davantages 32 , comme ceci : e ... 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` lemploi de this est ncessaire, imaginez quon nous oblige ` crire la mthode u e ae e dinstance distance en la ramenant ` un appel dune mthode de classe : a e static int distanceSymetrique(Point a, Point b); cest-`-dire une mthode qui, comme une fonction en C, nest pas attache ` une instance particuli`re et a e e a e calcule la distance entre les deux points donns comme arguments. Cela donnerait : e ... int distance(Point p) { return distanceSymetrique(this, p); } ... 6.2.3 Membres de classe (membres statiques)

Les membres de classe sont ceux dont la dclaration est qualie par le mot rserv static 33 : e e e e 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 // mthode dinstance e

// mthode de classe e

32. Notez cependant que certains stylistes de la programmation en Java recommandent demployer systmatiquement la e 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 ` un lecteur du programme de distinguer plus facilement ces deux a sortes de membres lors de leur utilisation. 33. Par la suite on dira indiremment membre de classe ou membre statique et membre dinstance ou membre non statique. e

30

c H. Garreta, 2000-2010

LES OBJETS

6.2

Classes, variables et mthodes e

return Math.abs(p.x - q.x) + Math.abs(p.y - q.y); } } Contrairement aux membres dinstance, les membres de classe ne sont pas attachs aux instances. Ce qui e 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 par lexcution du programme, de chaque variable de classe il est ee e cr la premi`re fois que la classe intervient dans lexcution du programme un unique exemplaire ee e e auquel toutes les instances acc`dent, e pour une mthode, quon peut lappeler sans devoir passer par un objet. Lappel dune mthode de e e classe ne se fait pas en faisant rfrence explicitement ou implicitement ` une instance particuli`re ee a e (autre que celles qui gurent ventuellement ` titre de param`tres) ; un tel appel ne peut dont pas tre e a e e vu comme un message adress ` un objet. ea Consquence importante : ` lintrieur dune mthode de classe, lobjet this (objet implicite ` travers e a e e a lequel une mthode dinstance est ncessairement appele) nest pas dni. e e e e Ainsi lexpression suivante, par exemple crite dans une mthode trang`re ` la classe Point : e e e e a Point.nombre est un acc`s bien crit ` la variable de classe nombre et, p et q tant des objets Point, lexpression e e a e Point.distanceSymetrique(p, q) est un appel correct de la mthode de classe distanceSymetrique. e Remarque 1. On notera que les deux expressions prcdentes peuvent scrire aussi e e e p.nombre p.distanceSymetrique(p, q) (le prxe p. ne sert ici qu` indiquer quil sagit des membres nombre et distance de la classe Point ; ces e a expressions ne font aucun usage implicite de lobjet p) mais ces notations sont trompeuses et dconseilles e e car elles donnent aux acc`s ` des membres de classe lapparence dacc`s ` des membres dinstance. e a e a Remarque 2. On aura compris que les mthodes de classe sont ce qui se rapproche le plus, en Java, des e fonctions autonomes , comme celles du langage C. Par exemple, la mthode Math.sqrt, mentionne plus e e haut, nest rien dautre que la fonction racine carre qui existe dans toutes les biblioth`ques mathmatiques. e e e Lobligation denfermer de telles fonctions dans des classes nest pas une contrainte mais une richesse, puisque cela permet davoir, dans des classes direntes, des fonctions qui ont le mme nom. e e De mme, la notion de variable de classe est voisine de celle de variable globale du langage C. De e telles variables existent d`s que la classe est charge, cest-`-dire la premi`re fois quelle intervient dans le e e a e programme, jusqu` la terminaison de celui-ci. a Remarque 3. Pour bien mettre en vidence les dirences entre les membres de classe et les membres e e dinstance, examinons une erreur quon peut faire quand on dbute : e 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 mthode test ne peut tre appele quen se rfrant, explicitement ou implicitement, ` e e e ee a un objet, alors que main tant static, elle nest lie ` aucun objet (en fait, dans ce programme on ne cre e e a e aucune instance de la classe Essai). Deux solutions. La premi`re consiste ` crer une instance, ventuellement un peu articielle, permettant e a e e dappeler test en passant par un objet :
c H. Garreta, 2000-2010

31

6.3

Surcharge des noms

LES OBJETS

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

6.3

Surcharge des noms

En Java les noms peuvent tre surchargs : un mme nom peut dsigner plusieurs entits distinctes, ` e e e e e a la condition que lors de chaque utilisation du nom le compilateur puisse dterminer sans erreur quelle est e lentit dsigne. e e e En pratique, cela signie quon peut donner le mme nom e ` des entits dont les rles syntaxiques sont dirents, comme une classe et un membre, ou bien une a e o e variable et une mthode, e ` des membres de classes distinctes, a ` des mthodes de la mme classe ayant des signatures 34 direntes. a e e e Par exemple, dans la classe Math on trouve, parmi dautres, les mthodes int abs(int x) (valeur absolue e 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 mthode eectivement appele est celle qui correspond au type eectif de v. Lintrt de ce mcanisme e e ee e est facile ` voir : il dispense le programmeur davoir ` conna toute une srie de noms dirents (un pour a a tre e e chaque type dargument) pour nommer les diverses implmentations dun mme concept, la valeur absolue e e dun nombre. On notera que le type du rsultat dune mthode ne fait pas partie de sa signature : deux mthodes dune e e e mme classe, ayant les mmes types darguments mais dirant par le type du rsultat quelles rendent ne e e e e peuvent pas avoir le mme nom. e Remarque. Il ne faut pas confondre la surcharge avec la rednition des mthodes, que nous expliquerons e e a ` la section 7.3 : 1. La surcharge des mthodes consiste dans le fait que deux mthodes, souvent membres de la mme e e e classe, ont le mme nom mais des signatures direntes. Sur un appel de mthode faisant appara e e e tre ce nom, la dtermination de la mthode quil faut eectivement appeler est faite dapr`s les arguments e e e de lappel. Cest un probl`me statique, cest-`-dire rsolu pendant la compilation du programme. e a e 2. La rednition des mthodes consiste dans le fait que deux mthodes ayant le mme nom et la mme e e e e e signature sont dnies dans deux classes dont lune est sous-classe, directe ou indirecte, de lautre. e Nous verrons que, sur lappel dune mthode ayant ce nom, la dtermination de la mthode quil faut e e e eectivement appeler est faite dapr`s le type eectif de lobjet destinataire du message. Cest un e mcanisme dynamique, qui intervient au moment de lexcution du programme. e e
34. La signature dune mthode est la liste des types des ses arguments. e

32

c H. Garreta, 2000-2010

LES OBJETS

6.4

Contrle de laccessibilit o e

6.4
6.4.1

Contrle de laccessibilit o e
Membres privs, protgs, publics e e e

La dclaration dun membre dune classe (variable ou mthode, dinstance ou de classe) peut tre qualie e e e e par un des mots rservs private, protected ou public, ou bien ne comporter aucun de ces qualieurs. e e Cela fonctionne de la mani`re suivante : e membres privs : un membre dune classe C dont la dclaration commence par le qualieur private e e nest accessible que depuis [les mthodes de] la classe C ; cest le contrle dacc`s le plus restrictif, e o e un membre dune classe C dont la dclaration ne commence pas par un des mots private, protected e ou public est dit avoir laccessibilit par dfaut ; il nest accessible que depuis [les mthodes de] la e e e classe C et les autres classes du paquet auquel C appartient, membres protgs : un membre dune classe C dont la dclaration commence par le qualieur protected e e e nest accessible que depuis [les mthodes de] la classe C, les autres classes du paquet auquel C appartient e et les sous-classes, directes ou indirectes, de C, membres publics : un membre de la classe C dont la dclaration commence par le qualieur public est e accessible partout o` C est accessible ; cest le contrle dacc`s le plus permissif. u o e Le concept de membre protg est li ` la notion dhritage. Pour cette raison, ces membres sont expliqus e e ea e e plus en dtail ` la section 7.5 (page 45). e a 6.4.2 Lencapsulation

Quand on dbute dans la programmation oriente objets on peut trouver que le contrle de laccessibilit e e o e est une chinoiserie peu utile. Il faut comprendre, au contraire, que cette question est un lment fondamental ee de la mthodologie. e En eet, nous cherchons ` crire des programmes les plus modulaires possibles, or lencapsulation est a e lexpression ultime de la modularit : faire en sorte que chaque objet du syst`me que nous dveloppons e e e ne puisse pas dpendre de dtails internes des autres objets. Ou, dit autrement, garantir que chaque objet e e sappuie sur les spcications des autres, non sur leurs implmentations. e e Il en dcoule une r`gle de programmation simple : tout membre qui peut tre rendu priv doit ltre 35 . e e e e e Pour illustrer cette question, considrons notre classe Point, et supposons que nous souhaitions permettre e a ` ses utilisateurs daccder ` labscisse et a lordonne des points. Premi`re solution, rendre les membres x e a ` e e et y publics : class Point { public int x, y; ... } Exemple dutilisation : si p est un objet Point, pour transformer un point en son symtrique par rapport ` e a laxe des abscisses il sura dcrire : e p.y = - p.y; Voici une autre dnition possible de la classe Point : e 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 dnition, pour transformer un point p en son symtrique par rapport ` laxe des abscisses il faut e e a crire : e p.setPos(p.getX(), - p.getY());
35. Certains langages vont plus loin, et font que toutes les variables sont doce prives. Java permet de dclarer des variables e e dinstance et de classe publiques ; notre propos ici est de dconseiller de telles pratiques. e

c H. Garreta, 2000-2010

33

6.5

Initialisation des objets

LES OBJETS

Malgr les apparences, la deuxi`me mani`re est la meilleure, car elle respecte le principe dencapsulation, e e e ce que ne fait pas la premi`re. Dabord, cette deuxi`me dnition permet de garantir la cohrence interne e e e e des objets crs par les utilisateurs de la classe Point, y compris les plus tourdis, puisque le seul moyen ee e de modier les valeurs des variables dinstance x et y est dappeler la mthode setPos, dans laquelle le e concepteur de la classe a crit le code qui valide ces valeurs (partie validation de a et b ). e Ensuite, la deuxi`me dnition garantit quaucun dveloppement utilisant les objets Point ne fera ine e e tervenir des dtails de limplmentation de cette classe, puisque les variables dinstance x et y sont prives, e e e cest-`-dire inaccessibles. Par exemple, si un jour il devenait ncessaire de reprsenter les points par leurs a e e coordonnes polaires au lieu des coordonnes cartsiennes, cela pourrait tre fait sans rendre invalide aucun e e e e programme utilisant la classe Point puisque, vu de lextrieur, le comportement de la classe Point serait e 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 cration dun objet est toujours dynamique : elle consiste en un appel de loprateur new, et e e peut se produire ` nimporte quel endroit dun programme. Il faut savoir que les variables dinstance des a objets ne restent jamais indtermines, elles ont des valeurs initiales prcises. e e e Un lment de la mthodologie objet, tr`s important pour la qualit des programmes, est que le concepteur ee e e e dune classe ma trise compl`tement les actions ` faire et les valeurs initiales ` donner lors de la cration des e a a e instances ; il peut ainsi garantir que les objets sont, d`s leur cration, toujours cohrents. e e e Notons pour commencer que, sil ny a pas dautres indications, Java donne une valeur initiale ` chaque a membre dune classe. Pour les membres de types primitifs, la valeur initiale correspondant ` chaque type a est celle quindique le tableau 1 (page 10). Pour les membres dautres types, cest-`-dire les tableaux et les a objets, la valeur initiale est null. Ainsi, sans que le programmeur nait ` prendre de prcaution particuli`re, a e e les instances dune classe dclare comme ceci e e class Point { int x, y; ... } sont des points ayant (0, 0) pour coordonnes. e Lorsque linitialisation souhaite est plus complexe que linitialisation par dfaut, mais assez simple pour e e scrire comme un ensemble daectations indpendantes de linstance particuli`re cre, on peut employer e e e ee une notation analogue ` celle de C. Par exemple, voici une classe Point dont les instances sont des points a alatoirement disposs dans le rectangle [0, 600[[0, 400[ : e e 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 dpend dle ee ments lis au contexte dans lequel lobjet est cre, la notation prcdente est insusante. Il faut alors dnir e ee e e e un ou plusieurs constructeurs, comme expliqu ` la section suivante. ea 34
c H. Garreta, 2000-2010

LES OBJETS

6.5

Initialisation des objets

6.5.1

Constructeurs

Un constructeur dune classe est une mthode qui a le mme nom que la classe et pas de type du rsultat 36 . e e e 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 de la mme mani`re : lors de la cration dun objet, cest-`-dire e e e e a comme oprande de loprateur new : e e 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 loprateur new qui rend quelque chose, ` savoir une rfrence sur lobjet nouveau), son e a ee rle est dinitialiser les variables dinstance de lobjet en cours de cration, et plus gnralement deectuer o e e e toutes les oprations requises par la cration de lobjet. e e Comme les autres mthodes, les constructeurs peuvent tre qualis public, protected ou private, ou e e e avoir laccessibilit par dfaut. Une situation utile et frquente est celle montre ci-dessus : un ou plusieurs e e e e constructeurs publics servant surtout ` initialiser un ensemble de variables dinstance prives. a e La surcharge des mthodes vaut pour les constructeurs : une classe peut avoir plusieurs constructeurs, e qui devront alors direr par leurs signatures : e 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 lintrieur dun constructeur lidenticateur this utilis comme un nom de variable dsigne (comme e e e dans les autres mthodes dinstance) lobjet en cours de construction. Cela permet parfois de lever certaines e ambigu es ; par exemple, le constructeur ` deux arguments donn plus haut peut scrire aussi 37 : t a e e class Point { private int x, y; public Point(int x, int y) { validation de x et y this.x = x; this.y = y; } ... }
36. Nous lavons dj` dit, le type du rsultat dune mthode ne fait pas partie de sa signature. Nanmoins, le fait davoir ou ea e e e non un type du rsultat est un lment de la signature. Il en dcoule que, par exemple, dans une certaine classe Point peuvent e ee e coexister un constructeur Point() et une mthode void Point() distincts. e 37. Parfois les noms des arguments des mthodes ne sont pas indirents, ne serait-ce quen vue de la documentation (ne pas e e oublier que loutil javadoc fabrique la documentation ` partir du code source). a

c H. Garreta, 2000-2010

35

6.5

Initialisation des objets

LES OBJETS

A lintrieur dun constructeur, lidenticateur this, utilis comme un nom de mthode, dsigne un autre e e e e constructeur de la mme classe (celui qui correspond aux arguments de lappel). Par exemple, voici une autre e mani`re dcrire le second constructeur de la classe Point montre plus haut : e e e 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 il doit tre la premi`re instruction du constructeur. t, e e Note 2. Lexpression qui cre un objet, new UneClasse() , se prsente toujours comme lappel dun e e constructeur, mme lorsque le programmeur na crit aucun constructeur pour la classe en question. Tout se e e passe comme si Java avait dans ce cas ajout ` la classe un constructeur implicite, rduit ` ceci : ea e a UneClasse() { super(); } (la signication de lexpression super() est explique ` la section 7.4) a 6.5.2 Membres constants (final)

La dclaration dun membre dune classe peut commencer par le qualieur final. Nous verrons ` la e a section 7.6.3 ce que cela veut dire pour une mthode ; pour une variable, cela signie quune fois initialise, e e elle ne pourra plus changer de valeur ; en particulier, toute apparition de cette variable ` gauche dune a aectation sera refuse par le compilateur. Une telle variable est donc plutt une constante. e o Par exemple, voici comment dclarer une classe dont les instances sont des points immuables : e 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 acceptes par le compilateur, e car il les reconna comme des initialisations ; toute autre aectation de ces variables sera refuse. t e Le programmeur a donc deux mani`res dassurer que des variables dinstance ne seront jamais modies e e une fois les instances cres : qualier ces variables final ou bien les qualier private et ne pas dnir de e e mthode qui permettrait de les modier. La premi`re mani`re est prfrable, car e e e ee la qualication private nempche pas quune variable soit modie depuis une mthode de la mme e e e e classe, la qualication final informe le compilateur du caract`re constant de la variable en question, celui-ci e peut donc eectuer les optimisations que ce caract`re constant permet. e Constantes de classe. Les variables de classe peuvent elles aussi tre qualies final ; elles sont e e alors tr`s proches des pseudo-constantes quon dnit en C par la directive #define. La coutume est de e e nommer ces variables par des identicateurs tout en majuscules : 36
c H. Garreta, 2000-2010

LES OBJETS

6.5

Initialisation des 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("Coordonnes invalides pour un Point"); e this.x = x; this.y = y; } ... } 6.5.3 Blocs dinitialisation statiques

Les constructeurs des classes sont appels lors de la cration des objets, ce qui est tout ` fait adapt ` e e a ea 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, encadre par une paire daccolades, prcde e e e e du mot static. Ces blocs (et les autres aectations servant ` initialiser des variables de classe) sont excuts, a e e dans lordre o` ils sont crits, lors du chargement de la classe, cest-`-dire avant toute cration dune instance u e a e et avant tout acc`s ` une variable ou ` une mthode de classe. Exemple : e a a e 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++, lopration de cration des objets (malloc, new, etc.) est e e couple ` une opration symtrique de libration de la mmoire (free, delete, etc.) que le programmeur e a e e e e doit explicitement appeler lorsquun objet cesse dtre utile. Dans ces langages, loubli de la restitution e de la mmoire alloue est une cause derreurs sournoises dans les programmes. Or, lorsque les objets sont e e complexes, la libration compl`te et correcte de la mmoire quils occupent, eectue par des mthodes e e e e e appeles destructeurs, est un probl`me souvent dicile. e e Voici une bonne nouvelle : en Java il ny a pas dopration de libration de la mmoire ; en particulier, e e e on na pas besoin de munir les classes de destructeurs qui seraient le pendant des constructeurs 38 . Quand un objet cesse dtre utile on loublie, tout simplement. Exemple : e Point p = new Point(a, b); ... p = new Point(u, v); ici, le point P(a,b) a t oubli ee e ... p = null; maintenant, le point P(u,v) a t oubli galement ee ee ... Si un programme peut tourner longtemps sans jamais soccuper de la destruction des objets devenus caducs cest que la machine Java int`gre un mcanisme, appel garbage collector, qui rcup`re la mmoire e e e e e e
38. Attention, ne prenez pas pour un destructeur la mthode finalize, une notion dicile ` cerner et ` utiliser que nous e a a nexpliquerons pas dans ce cours.

c H. Garreta, 2000-2010

37

6.6

Classes internes et anonymes

LES OBJETS

inutilise. A cet eet Java maintient dans chaque objet le dcompte des rfrences que lobjet supporte, et e e ee rcup`re lespace occup par tout objet dont le nombre de rfrences devient nul 39 . e e e ee Ce mcanisme, qui implique le parcours de structures ventuellement tr`s complexes, se met en marche e e e automatiquement lorsque la mmoire libre vient ` manquer, et aussi en tache de fond lorsque la machine est e a oisive ou eectue des oprations lentes, comme des acc`s rseau ou des lectures au clavier. e e e

6.6

Classes internes et anonymes

Cette section pointue peut tre ignore en premi`re lecture. e e e 6.6.1 Classes internes

Si la seule utilit dune classe I est de satisfaire les besoins dune autre classe E alors on peut dnir I e e a ` lintrieur de E. On dit que I est une classe interne, et que E est la classe englobante de I. Cela a deux e consquences majeures : e une consquence statique, facile ` comprendre : ` lintrieur de la classe englobante le nom de la classe e a a e interne peut tre employ tel quel, mais a lextrieur de la classe englobante le nom de la classe interne e e ` e nest utilisable que sil est prx par le nom de la classe englobante ou par celui dune instance de e e cette classe ; il en rsulte une diminution, toujours bienvenue, du risque de collisions de noms, e une consquence dynamique, bien plus subtile : si elle nest pas dclare static, la classe interne est e e e lie ` une instance particuli`re de la classe englobante, ` laquelle elle fait implicitement rfrence. e a e a ee Exemple. La classe Automobile est destine ` reprsenter les divers mod`les au catalogue dun construce a e e teur. Un mme mod`le est fabriqu avec dirents moteurs. Il a t dcid que la classe Moteur na dintrt e e e e ee e e ee qu` lintrieur de la classe Automobile 40 : a e 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", 2400); e System.out.println(auto.moteur); } } Regardez bien la mthode toString ci-dessus : les deux variables cylindree et modele qui y apparaissent e ont des statuts dirents, puisque cylindree appartient ` une instance de Moteur, tandis que modele est e a lie ` une instance dAutomobile. e a
39. On peut expliquer le fonctionnement du garbage collector de la mani`re suivante : un objet est vivant sil est (a) la valeur e dune variable de classe dune classe charge, (b) la valeur dune variable dinstance dun objet vivant ou (c) la valeur dune e variable locale dune mthode active. e Le travail du garbage collector se compose, au moins logiquement, de trois phases : (1) parcourir tous les objets vivants et marquer les cellules mmoire quils occupent, (2) noter comme tant rutilisables toutes les cellules non marques pendant e e e e la phase prcdente et (3) de temps en temps, rarranger la mmoire pour regrouper les cellules rutilisables, de mani`re ` e e e e e e a lutter contre lmiettement de lespace disponible. e 40. Il y l` un choix de conception tr`s discutable (mme sil para normal que le moteur soit ` lintrieur de lautomobile !) a e e t a e car cela interdit que deux mod`les dautomobile distincts aient le mme moteur. e e

38

c H. Garreta, 2000-2010

LES OBJETS

6.6

Classes internes et anonymes

Puisque la classe Moteur toute enti`re est un membre non statique de la classe Automobile, la premi`re e e ne peut tre accde qu` travers une instance particuli`re de la seconde. Ainsi, par exemple, le constructeur e e e a e de Moteur est une mthode dinstance de Automobile. e Il en rsulte que dans les mthodes dinstance de Moteur deux variables this sont dnies : celle qui e e e identie un objet Moteur particulier et celle qui identie lobjet Automobile dans lequel cet objet Moteur a t cr. On peut dire que ce deuxi`me this se comporte comme une variable de classe de la classe Moteur, e e ee e a ` la condition de comprendre quil y en aura un dirent pour chaque instance de la classe Automobile. e A lintrieur dune instance de Moteur, ces deux variables peuvent tre atteintes par les appellations e e respectives this et Automobile.this. 6.6.2 Classes anonymes

Les classes anonymes sont des classes internes cres ` la vole au moment de leur instanciation, comme ee a e les tableaux anonymes (cf. section 3.4.4). Cela est particuli`rement utile lorsquil faut dnir une sous-classe e e dune classe donne, ou une classe implmentant une interface donne, alors quon na besoin que dune seule e e e instance de la nouvelle classe. Par exemple, linstruction suivante cre dans la foule une classe anonyme, sous-classe de la classe Point, e e dans laquelle la mthode toString est rednie, et une instance (qui restera unique) de la classe anonyme e e ainsi dnie : e Point o = new Point(0, 0) { public String toString() { return "[0rigine]"; } };

// lobjet o est un Point ordinaire, sauf // pour ce qui concerne la mthode toString e

Si, apr`s la compilation de la classe Point ci-dessus, on examine la liste des chiers produits par le e compilateur on trouvera les deux chiers Point.class et Point$1.class. Le second traduit la cration e dune classe anonyme ` loccasion de linstanciation prcdente. a e e Autre exemple, tir de la gestion des vnements dans AWT : pour attacher un auditeur dvnements e e e e e action ` un composant produisant de tels vnements, comme un bouton ou un menu, il faut excuter a e e e linstruction : composant.addActionListener(auditeur ); o` auditeur est un objet dune classe implmentant linterface ActionListener. Or cette interface se compose u e dune unique mthode, actionPerformed. On sen sort donc ` moindres frais avec une classe anonyme : e a composant.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { traitement de lvnement e e } });

c H. Garreta, 2000-2010

39

HERITAGE

7
7.1

Hritage e
Introduction : raner, abstraire

Pour approcher la notion dhritage, examinons deux sortes de besoins, lg`rement dirents, quil sae e e e tisfait. Le premier, que nous appellerons ranement, correspond ` la situation suivante : on dispose dune a classe A acheve, oprationnelle, dnissant des objets satisfaisants, et il nous faut dnir une classe B qui en e e e e est une extension : les objets B ont tout ce quont les objets A plus quelques variables et mthodes ajoutes e e et/ou quelques mthodes amliores (on dira rednies). e e e e Imaginez, par exemple, quon dispose dune classe RectangleGeometrique pour reprsenter des rectangles e en tant quentits mathmatiques, avec des variables dinstance (x, y, largeur, hauteur, etc.) et des mthodes e e e (translation, rotation, etc.) et quil nous faille une classe RectangleGraphique dont les instances sont des entits rectangulaires capables de sacher sur un cran. Elles comportent donc tout ce qui fait un e e RectangleGeometrique et, en plus, quelques variables (couleurFond, couleurBord, paisseurBord, etc.) e et mthodes supplmentaires (affichage, transformationCouleur, etc.). e e

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 expliqus dans les chapitres prcdents, nous devrions dnir la e e e e classe RectangleGraphique en y dupliquant (cf. gure 7, ` gauche) les informations qui se trouvent dans la a dnition de RectangleGeometrique. e Le mcanisme de lhritage permet dviter cette duplication, en nous laissant dclarer d`s le commene e e e e cement que la classe RectangleGraphique tend la classe RectangleGeometrique et en poss`de donc tous e e les attributs (cf. gure 7, ` droite). De cette mani`re, il ne nous reste ` dnir que les membres spciques a e a e e que la deuxi`me classe (que nous appellerons la sous-classe) ajoute ` la premi`re (la super-classe). e a e Une deuxi`me sorte de besoins auxquels lhritage sattaque sont ceux qui se manifestent lorsquon a e e a e ` dvelopper plusieurs classes possdant un ensemble de membres communs. Sans lhritage, ces derniers e e devraient tre dclars en autant dexemplaires quil y a de classes qui en ont besoin. Lhritage va nous e e e e permettre de les dclarer une seule fois, dans une classe distincte, invente pour loccasion, dont la seule e e justication sera de contenir ces membres communs ` plusieurs autres. a

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

40

c H. Garreta, 2000-2010

HERITAGE

7.2

Sous-classes et super-classes

Imaginons par exemple une application manipulant plusieurs sortes dobjets susceptibles de sacher sur un cran : des rectangles, des ellipses, des polygones, etc. Il faudra dnir plusieurs classes distinctes, e e comportant des lments spciques on ne dessine pas un rectangle comme on dessine une ellipse mais ee e aussi des lments communs, aussi bien des variables (la couleur du fond, la couleur et lpaisseur du bord, ee e etc.) que des mthodes (positionnement, translation, etc.) e Voyez la gure 8 (droite) : lhritage permet de dnir des classes RectangleGraphique, EllipseGraphie e que, etc., dans lesquelles seuls les lments spciques sont spcis, car elles sont dclares comme des ee e e e e e extensions dune classe ObjetGraphique o` sont dnis les lments communs ` toutes ces autres classes. u e ee a Il y a une dirence tr`s prcise entre cette situation et la prcdente : la classe ObjetGraphique ne doit e e e e e pas avoir des instances. Un objet qui serait un ObjetGraphique sans tre quelque chose de plus concret e (un RectangleGraphique, une EllipseGraphique, etc.) naurait pas de sens. Pour exprimer cette proprit ee on dit que ObjetGraphique est une classe abstraite. Elle est un moyen commode et puissant pour dsigner e collectivement les diverses sortes dobjets destins ` lachage, mais pour la cration dune tel objet il faut e a e toujours utiliser une classe concr`te. e Remarque pointue. Voyant les deux exemples prcdents on peut se demander sil est possible de e e dnir la classe RectangleGraphique comme sous-classe en mme temps de RectangleGeometrique et e e dObjetGraphique. La rponse est non, en Java lhritage est simple : pour des raisons aussi bien decacit e e e que de simplicit conceptuelle, une classe ne peut tre un ranement que dune seule autre. e e Cependant nous introduirons, le moment venu, la notion dinterface (une interface est une classe tr`s e abstraite) et on verra quune classe peut tre sous-classe de plusieurs interfaces, la relation dhritage se e e nommant alors implmentation. Ainsi, si notre classe ObjetGraphique peut tre crite sous-forme dinterface, e e e on pourra nalement exprimer en Java que la classe RectangleGraphique est une extension de la classe RectangleGeometrique et une implmentation de linterface ObjetGraphique ; cela nous apportera une e grande partie des avantages quon aurait pu esprer de lhritage multiple, sil avait t possible. e e ee

7.2
7.2.1

Sous-classes et super-classes
Dnition de sous-classe e

Lhritage est le mcanisme qui consiste ` dnir une classe nouvelle, dite classe drive ou sous-classe, e e a e e e par extension dune classe existante, appele sa classe de base ou super-classe. La sous-classe poss`de doce e e tous les membres de la super-classe, auxquels elle ajoute ses membres spciques. e Lhritage est indiqu par lexpression extends SuperClasse crite au dbut de la dnition dune e e e e e classe. Par exemple, dnissons la classe Pixel comme sous-classe de la classe Point qui nous a dj` servi e ea dexemple. Un pixel est un point, tendu par lajout dune variable dinstance qui reprsente une couleur e e (Color est une classe dnie dans le paquet java.awt) : e class Point { int x, y; ... } class Pixel extends Point { Color couleur; ... } Avec la dnition prcdente, un Pixel se compose de trois variables dinstance : x et y, hrites de la e e e e e classe Point, et couleur, une variable dinstance spcique. Ces trois variables sont membres de plein droit e de la classe Pixel et, si pix est un objet de cette classe, on peut crire sous rserve quon ait le droit e e dacc`s pix.x et pix.y exactement comme on peut crire pix.couleur. e e Note. En toute rigueur, si la dnition dune classe D commence par e 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 tant, nous dirons sous-classe [resp. super-classe] pour sous-classe directe [resp. super-classe directe], e sauf dans les (rares) situations o` cela crerait une confusion. u e
c H. Garreta, 2000-2010

41

7.3

Rednition des mthodes e e

HERITAGE

7.2.2

Larbre de toutes les classes

En Java lhritage est simple : chaque classe poss`de au plus une super-classe directe. En fait, il y a une e e classe particuli`re, nomme Object, qui na pas de super-classe, et toutes les autres classes ont exactement e e une super-classe directe. Par consquent, lensemble de toutes les classes, muni de la relation est sous-classe e directe de , constitue une unique arborescence dont la racine est la classe Object. Ainsi, les variables et mthodes qui composent un objet ne sont pas toutes dnies dans la classe de e e 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 mthodes : un message e ayant t envoy ` un objet, la rponse pertinente doit tre recherche dans la classe de celui-ci ou, en cas ee ea e e e dchec, dans la super-classe de celle-l`, puis dans la super-classe de la super-classe, et ainsi de suite, en e a remontant le long de la branche de larbre dhritage, jusqu` trouver une classe dans laquelle on a prvu de e a e rpondre au message en question. e Le procd de recherche des mthodes est un probl`me important, dans tous les langages qui pratiquent e e e e lhritage 41 . Il peut tre trait ` la compilation, on parle alors de liaison statique, ou bien ` lexcution, on dit e e ea a e quon pratique alors la liaison dynamique. La liaison statique est plus ecace, puisque les incertitudes sont leves avant que lexcution ne commence, mais la liaison dynamique est beaucoup plus souple et puissante. e e Comme la suite le montrera, Java met en uvre un savant mlange de liaison statique et dynamique. e

7.3
7.3.1

Rednition des mthodes e e


Surcharge et masquage

Que se passe-t-il lorsque des membres spciques de la sous-classe ont le mme nom que des membres e e hrits ? Deux cas : e e 1. Si les entits qui ont le mme nom ont des rles ou des signatures direntes, alors cest un cas de e e o e surcharge et il est trait comme sil sagissait de deux membres de la mme classe. Par exemple, rien e e ne soppose ` ce que cohabitent sans conit dans la sous-classe une variable dinstance propre f et une a mthode hrite f, ou deux mthodes de signatures direntes dont une est hrite et lautre non. e e e e e e e 2. Sil sagit au contraire de deux entits ayant le mme rle et, dans le cas des mthodes, la mme e e o e e signature alors il y a masquage : dans la sous-classe, le membre spcique masque le membre hrit. e e e Il y a plusieurs mani`res daccder ` un membre masqu. Imaginons par exemple quon a introduit une e e a e mesure de qualit dans les points, et aussi une notion de qualit dans les pixels, ces deux notions nayant e e pas de rapport entre elles 42 : class Point { int x, y; int qualite; ... } class Pixel extends Point { Color couleur; int qualite; ... } Dans ces conditions, ` lintrieur dune mthode de la classe Pixel, les expressions qualite et this.qualite a e e dsignent le membre qualite spcique de la classe Pixel. Mais les expressions e e super.qualite et ((Point) this).qualite dsignent toutes deux le membre qualite hrit de la classe Point. e e e
41. Notez que ce probl`me est partiellement simpli et optimis en Java par le fait quon ny pratique que lhritage simple. e e e e Dans les langages ` hritage multiple, o` une classe peut avoir plusieurs super-classes directes, le graphe dhritage nest plus a e u e un arbre. Dans ces langages, la recherche des mthodes devient une opration litigieuse et complexe. e e 42. Si la qualit dun pixel (en tant que pixel) na pas de rapport avec la qualit dun point, cest une maladresse que de e e donner le mme nom ` ces variables dinstance ; il vaudrait certainement mieux que le membre Pixel.qualite ait un autre e a nom.

42

c H. Garreta, 2000-2010

HERITAGE

7.3

Rednition des mthodes e e

7.3.2

Rednition des mthodes e e

Si la dnition dans une sous-classe dune variable ayant le mme nom quune variable de la super-classe e e appara souvent comme une maladresse de conception, la dnition dune mthode ayant le mme nom et t e e e la mme signature quune mthode de la super-classe est au contraire une technique justie et tr`s utile. e e e e En eet, la sous-classe tant une extension, cest-`-dire une amlioration , de la super-classe, les objets e a e de la sous-classe doivent rpondre ` tous les messages auxquels rpondent les objets de la super-classe, mais e a e il est normal quil y rpondent de mani`re amliore : beaucoup de mthodes de la sous-classe font les e e e e e mmes choses que des mthodes correspondantes de la super-classe, mais elles le font mieux , cest-`-dire e e a 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 mthode toString 43 : e 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 rponse ` un appel comme unPixel.toString() peut tre vue e a e comme une amlioration de la rponse ` unPoint.toString() : si unPoint reprsente un point et unPixel e e a e 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 mthode Pixel.toString prcdente a deux dfauts : e e e e le mme code (le traitement de x et y) est crit dans Point.toString et dans Pixel.toString, ce e e qui constitue une redondance, toujours regrettable, plus grave, la classe Pixel sappuie ainsi sur des dtails internes de la classe Point. e Une mani`re bien prfrable dcrire les mthodes rednies de la sous-classe consiste ` laisser les mthodes e ee e e e a e de la super-classe se charger du traitement de la partie hrite : e e class Pixel extends Point { Color couleur; ... public String toString() { return "[" + super.toString() + ";" + couleur + "]"; } } Contraintes de la rednition des mthodes e e 1. On ne peut pas proter de la rednition dune mthode pour en restreindre laccessibilit : la rede e e e nition dune mthode doit tre au moins aussi publique que la dnition originale. En particulier, la e e e rednition dune mthode publique 44 doit tre qualie public. e e e e 2. La signature de la rednition dune mthode doit tre identique ` celle de la mthode hrite. La e e e a e e e signature dune mthode se compose de trois lments : e ee
43. La mthode toString appartient a tous les objets, puisquelle est dnie dans la classe Object. e ` e 44. On notera que cela concerne en particulier la rednition obligatoire, dans ce cas des mthodes des interfaces (cf. e e section 7.7.3) qui, par dnition, sont toutes implicitement publiques. e

c H. Garreta, 2000-2010

43

7.4

Hritage et constructeurs e

HERITAGE

le nom de la mthode, e la suite des types de ses arguments, le fait que la mthode soit ordinaire (dinstance) ou static. e Par exemple, si la dnition dune mthode commence par la ligne e e 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`s attention ` la contrainte voque au point prcdent, car les dirences de signature e a e e e e e ne sont pas en tant que telles signales par le compilateur. e En eet, imaginons que la mthode ci-dessus soit dnie dans une classe A, et que dans une sous-classe e e B de A on crive une mthode (que lon pense tre une rednition de la prcdente) commenant par e e e e e e c public double moyenne(double[] tableau, short nombre, String titre) { Les signatures de ces deux mthodes ntant pas identiques, la deuxi`me nest pas une rednition de la e e e e premi`re. Hlas pour le programmeur, cela ne constitue pas une erreur que le compilateur pourrait diagnose e tiquer, mais un simple cas de surcharge : la classe B poss`de deux mthodes nommes moyenne : la premi`re e e e e prend un int pour second argument tandis que la deuxi`me prend un short 45 . e 4. On notera bien que le type du rsultat renvoy par une mthode ne fait pas partie de la signature de e e e celle-ci. Dans ces conditions : une dnition de mthode est une rednition si et seulement si la signature est identique ` celle dune e e e a mthode hrite, indpendamment du type du rsultat, e e e e e si une dnition est une rednition, alors le type du rsultat de la rednition doit tre identique au e e e e e type du rsultat de la mthode hrite. e e e e Note Java 5. La pratique montre que la contrainte exprime ci-dessus est trop forte. Dans la mesure e o` on peut voir la rednition dune mthode comme un ranement de celle-ci, on souhaiterait parfois que u e e la mthode rane puisse rendre un rsultat qui est lui-mme un ranement du rsultat renvoy par la e e e e e e mthode originale. e Cest pourquoi en Java 5 la r`gle prcdente est devenue : e e e une dnition de mthode est une rednition si et seulement si la signature est identique ` celle dune e e e a mthode hrite, indpendamment du type du rsultat, e e e e e si une dnition est une rednition, alors le type du rsultat de la rednition doit tre soit identique, e e e e e soit une sous-classe du type du rsultat de la mthode hrite. e e e e

7.4

Hritage et constructeurs e

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 ncessairement par lappel dun constructeur e de la super-classe. Si le programmeur na rien prvu, ce sera le constructeur sans arguments de la super-classe, qui doit donc e exister. Mais on peut expliciter lappel dun constructeur de la super-classe par linstruction : super(arguments); Si elle est prsente, cette instruction doit tre la premi`re du constructeur de la sous-classe. Par exemple, si e e e la classe Point na quun constructeur, ` deux arguments : a 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 dcrire un constructeur pour la classe Pixel, comme ceci : e e
45. La dirence entre un int et un short tant minime (la valeur 10 est-elle de type int ou de type short ?), on montre l` e e a une situation qui, si elle tait voulue, serait certainement une maladresse source de confusion et derreurs ultrieures. e e

44

c H. Garreta, 2000-2010

HERITAGE

7.5

Membres protgs e e

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

7.5

Membres protgs e e

Comme il a t dit (cf. 6.4) un membre dune classe C dont la dclaration commence par le qualieur ee e protected est accessible depuis les mthodes de la classe C, celles des autres classes du paquet auquel C e appartient, ainsi que celles des sous-classes, directes ou indirectes, de C. En ralit la r`gle qui gouverne lacc`s aux membres protgs est plus complexe que cela. Considrons e e e e e e e un acc`s tel que : e unObjet.unMembre ou unObjet.unMembre(arguments) dans lequel unMembre (une variable dans le premier cas, une mthode dans le second) est un membre protg e e e dune certaine classe C. Pour tre lgitime, cette expression e e doit tre crite dans une mthode de C ou dune classe du mme paquet que C en cela les membres e e e e protgs sont traits comme les membres ayant laccessibilit par dfaut , ou bien e e e e e doit tre crite dans une mthode dune classe S qui est sous-classe de C, mais alors unObjet doit tre e e e e 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 46 . Pour comprendre lintrt dune mthode protge il faut imaginer un traitement qui doit tre dni dans ee e e e e e une classe A alors quil ne peut tre appel que depuis les instances dune sous-classe de A. e e Cest le cas, par exemple, du constructeur dune classe qui ne doit pas avoir dinstances 47 , mais uniquement des sous-classes qui, elles, auront des instances. Voici une version tr`s na de quelques classes pour e ve grer le stock dune entreprise de location de choses. Il existe une classe Article, la plus gnrale, dont e e e 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 galement un certain nombre de sous-classes de la prcdente, reprsentant des catgories prcises e e e e e e dobjets ` louer, comme les vhicules : a e

46. Certains thoriciens de la programmation oriente objets estiment mme que le concept de membre protg est injusti e e e e e e et contreproductif. 47. Plus loin, de telles classes seront appeles classes abstraites, voir 7.7.2. e

c H. Garreta, 2000-2010

45

7.6

Le polymorphisme

HERITAGE

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 lous sont manipuls dans le programme ` travers des variables dclares de type Article : e e a e e Article unArticle; Il ne faut pas que la valeur dune telle variable puisse tre une instance directe de la classe Article, car e un objet qui serait un Article sans tre quelque chose de plus prcis (un vhicule, un outil, un meuble, etc.) e e e na pas de sens. Le constructeur de la classe Article doit donc tre rendu moins accessible que public an e de garantir que cette classe ne sera jamais directement instancie : e unArticle = new Article(111222333, 120.0); // *** ERREUR ***

Or, en mme temps, ce constructeur de Article doit tre rendu plus accessible que private an quil e e puisse tre appel (` travers lexpression super(reference, prixParJour); ) depuis le constructeur e e a 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 t dans le mme paquetage, la qualication protected ee e naurait rien ajout ` la qualication par dfaut. Comme on le voit, lintrt de la qualication protected est ea e ee assez limit, surtout en Java. e Note 2. Lexemple ci-dessus tire son intrt de la prsence dune classe qui ne doit pas avoir dinstances. ee e De telles classes sont dites abstraites ; nous rencontrerons plus loin (cf. 7.7.2) de bien meilleures mani`res e de les prendre en considration. e

7.6

Le polymorphisme

Le polymorphisme est un concept particuli`rement riche prsent dans beaucoup de langages orients e e e objets. Laspect que nous en tudions ici tourne autour des notions de gnralisation et particularisation. e e e La gnralisation est la possibilit de tenir un objet pour plus gnral quil nest, le temps dun traitement. e e e e e Par exemple, pour appliquer une transformation gomtrique ` un Pixel il sut de savoir quil est une sorte e e a de Point. Par particularisation nous entendons la possibilit de retrouver le type particulier dun objet alors que ce e dernier est accd ` travers une variable dun type plus gnral. Par exemple, retrouver le fait que la valeur e ea e e dune variable de type Point est en ralit un Pixel. e e 7.6.1 Gnralisation et particularisation e e

Generalisation (conversion sous-classe super-classe). Si B est une super-classe dune classe D, la conversion dun objet D vers le type B est une opration naturelle et justie. En eet, ` cause de lhritage, e e a e toutes les variables et mthodes de la classe B sont dans la classe D ; autrement dit, tout ce quun B sait faire, e un D sait le faire aussi bien (et peut-tre mieux, ` cause de la rednition possible des mthodes hrites). e a e e e e Par consquent, en toute circonstance, l` o` un B est attendu on peut mettre un D. e a u De telles conversions sont implicites et toujours accepte par le compilateur. Nous les rencontrerons dans e de tr`s nombreuses situations. Par exemple, avec nos classes Point et Pixel : e class Point { int x, y; ... int distance(Point p) { return Math.abs(x - p.x) + Math.abs(y - p.y); } 46
c H. Garreta, 2000-2010

HERITAGE

7.6

Le polymorphisme

... } class Pixel extends Point { Color couleur; ... } si les variables unPoint et unPixel ont les types que leurs noms sugg`rent, lexpression e r = unPoint.distance(unPixel); illustre la gnralisation : lors de lappel de la mthode distance, la valeur de la variable unPixel est aecte e e e e a ` largument p (de type Point) ; ainsi, durant le calcul de sa distance au point donn, le pixel est vu comme e un Point, ce qui est susant car, dans le calcul dune distance, seuls interviennent les membres que le pixel hrite de la classe Point. e Notez que cest le mme genre de considrations qui donnent un sens ` lexpression : e e a r = unPixel.distance(unPoint); Particularisation (conversion super-classe sous-classe). Une consquence du fait que les objets e sont dsigns par rfrence (cf. section 3.3) est quils ne sont pas altr par leur gnralisation : lorsquun e e ee ee e e objet dune classe D est accd ` travers une variable dun type plus gnral B on ne peut pas atteindre les e ea e e 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 ` lopration rciproque de la gnralisation : donner ` un objet O un type T plus a e e e e a particulier que celui ` travers lequel il est connu ` un instant donn. Bien entendu, cela nest lgitime que si a a e e T est soit le type eectif de O, soit une gnralisation de ce type. e e Une telle conversion doit toujours tre explicite par le programmeur, elle nest jamais implicite : e e Point unPoint; Pixel unPixel = new Pixel(a, b, c); ... unPoint = unPixel; // OK. Gnralisation e e ... unPixel = unPoint; ... unPixel = (Pixel) unPoint; // ERREUR // OK. Particularisation

Les contraintes que doit vrier une expression de la forme (T ) E, o` T est une classe et E une expression e u dun type classe, ne sont pas les mmes ` la compilation et ` lexcution du programme : e a a e ` la compilation, il faut que T soit sous-classe ou super-classe, directe ou indirecte, du type eectif a de E (cest-`-dire que les conversions ne sont acceptes ` la compilation quentre deux classes qui se a e a trouvent sur la mme branche de larbre dhritage), e e ` lexcution, il faut que la conversion reprsente une gnralisation du type eectif de E, sinon, une a e e e e exception ClassCastException sera lance. e Ces contraintes sont faciles ` comprendre : il sut de se rappeler que la gnralisation et la particularia e e sation 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 gnralisation et la particularisation apparaissent tr`s naturellee e e ment est lemploi doutils gnraux de la biblioth`que Java, comme les collections. Par exemple, une mani`re e e e e de reprsenter une ligne polygonale consiste ` se donner une liste (ici, une liste cha ee, LinkedList) de e a n points (ici, tirs au hasard) : e ... 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); } ...
c H. Garreta, 2000-2010

47

7.6

Le polymorphisme

HERITAGE

Considrons lexpression lignePolygonale.add(unPoint) . Les LinkedList tant dnies ` un niveau e e e a de gnralit maximal, lobjet unPoint ne peut tre trait, dans les mthodes de la liste, que comme un simple e e e e e e Object, la classe la plus gnrale. e e Du coup, lorsque ces points sont extraits de la liste, il faut explicitement leur redonner le type qui est le leur. Par exemple, cherchons ` acher les sommets dune telle ligne polygonale : a ... Iterator iter = lignePolygonale.iterator(); while (iter.hasNext()) { unPoint = (Point) iter.next(); application ` unPoint dun traitement ncessitant un Point a e } ... La conversion (Point) iter.next() est ncessaire, car le rsultat rendu par next est un Object. Elle e e est certainement correcte, car dans la collection que iter parcourt nous navons mis que des objets Point. Lorsquune liste nest pas homog`ne comme ci-dessus, il faut saider de loprateur instanceof pour e e 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 prcdent traitera les points, mais aussi les pixels et les objets de toutes les souse e classes, directes et indirectes, de la classe Point. Telle est la smantique de loprateur instanceof (cest le e e comportement gnralement souhait). e e e 7.6.2 Les mthodes rednies sont virtuelles e e

Soit v une variable dun type classe B et m une mthode de B ; un appel tel que v.m(arguments) est e lgitime. Imaginons quau moment dun tel appel, la valeur eective de v est instance de D, une sous-classe e de B, dans laquelle m a t rednie. La question est : quelle version de m sera appele ? Celle de B, la classe ee e e de la variable v, ou bien celle de D, la classe de la valeur eective de v ? En Java, la rponse est : la seconde. Quel que soit le type sous lequel un objet est vu ` la compilation, e a lorsqu` lexcution la machine appelle sur cet objet une mthode qui a t rednie, la dnition eectivement a e e ee e e employe est la plus particuli`re, cest ` dire la plus proche du type eectif de lobjet. e e a Exemple, trivial mais rvlateur, avec la mthode toStringtoString : e e e Object unObjet = new Point(1, 2); ... String str = unObjet.toString(); La cha aecte ` str par lexpression ci-dessus est "(1,2)", cest-`-dire lexpression textuelle dun objet ne e a a Point (et non "Point@12cf71", qui serait le rsultat de la version de toString dnie dans Object). Noter e e que cest bien parce que toString est dnie dans la classe Object que lexpression unObjet.toString() e est accepte ` la compilation, mais ` lexcution cest la version dnie dans la classe Point, la classe de la e a a e e valeur eective de unObjet, qui est employe. e Dans certains langages, comme C++, on appelle cela des mthodes virtuelles ; en Java, toutes les me e thodes sont donc virtuelles. Cela a dimportantes consquences mthodologiques, et rend le polymorphisme e e extrmement intressant et puissant. e e Autre exemple (plus instructif). Considrons une application manipulant des classes dobjets devant e tre dessins dans des fentres graphiques : des segments, des rectangles, des cercles, etc. Dans toutes ces e e e classes il y a une mthode seDessiner prenant en charge la prsentation graphique des objets en question. e e 48
c H. Garreta, 2000-2010

HERITAGE

7.6

Le polymorphisme

La question est : comment manipuler ensemble ces objets dirents, tout en ayant le droit dutiliser ce e quils ont en commun ? Par exemple, comment avoir une collection de tels objets graphiques dirents, et e pouvoir appeler la mthode seDessiner de chacun ? e On laura compris, la solution consiste ` dnir une super-classe de toutes ces classes, dans laquelle la a e mthode seDessiner est introduite : e class ObjetGraphique { ... void seDessiner(Graphics g) { } ... } class Segment extends ObjetGraphique { int x0, y0, x1, y1; // extrmits e e 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 gnralisation lors de leur introduction dans le tableau figure. e e Puisque seDessiner est dnie dans la classe ObjetGraphique, on peut appeler cette mthode ` travers e e a les lments de figure. Lintrt de tout cela rside dans le fait que cest la mthode propre ` chaque objet ee ee e e a graphique particulier qui sera appele, non celle de la classe ObjetGraphique : e for (int i = 0; i < figure.length; i++) figure[i].seDessiner(g); // ceci dpend de la valeur effective de figure[i] e Les mthodes rednies sont ncessairement virtuelles e e e La virtualit des mthodes peut donc se rsumer ainsi : la mthode eectivement appele par une e e e e e expression comme unObjet.uneMethode() dpend de la valeur eective de unObjet au moment de cet appel, e non de la dclaration de unObjet ou de proprits statiques dcoulant du texte du programme. e ee e Bien que la plupart du temps cette proprit soit extrmement utile, on voudrait quelquefois pouvoir ee e choisir la mthode a appeler parmi les diverses rednitions faites dans les super-classes. Il faut comprendre e e que cela ne se peut pas : le mcanisme des mthodes virtuelles en Java nest pas dbrayable. e e e
c H. Garreta, 2000-2010

49

7.6

Le polymorphisme

HERITAGE

Seule exception : si uneMethode est rednie dans une classe, lexpression super.uneMethode() permet e dappeler, depuis une mthode de la mme classe, la version de uneMethode qui est en vigueur dans la supere e classe. Mais il ny a aucun autre moyen pour contourner une ou plusieurs rednitions dune mthode. e e On notera que les variables ne sont pas traites comme les mthodes (mais la rednition des variables e e e na pas dintrt, ce nest quun masquage gnralement maladroit). Lexemple suivant illustre la situation : ee e e class A { String v = "variable A"; String m() { return "mthode A"; } e } class B extends A { String v = "variable B"; String m() { return "mthode B"; } e } class C extends B { String v = "variable C"; String m() { return "mthode C"; } e 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 mthode C e mthode B e mthode C e

pour une variable, cela marche

pour une mthode non e

7.6.3

Mthodes et classes nales e

Les mthodes virtuelles sont extrmement utiles, mais elles ont un cot : de linformation cache doit e e u e tre ajoute aux instances de la classe ObjetGraphique pour permettre ` la machine Java de rechercher la e e a mthode qui doit tre eectivement appele ` loccasion dune expression comme e e e a unObjetGraphique.seDessiner(g); cette recherche prenant dailleurs du temps ` lexcution. a e Cest la raison pour laquelle le programmeur peut optimiser son programme en dclarant quune mthode e e ne sera pas rednie dans les ventuelles sous-classes, ce qui permet au compilateur de lier statiquement les e e appels de cette mthode, au lieu de les lier dynamiquement comme le veut la r`gle gnrale. e e e e Cela se fait par lemploi du qualieur final. Par exemple, sil y a lieu de penser que le dessin dun cercle sera le mme dans la classe Cercle et dans les sous-classes de celle-ci, on peut dclarer cette mthode comme e e e ceci : class Cercle extends ObjetGraphique { int x, y; // centre int r; // rayon 50
c H. Garreta, 2000-2010

HERITAGE

7.7

Abstraction

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

// cette mthode ne sera e // pas redfinie dans les e // 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 prcdent sur toutes ses mthodes en dclarant final la classe tout enti`re. Par exemple, si e e e e e la classe Triangle nest pas destine ` avoir des sous-classes, on peut lcrire : e a e 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
Mthodes abstraites e

Revenons sur lexemple de la section prcdente : e e class ObjetGraphique { ... void seDessiner(Graphics g) { } ... } Nous observons ceci : la mthode seDessiner doit tre dnie dans la classe ObjetGraphique, car le rle e e e o de cette classe est de rassembler les lments communs aux divers objets graphiques considrs, or la capacit ee ee e de se reprsenter graphiquement est bien un de ces lments, sans doute le principal. En mme temps il nous e ee e est impossible, au niveau de la classe ObjetGraphique, dcrire quoi que ce soit dans la mthode seDessiner, e e car nous nen savons pas assez sur ce quil sagit de dessiner. On exprime cette situation en disant que seDessiner est une mthode abstraite. Sa dclaration dans la e e classe ObjetGraphique est une promesse : on annonce que tout objet graphique devra avoir une mthode e seDessiner, quil nest pas possible de fournir pour le moment. En Java on peut dclarer quune mthode est abstraite ` laide du qualieur abstract. Le corps de la e e a mthode doit alors tre remplac par un point virgule (et, comme on le verra ` la section suivante, la classe e e e a contenant une telle mthode doit elle aussi tre dclare abstraite) : e e e e abstract class ObjetGraphique { ... abstract void seDessiner(Graphics g); ... } Les mthodes abstraites dune classe restent abstraites dans ses sous-classes, sauf si elles y ont une e rednition qui leur donne un corps. e La magie des fonctions virtuelles, lexemple canonique. Ce nest pas parce quune mthode est e abstraite quon ne peut pas lappeler, y compris dans des classes o` elle nest pas encore dnie. Par exemple, u e une mani`re (na e ve) deacer un objet graphique consiste ` le dessiner avec une plume qui a pour couleur la a couleur du fond : abstract class ObjetGraphique { ... abstract void seDessiner(Graphics g); ...
c H. Garreta, 2000-2010

51

7.7

Abstraction

HERITAGE

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 dnit une version e eective de seDessiner dispose aussitt dune version oprationnelle de sEffacer. o e 7.7.2 Classes abstraites

Une classe abstraite est une classe qui ne doit pas avoir dinstances ; elle nest destine qu` avoir des e a sous-classes qui, elles, auront des instances. Cela peut provenir dune impossibilit technique ; par exemple, une classe qui poss`de des mthodes abstraites (en propre e e e ou hrites) ne peut pas avoir des instances, car ce seraient des objets dont une partie du comportement e e requis naurait pas t crit, eee dune impossibilit conceptuelle, cest-`-dire un choix du concepteur. Par exemple, les classes XxxAdape a ter du paquet java.awt.event sont des classes enti`rement faites de mthodes vides, dont dventuelles e e e instances nauraient aucun intrt. ee 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`de des mthodes abse e traites, propres ou hrites. e e 7.7.3 Interfaces

Parlant na vement, on peut dire que les mthodes non abstraites dune classe sont des services que e celle-ci rend aux concepteurs de ses ventuelles sous-classes, tandis que les mthodes abstraites sont des e e corves que la classe transmet aux concepteurs des sous-classes, qui devront en donner des dnitions. e e Une interface est une classe enti`rement faite de membres publics qui sont e des mthodes abstraites, e variables statiques nales (cest-`-dire des constantes de classe). a Une interface se dclare avec le mot-cl interface au lieu de class. Il ny a alors pas besoin dcrire les e e e qualieurs public et abstract devant les mthodes, ni public, static et final devant les variables. e Par exemple, si elle est enti`rement faite de mthodes abstraites, notre classe ObjetGraphique peut tre e e e dclar comme une interface : e e interface ObjetGraphique { void seDessiner(Graphics g); ... } Autre exemple, extrait de la biblioth`que Java (plus prcisment du paquet java.util) : e e e interface Collection { boolean isEmpty(); int size(); boolean contains(Object o); boolean add(Object o); Iterator iterator(); ... } Une interface est une spcication : elle xe la liste des mthodes quon est certain de trouver dans toute e e classe qui dclare tre conforme ` cette spcication. e e a e Cela sappelle une implmentation de linterface, et sindique avec le qualieur implements : e 52
c H. Garreta, 2000-2010

HERITAGE

7.7

Abstraction

class Tas implements Collection { public boolean isEmpty() { implmentation de la mthode isEmpty e e } public int size() { implmentation de la mthode size e e } ... } Notez que les mthodes des interfaces sont toujours publiques (implicitement) ; par consquent, leurs e e dnitions dans des sous-classes doivent tre explicitement qualies public, sinon une erreur sera signale. e e e e Deux interfaces peuvent hriter lune de lautre. Par exemple, toujours dans le paquet java.util on e trouve linterface SortedSet (ensemble tri) qui est une sous-interface de Set, elle-mme une sous-interface e e de Collection, etc. Dautre part, la relation implements entre une classe et une interface est aussi une sorte dhritage. Cet e hritage est multiple : une classe peut implmenter plusieurs interfaces distincts. Par exemple, on pourrait e e dnir une classe Figure qui serait une sorte de Collection (dobjets graphiques) et en mme temps une e e 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) ` la gure a } public boolean isEmpty() { la gure est-elle vide ? } ... } Lintrt de cette sorte dhritage multiple appara clairement : une instance de notre classe Figure ee e t pourra tre mise ` tout endroit o` une Collection est attendue, et aussi ` tout endroit o` un ObjetGraphique e a u a u 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 mthode soit argument dune autre ? e La solution consiste ` dclarer la mthode comme membre dune interface dnie ` cet eet, et ` mettre a e e e a a linterface comme type de largument en question. Voici par exemple comment dnir, dans une classe e CalculNumerique, une mthode zero qui recherche par dichotomie une solution approche ` -pr`s de e e a e lquation f (x) = 0, x [ a, b ] : e 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; }
c H. Garreta, 2000-2010

53

7.7

Abstraction

HERITAGE

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 dnie pour cette occasion. Elle se rduit ` une mthode val, qui reprsente la e e a e e fonction en question : interface Fonction { double val(double x); } Notez ` quel point Fonction et zero illustrent la notion dinterface et son utilit : tre un objet a e e Fonction ce nest rien dautre que possder une mthode nomme val qui prend un double et rend un e e e double . Il ny a pas besoin den savoir plus pour crire la mthode zero ! e e e a A titre dexemple proposons-nous dutiliser cette mthode pour calculer la valeur de 2 approche ` 108 e pr`s. Il sagit de rsoudre lquation x2 2 = 0 sur, par exemple, lintervalle [ 0, 2 ]. La fonction ` considrer e e e a e est donc f (x) = x2 2. Premi`re mthode, lourde, dnir une classe expr`s : e e e e 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 allger notre programme en utilisant ` e 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 mme faire lconomie de f (mais le programme obtenu est-il plus lisible ?) : e e 54
c H. Garreta, 2000-2010

HERITAGE

7.7

Abstraction

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); } }

c H. Garreta, 2000-2010

55

EXCEPTIONS

Exceptions

On dit quune exception se produit lorsque les conditions dexcution sont telles que la poursuite du e programme devient impossible ou incorrecte. Exemple : lindice dun tableau se trouve en dehors des bornes, la mmoire manque lors de la cration dun objet, etc. e e Les exceptions sont gnralement dtectes par les fonctions de bas niveau, voire par la machine Java e e e e elle-mme, mais la plupart du temps ce nest que dans les fonctions de haut niveau quon peut programmer e la raction adquate ` de telles situations non prvues. e e a e Le mcanisme des exceptions de Java est un moyen de communication permettant aux lments des e ee couches basses des programmes de notier aux couches hautes la survenue dune condition anormale. Par exemple, nous avons dj` vu une classe Point dont les instances taient soumises ` validation. Une ea e a bonne mani`re de traiter linvalidit des arguments de la construction dun point consiste ` lancer une e e a 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("Coordonnes illgales"); e e x = a; y = b; } ... } Les exceptions ont diverses sortes de causes : des causes synchrones 48 , cest-`-dire provoques par lexcution dune instruction, comme la division a e e par zro, limpossibilit dallouer de la mmoire, limpossibilit de charger une classe, etc., e e e e cas particulier du prcdent, lexcution de linstruction throw, e e e des causes asynchrones ; en Java il ny en a que deux : lexcution, depuis un autre thread, de la e mthode Thread.stop et la survenue dune erreur interne de la machine Java. e Une fois lance, une exception remonte , cest-`-dire : e a lexcution du bloc de code dans lequel lexception a t lance est abandonn, e ee e e si ce bloc nest ni un bloc try ni le corps dune mthode, alors il est lui-mme vu comme une instruction e e ayant lanc lexception, e si ce bloc est le corps dune mthode, alors lappel de cette derni`re, dans la mthode appelante, est e e e vu comme une instruction ayant lanc lexception, e si ce bloc est un bloc try comportant une clause catch compatible avec lexception, alors cette derni`re e est attrape : le code associ ` cette clause catch est excut, et lexception ne va pas plus loin. e ea e e

8.1

Interception des exceptions

Syntaxe : try { bloc0 } catch(type exception1 arg1 ) { bloc1 } catch(type exception2 arg2 ) { bloc2 } ... finally { block }
48. Ces causes synchrones montrent quil nest pas correct de se limiter ` dire quune exception est une situation imprvisible. a e Une division par zro ou lutilisation dune rfrence nulle ne sont quapparemment imprvisibles, si on avait mieux analys e ee e e le programme et ses donnes on aurait pu les prvoir avec certitude. Mais, comme on le verra, il est tr`s commode de ranger e e e parmi les exceptions ces vnements, malgr tout diciles ` prvoir et gnralement aux consquences graves. e e e a e e e e

56

c H. Garreta, 2000-2010

EXCEPTIONS

8.2

Lancement des exceptions

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

8.2

Lancement des exceptions


throw exception;

Une exception se lance par linstruction

o` exception est une expression dont la valeur doit tre un objet dune des classes de la hirarchie explique u e e e a ` la section suivante. 8.2.1 Hirarchie des exceptions e

Toutes les classes dexceptions appartiennent ` un sous-arbre de larbre des classes dont la racine est la a 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 ` rcuprer. a e e Exceptions mritant dtre dtectes et traites. e e e e e Exceptions pouvant survenir durant le fonctionnement normal de la machine Java : - indice de tableau hors des bornes - acc`s ` un membre dune rfrence null e a ee - erreur arithmtique (division par zro, etc.) e e Exceptions pouvant survenir pendant les oprations e dentre/sortie e

Vos propres classes exceptions viennent ici Autres classes 8.2.2 Dclaration des exceptions lances par une mthode e e e

Une mthode contenant une instruction pouvant lancer une exception dun certain type E doit ncessaie e rement soit attraper lexception, au moyen dun bloc try...catch... adquat, e soit dclarer quelle est susceptible de lancer, ou plutt de laisser chapper, des exceptions du type E. e o e Cette dclaration se fait par un nonc de la forme e e e throws listeDExceptions plac ` la n de len-tte de la mthode. Par exemple, le constructeur de la classe Point tant crit ainsi ea e e e e Point(int a, int b) throws Exception { if (a < 0 || a >= XMAX || b < 0 || b >= YMAX) throw new Exception("Coordonnes illgales"); e e x = a;
c H. Garreta, 2000-2010

57

8.2

Lancement des exceptions

EXCEPTIONS

y = b; } (notez que lnonc throws Exception est obligatoire) pour lessayer, nous devrons crire une mthode main e e e e soit de la forme : public static void main(String[] args) { ... try { Point p = new Point(u, v); ... } catch (Exception e) { System.out.println("Probl`me: " + e.getMessage()); e } ... } 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 dnissant pas de e classe spcique pour les exceptions qui intressent notre programme. En r`gle gnrale on dnit de telles e e e e e e classes, car cela permet une rcupration des erreurs plus slective : e e e class ExceptionCoordonnesIllegales extends Exception { ExceptionCoordonnesIllegales() { super("Coordonnes illgales"); e e } } 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`me avec les coordonnes du point"); e e } ... } } Exceptions controlees et non controlees. Les exceptions contrles sont celles quon est oblig oe e de dclarer dans len-tte de toute mthode susceptible de les lancer ; les autres exceptions sont dites non e e e contrles. oe Toutes les exceptions sont contrles, sauf : oe les instances de Error, car elles expriment des vnements irrattrapable, e e les instances de RuntimeException, car sil fallait dclarer ces exceptions, cela concernerait toutes les e mthodes. e 58
c H. Garreta, 2000-2010

EXCEPTIONS

8.3

Assert

8.3

Assert

Le service rendu par linstruction assert 49 est double : assert est un mcanisme simple et concis permettant de vrier, ` lexcution, qu` certains endroits e e a e a dun programme des conditions qui doivent tre remplies le sont eectivement, e assert comporte un dispositif global et immdiat dactivation ou dsactivation qui permet, au moment e e de lexcution, de choisir entre plusieurs modes, allant dun mode atelier muni de nombreuses vrie e cations (qui consomment du temps) a un mode utilisateur nal , plus rapide puisque les occurrences ` de assert y sont neutralises. e Linstruction assert se prsente sous deux formes : e assert expression 1 ; et assert expression 1 : expression 2 ; expression 1 est une expression boolenne, expression 2 une expression dun type quelconque. Dans les deux e cas, lexcution de linstruction assert commence par valuer expression 1 . Si cette expression est vraie, e e lexcution continue sans que rien ne se passe. e En revanche, si expression 1 se rv`le fausse alors une erreur 50 de type java.lang.AssertionError est e e lance. Si cest la deuxi`me forme de assert qui a t utilise, la valeur dexpression 2 gure dans le message e e ee e associ ` lerreur. ea Exemple : void uneMethode(int x) { ... assert MIN < x && x < MAX; ... } Lors dune excution dans laquelle uneMethode est appele avec un argument infrieur ` MIN ou suprieur ` e e e a e a MAX on obtiendra larrt du programme sauf si lerreur est attrape avec un message du style : e e java.lang.AssertionError at Tests.uneMethode(Tests.java:187) at Tests.main(Tests.java:12) Exception in thread "main" Si linstruction assert avait t crite sous la forme : eee ... assert MIN < x && x < MAX : "MIN < x && x < MAX, x = " + x; ... alors le message aurait t ee 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 dcouvrir des erreurs de conception et on ne saurait e trop insister sur lintrt de son utilisation. Mais elle nest pas la bonne mani`re de sauver des situations que ee e le programmeur ne peut pas empcher, comme des erreurs dans les donnes : saborder le programme nest e e en gnral pas la bonne raction ` une faute de frappe commise par lutilisateur ! e e e a De mme, assert nest pas la bonne mani`re denvoyer des messages ` lutilisateur nal : en principe e e a non-informaticien, celui-ci nest pas cens comprendre un diagnostic abscons mentionnant des classes dont il e ignore lexistence et des numros de ligne dont il na que faire. Linformation que assert produit ne sadresse e qu` lauteur du programme. a En rsum, assert est tr`s pratique mais il faut le remplacer par une autre construction (comme une e e e instruction if qui produit un dialogue avec lutilisateur sans tuer le programme) lorsque
49. Notez que, contrairement ` ce qui se pase en C, le mcanisme assert nest pas ralis en Java par une biblioth`que spare, a e e e e e e mais par une vraie instruction, cest-`-dire une extension de la syntaxe du langage. a 50. Rappelons que les erreurs (classe java.lang.Error, sous-classe de java.lang.Throwable) sont une sorte dexceptions non contrles. Elles sont destines principalement mais non exclusivement ` reprsenter des probl`mes srieux que les oe e a e e e applications ne doivent pas chercher ` rattraper. a

c H. Garreta, 2000-2010

59

8.3

Assert

EXCEPTIONS

il sagit de dtecter des erreurs autres que de conception ou de programmation, e il sagit de produire des messages adresss ` lutilisateur nal, e a il sagit de vrications qui doivent tre faites mme lorsque le mcanisme assert nest pas actif (voir e e e e ci-dessous). Activation et dsactivation de assert e Par dfaut, assert est dsactiv : quand une application Java est excute, cela se passe comme si ces e e e e e instructions avaient t enleves du code. ee e Pour rendre le mcanisme actif, il faut lancer la machine Java avec loption -enableassertions ou -ea, e qui peut prendre un argument, de la mani`re suivante : e -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 et tous ses sous-paquetages, e dans le paquetage sans nom, dans la classe indique, e dans toutes les classes du syst`me. e

Exemple. Excution dune application dont la mthode principale est dans la classe MaClasse en activant e e assert dans toutes les classes du paquetage courant : java -ea ... MaClasse

60

c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9
9.1
9.1.1

Quelques classes utiles


Nombres et outils mathmatiques e
Classes-enveloppes des types primitifs

Java comporte une unique arborescence de classes, de racine Object, dans laquelle se trouvent les classes de toutes les donnes manipules par les programmes... sauf les valeurs de types primitifs qui, pour dvidentes e e e raisons decacit, gardent leur statut de donnes lmentaires, utilisables par les oprations basiques cbles e e ee e a e dans les ordinateurs. An que ces donnes simples puissent tre traites comme des objets lorsque cela est ncessaire, Java e e e e fournit huit classes-enveloppes, une pour chaque type primitif : Byte, Short, Integer, Long, Float, Double, Boolean et Character. Le rle principal de chaque instance dune de ces classes est dencapsuler une valeur o du type primitif correspondant. Ces classes ont ` peu pr`s les mmes mthodes ; parmi les principales : a e e e un constructeur prenant pour argument la valeur du type primitif quil sagit denvelopper, la rciproque : une mthode xxx Value (xxx vaut byte, short, etc.) pour obtenir la valeur de type e e primitif enveloppe, e une mthode nomme toString pour obtenir cette valeur sous forme de cha de caract`res, e e ne e ventuellement, une mthode statique, appele parseXxx, permettant dobtenir une valeur dun type e e e primitif ` partir de sa reprsentation textuelle (cela sappelle parse car former une valeur ` partir dun a e a texte cest faire une analyse lexicale), ventuellement, une mthode statique valueOf pour construire un tel objet ` partir de sa reprsentation e e a e sous forme de texte. Par exemple, IntegerValueOf(uneChaine) donne le mme rsultat que e e new Integer(Integer.parseInt(uneChaine)) ; Pour chacune des huit classes, ces mthodes sont 51 : e 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

51. Les deux premi`res mthodes listes ici pour chacune de ces huit classes (le constructeur et la mthode xxx Value()) e e e e assurent deux oprations quon appelle famili`rement lemballage et le dballage dune valeur primitive. e e e On notera qu` partir de Java 5 ces oprations deviennent implicites (cf. section 12.2) : le compilateur se charge de les a e insrer l` o` elles sont ncessaires. e a u e

c H. Garreta, 2000-2010

61

9.1

Nombres et outils mathmatiques e

QUELQUES CLASSES UTILES

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 galement lexistence dans la classe String des mthodes suivantes : e e 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 mathmatiques e

La classe Math reprsente la biblioth`que mathmatique. Elle nest pas destine ` avoir des instances : e e e e a toutes ses mthodes sont statiques. On y trouve : e 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 infrieur ou gal ` v. e e a double ceil(double v) Le plus petit entier suprieur ou gal ` v. e e a 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 mme que celle de (int) floor(v + 0,5). e double random() Un nombre pseudo-alatoire dans [0, 1[. (Sagissant de nombres pseudo-alatoires, la classe java.e e util.Random permet de faire des choses plus savantes.) double exp(double x), double log(double x) 62
c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.1

Nombres et outils mathmatiques e

Exponentielle et logarithme neprien. e double pow(double a, double b) Elevation de a ` la puissance b. a La documentation ne donne pas dindication sur lalgorithme employ ni sur son ecacit, mais e e il est raisonnable de penser que si b est entier (cest-`-dire si b = Math.ceil(b), alors ab est a calcul en faisant des multiplications, aussi peu nombreuses que possible. Dans le cas gnral, ab e e e est calcul par la formule eb log a . 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 trigonomtriques habituelles. e 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 mme chose que tan a ). e 9.1.3 Nombres en prcision innie e

Le paquet java.math (` ne pas confondre avec la classe Math du paquet java.lang) ore des classes a permettant de manipuler des nombres avec autant de chires que ncessaire. e Nombres entiers. Les instances de la classe BigInteger reprsentent des nombres entiers. Parmi les e 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 en argument : e 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); } } }
c H. Garreta, 2000-2010

63

9.2

Collections et algorithmes

QUELQUES CLASSES UTILES

exemple dutilisation : >java Factorielle 500 122013682599111006870123878542304692625357434280319284219241358838584537 315388199760549644750220328186301361647714820358416337872207817720048078 etc. 00000000000000000000000000000000000000000000000000000000000000000000000 > Nombres decimaux. Les objets BigDecimal sont des nombres dcimaux en grande prcision. Plus pre e e cisment, un BigDecimal nombre est reprsent par un couple form dun BigInteger mantisse et dun int e e e e (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 chelle e BigDecimal setScale(int scale) : dnition de la partie chelle e e BigDecimal movePointLeft(int n), BigDecimal movePointRight(int n) : dplacement de la virgule e mantisse 10echelle

9.2

Collections et algorithmes

Note Java 5. Les classes et interfaces de la biblioth`que des collections et algorithmes ont t considrae ee e blement modies par lintroduction de la gnricit en Java 5. Notez bien que les collections sont expliques e e e e e ici comme en Java 1.4 ; pour les nouveauts apparues en Java 5 consultez la section 12.5. e Les programmes que nous ralisons couramment manipulent trois sortes de donnes : les valeurs de types e e primitifs, les objets et les collections dobjets. Dans les sections prcdentes nous avons vu ce que Java propose e e pour les types primitifs et les objets. Pour reprsenter les pluralits dobjets nous ne connaissons pour linstant que les tableaux. Ceux-ci ont e e un avantage considrable, la possibilit daccder directement (i.e. en temps constant ) ` un lment ` e e e a ee a partir de son indice. Mais ils ont aussi un important inconvnient, le manque de souplesse dans la gestion e de leur espace, puisquil faut conna le nombre maximum de leurs lments au moment de leur cration tre ee e (do` un risque du dbordement). u e Cette section montre qu` ct des tableaux, la biblioth`que Java propose une grande varit de colleca oe e ee tions, qui sont des structures de donnes beaucoup plus souples et riches. e 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 52 .
52. Il nest pas ais dexpliquer les collections et, encore moins, les algorithmes qui leur sont associs, car on ne peut pas se e e limiter aux spcication de ces classes. Par exemple, pour faire comprendre les dirences quil y a entre une ArrayList et un e e Vector il faut se pencher sur les implmentations de ces classes, ce qui va contre le principe dencapsulation. e Tout au long de cette section on gardera ` lesprit que les indications sur limplmentation restent des recommandations a e et que, mme si cela semble bizarre, une ralisation particuli`re de la biblioth`que pourrait ne pas les suivre, ` condition de e e e e a respecter les spcications. e

64

c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.2

Collections et algorithmes

Pour les dtails prcis, on se rfrera avec prot aux pages concernant le paquetage java.util dans la e e ee 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 dhritage entre les classes est indique par la marge laisse ` e e e a gauche : Interfaces Collection. Cette interface reprsente la notion de collection dobjets la plus gnrale. A ce e e e niveau dabstraction, les oprations garanties sont : obtenir le nombre dlments de la e ee collection, savoir si un objet donn sy trouve, ajouter (sans contrainte sur la position) et e enlever un objet, etc. On notera que les lments des collections sont dclars avec le type Object. Cela a deux ee e e consquences principales 53 : e 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 gnrale qui soit. Par consquent, quand un objet est extrait dune collection il faut e e e 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 tre directee ment ajoutes aux collections, il faut auparavant les emballer dans des instances des e classes enveloppes correspondantes (Boolean, Integer, Float, etc.). Point important, toutes les collections peuvent tre parcourues. Cela se fait ` laide dun e a itrateur (interfaces Iterator ou Enumeration, voyez la section 9.2.2), un objet qui assure e que tous les lments de la collection sont atteints, chacun ` son tour, et qui encapsule les ee a dtails pratiques du parcours, dpendant de limplmentation de la collection. e e e List. Il sagit de la notion de squence 54 , cest-`-dire une collection o` chaque lment a e a u ee un rang. On trouve ici des oprations lies ` lacc`s direct aux lments (insertion dun e e a e ee lment ` un rang donn, obtention de llment qui se trouve ` un rang donn, etc.) ee a e ee a e mme si, ` ce niveau de gnralit, on ne peut pas donner dindication sur le cot de e a e e e u tels acc`s. e Set. Comme cest souvent le cas, la notion densemble est celle de collection sans rptition : e e un Set ne peut pas contenir deux lments e1 et e2 vriant e1 .equals(e2 ). ee e Pour lessentiel, linterface Set najoute pas des mthodes ` linterface Collection, mais e a uniquement la garantie de lunicit des lments lors de la construction dun ensemble e ee ou de lajout dun lment. ee Aucune indication nest donne a priori sur lordre dans lequel les lments dun Set e ee sont visits lors dun parcours de lensemble. e SortedSet. Un ensemble tri garantit que, lors dun parcours, les lments sont succese ee sivement atteints en ordre croissant soit selon un ordre propre aux lments (qui doivent alors implmenter linterface ee e Comparable), soit selon une relation dordre (un objet Comparator) donne explicitement lors e de la cration de lensemble. e Map. Cette interface formalise la notion de liste associative ou dictionnaire, cest-`-dire une cola lection de couples (cl, valeur ) appels associations. e e Les oprations fondamentales des dictionnaires sont lajout et la suppression dune associae tion et la recherche dune association ` partir de la valeur dune cl. a e
53. Ces deux r`gles sont importantes et il faut sassurer de bien les comprendre. Nous devons cependant signaler que dans e Java 5 elles sont considrablement adoucies par deux lments nouveaux : e ee les types paramtrs (cf. section 12.5.1) permettent de travailler avec des collections dont les lments sont plus prcis e e ee e que de simples Object, lemballage et dballage automatique (cf. section 12.2) simplient notablement lintroduction et lextraction des lments e ee des collections. 54. Pour exprimer que les lments dune squence ont un rang, la documentation ocielle parle de collections ordonnes. ee e e Attention, lexpression est trompeuse, cela na rien ` voir avec une quelconque relation dordre sur les lments (les collections a ee respectant une relation dordre sont appeles collections tries). e e

c H. Garreta, 2000-2010

65

9.2

Collections et algorithmes

QUELQUES CLASSES UTILES

Sont fournies galement des mthodes pour obtenir diverses vues du dictionnaire : lensemble e e des cls, la collection des valeurs, lensemble des associations. e Lunicit des cls est garantie : un objet Map ne peut pas contenir deux associations (c1 , v1 ) e e et (c2 , v2 ) telles que c1 .equals(c2 ). SortedMap. Un dictionnaire dans lequel les associations sont places dans lordre croissant e des cls, ce qui se manifeste lors des parcours des trois collections associes au dictione e naire : lensemble des cls, la collection des valeurs et lensemble des associations. e Classes AbstractCollection. Cette classe abstraite ore un dbut dimplmentation de linterface Cole e lection, destine ` allger leort a fournir pour disposer dune implmentation compl`te. e a e ` e e Pour avoir une collection immuable il sut de dnir une sous-classe de AbstractCollection, e dans laquelle seules les mthodes iterator() et size() sont ` crire. Pour avoir une cole ae lection modiable il faut en outre surcharger la mthode add(Object o). e AbstractList. Classe abstraite qui est un dbut dimplmentation de linterface List. e e Attention, on suppose ici quil sagit de raliser une collection base sur une structure e e de donnes, comme un tableau, dans laquelle lacc`s direct est optimis. Si la liste nest e e e pas base sur une structure de donnes ` acc`s direct il vaut mieux tendre la classe e e a e e AbstractSequentialList au lieu de celle-ci. Pour disposer dune liste immuable, les mthodes get(int index) et size() sont ` e a crire. Si on souhaite une liste modiable, il faut en outre surcharger la mthode set(int e e index, Object element). AbstractSequentialList. Cette classe abstraite est un dbut dimplmentation de e e linterface List, quil faut utiliser de prfrence ` AbstractList lorsque la ee a collection ` dnir est base sur une structure de donnes ` acc`s (uniquement) a e e e a e squentiel. e Pour disposer dune liste il faut tendre cette classe en dnissant les mthodes e e e listIterator() et size(). Litrateur renvoy par la mthode listIterator est e e e utilis par les mthodes qui implmentent lacc`s direct 55 get(int index), set(int e e e e index, Object element), etc. LinkedList. Une implmentation compl`te de linterface List. e e Une LinkedList est rpute tre implmente par une liste cha ee bidirectione e e e e n nelle. En tout cas, toutes les oprations qui ont un sens pour de telles listes existent e et ont, en principe, le cot quelles auraient dans ce cas. u Il en dcoule que les LinkedList sont particuli`rement bien adaptes ` la ralie e e a e sation de piles (LIFO), de les dattente (FIFO) et de queues ` deux extrmits. a e e ArrayList. La mme chose quun Vector, sauf que ce nest pas synchronis (` propos e e a de synchronisation, voyez la section 10.2). Vector. Un Vector est une liste implmente par un tableau qui prend soin de sa propre e e taille. Lorsquon a besoin dun tableau qui grandit au fur et ` mesure du droulement dun a e programme, les Vector sont une alternative intressante aux tableaux ordinaires : e lacc`s direct aux lments y est ralis avec autant decacit et, en plus, le proe ee e e e grammeur 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 ` la n du a tableau. Deux proprits, dont on peut ventuellement xer la valeur lors de la construction ee e du Vector, en commandent la croissance : capacity : la taille courante du tableau sous-jacent au Vector, capacityIncrement : le nombre dunits dont la capacit est augmente chaque e e e fois que cela est ncessaire. e
55. Par consquent, lacc`s au ieme lment a un cot proportionnel ` i. Cest la raison pour laquelle on doit prendre e e ee u a AbstractSequentialList pour super-classe uniquement lorsque la structure de donnes sous-jacente ne dispose pas dacc`s e e direct.

66

c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.2

Collections et algorithmes

De plus, un objet Vector est synchronis 56 . e Stack. Un objet Stack est une pile implmente par un Vector. Cela se manifeste e e par des oprations spciques : e e push(Object o) : empiler un objet au sommet de la pile, Object pop() : dpiler lobjet au sommet de la pile, e Object peek() : obtenir la valeur de lobjet au sommet de la pile sans le dpiler, e 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 dbut dimplmentation de linterface Set. Le e e procd est le mme que pour AbstractCollection (voir ci-dessus) sauf que le programe e e meur doit prendre soin, en dnissant les mthodes manquantes, dobir aux contraintes e e e supplmentaires des ensembles, surtout pour ce qui est de lunicit des lments. e e ee HashSet. Une implmentation (compl`te) de linterface Set ralise ` laide dune table e e e e a dadressage dispers, ou hashcode (cest-`-dire une instance de la classe HashMap). e a Cest tr`s ecace, car les oprations de base (add, remove, contains et size) se font e e en temps constant. Le seul inconvnient 57 est que lors des parcours de la structure e les lments apparaissent dans un ordre imprvisible. ee e LinkedHashSet. Une implmentation de linterface Set qui utilise une table de hase code et, de mani`re redondante, une liste doublement cha ee. e n Cela fonctionne comme un HashSet, et avec pratiquement la mme ecacit, mais e e de plus, lors des parcours de la structure ses lments sont retrouvs dans lordre ee e dans lequel ils ont t insrs (cest la premi`re insertion qui dtermine lordre). ee ee e e Un LinkedHashSet est une bonne solution lorsquon ne peut pas supporter lordre gnralement chaotique dans lequel sont parcourus les lments dun HashSet et e e ee que, en mme temps, on ne peut pas payer le cot additionnel dun TreeSet, voir e u ci-apr`s. e TreeSet. Une implmentation de linterface Set ralise ` laide dun arbre binaire de e e e a recherche (cest-`-dire une instance de la classe TreeMap). a Lors des parcours, les lments de lensemble apparaissent en ordre croissant ee soit relativement ` un ordre qui leur est propre, et dans ce cas ils doivent impla e menter linterface Comparable, soit relativement ` une relation dordre, un objet Comparator, fournie lors de la a cration de la structure. e Les oprations de base (add, remove et contains) sont garanties prendre un temps e O(log n) (n est le nombre dlments). ee AbstractMap. Cette classe abstraite ore un dbut dimplmentation de linterface Map, destine e e e a e ` allger leort ` fournir pour disposer dune implmentation compl`te. a e e Pour avoir un dictionnaire immuable il sut de dnir une sous classe de AbstractMap et e dy rednir la mthode entrySet. Pour un dictionnaire modiable il faut en outre rednir e e e la mthode put. e HashMap. Implmentation de linterface Map ` laide dune table dadressage dispers ou e a e hashcode. Cest tr`s ecace, car les oprations de base (get et put) se font en temps e e constant, du moins si on suppose que la fonction de dispersion rpartir uniformment e e les valeurs des cls. e La table de hashcode est ralise par un tableau qui, ` la mani`re dun Vector, prend e e a e soin de grandir lorsque la table atteint un certain facteur de remplissage. Le seul inconvnient est que lors des parcours de la structure les lments apparaissent e ee avec les cls dans un ordre imprvisible. e e
56. Cela veut dire que des dispositions sont prises pour interdire que deux threads acc`dent de mani`re concurrente ` un e e a mme Vector, ce qui donnerait des rsultats imprvisibles si lun des deux modiait le vecteur. A ce propos voyez la section 10.2. e e e 57. Ce nest quun inconvnient pratique. En thorie, la notion de ordre dans lequel les lments appartiennent ` un e e ee a ensemble na mme pas de sens. e

c H. Garreta, 2000-2010

67

9.2

Collections et algorithmes

QUELQUES CLASSES UTILES

LinkedHashMap. Implmentation de linterface Map ` laide dune table de hashcode et e a dune liste doublement cha ee redondante. n Grce ` cette liste, lors des parcours de la structure les associations (cl,valeur ) a a e apparaissent de mani`re ordonne, en principe dans lordre dans lequel elles ont t e e ee ajoutes ` la table (dit ordre dinsertion). e a Un argument du constructeur permet de spcier que lon souhaite, au lieu de lordre e dinsertion, un ordre dni par les acc`s faits aux lments une fois quils ont t e e ee ee ajouts : cela consiste ` ordonner les lments en allant du moins rcemment accd e a ee e e e vers le plus rcemment accd (cela permet dutiliser des objets LinkedHashMap e e e pour raliser des structures LRU ). e IdentityHashMap. Cette classe implmente linterface Map comme HashMap, sauf quelle e utilise la relation dquivalence dnie par loprateur == (galit des rfrences ) au e e e e e ee lieu de celle dnie par le prdicat equals (galit des valeurs ). e e e e Cest donc une classe tr`s technique, ` utiliser avec une extrme prudence. e a e WeakHashMap. Cette classe implmente linterface Map comme HashMap, sauf que les assoe ciations (cl,valeur ) sont considres comme tant faiblement lies ` la table. e ee e e a Cela veut dire que si la table est le seul objet qui rfrence une association donne, ee e alors cette derni`re pourra tre dtruite par le garbage collector (cf. section 6.5.4) la e e e prochaine fois que la mmoire viendra ` manquer. e a Lintrt pratique est facile ` voir : lorsquun objet devient sans utilit le programmeur ee a e na pas ` se proccuper de lenlever des tables WeakHashMap dans lesquelles il a pu tre a e e enregistr et qui, sans cela, le feraient passer pour utile et le maintiendraient en vie. e Cela tant, cest encore une classe tr`s technique, ` utiliser avec prudence. e e a TreeMap. Cette classe implmente linterface SortedMap en utilisant un arbre binaire rouge e et noir 58 . Cest tr`s ecace, puisque les oprations fondamentales (containsKey, get, e e 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 cls en ordre croissant : e soit relativement ` un ordre naturel, et dans ce cas les cls doivent implmenter a e e linterface Comparable, soit relativement ` une relation dordre (un objet Comparator) fournie lors de la a cration du dictionnaire. e Attention. Une relation dordre (mthode compareTo dans le cas de linterface Comparable, e mthode compare dans le cas de linterface Comparator) doit tre compatible avec lgae e e lit (cf. section 9.2.4) pour quun objet TreeMap qui lutilise soit correct. e 9.2.2 Itrateurs e

Un objet qui implmente linterface Iterator reprsente le parcours dune collection. Il permet donc, au e e moyen doprations indpendantes de la collection particuli`re dont il sagit, de se positionner sur le premier e e e lment de la collection et dobtenir successivement chaque lment de cette derni`re. ee ee e Ce que premier lment veut dire et lordre dans lequel les lments sont obtenus dpendent de la ee ee e nature de la collection parcourue, comme il a t indiqu dans la section prcdente. ee e e e Un objet Iterator encapsule une position courante qui reprsente ltat du parcours. Les mthodes e e e constitutives de linterface Iterator sont : boolean hasNext() : Prdicat vrai si et seulement si le parcours que litrateur reprsente nest e e e pas ni (cest-`-dire si la position courante est valide). a Object next() : Renvoie lobjet sur lequel litrateur est positionn et fait avancer la position e e courante. void remove() : Supprime de la collection le dernier lment prcdemment renvoy par litee e e e e rateur. Il faut avoir pralablement appel next, et un appel de remove au plus est permis e e pour un appel de next.
58. A propos des arbres rouge et noir, voyez Thomas Cormen, Charles Leiserson et Ronald Rivest, Introduction a lalgorith` mique, Dunod, 1994.

68

c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.2

Collections et algorithmes

Lopration remove est facultative . Plus prcisment, elle est lie 59 au caract`re modie e e e e able de la collection qui est en train dtre parcourue : e si la collection est modiable, cette opration doit tre oprationnelle, e e e si la collection est immuable, cette opration doit se limiter ` lancer une exception e a UnsupportedOperationException. Limplmentation dun itrateur dpend de la collection ` parcourir ; par consquent, on construit un e e e a e itrateur nouveau, positionn au dbut dune collection, en le demandant ` cette derni`re. Cela fonctionne e e e a e selon le schma suivant : e Collection uneCollection; ... Iterator unIterateur = uneCollection.iterator(); while ( unIterateur .hasNext() ) { Object unObjet = unIterateur .next(); exploitation de unObjet } Exemple. Le programme purement dmonstratif suivant ache la liste trie des nombres distincts 60 e e obtenus en tirant pseudo-alatoirement N nombres entiers dans lintervalle [ 0, 100 [ : e ... 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 quivalente ` Iterator. Sans e a aller jusqu` dire que Enumeration est dsapprouve (deprecated ), la documentation ocielle indique quil a e e faut lui prfrer Iterator... ce qui nest pas toujours possible car un certain nombre de services sont rservs ee e e aux numrations et nont pas de contrepartie pour les itrateurs (par exemple, la mthode list de la classe e e e e Collections, cf. section 9.2.4). Les homologues des mthodes hasNext et next, dans Enumeration, sont hasMoreElements et nextElement. e Le schma, dans le cas des numrations, est donc celui-ci : e e e Collection uneCollection; ... Enumeration uneEnumeration = uneCollection.elements(); while ( uneEnumeration.hasMoreElements() ) { Object unObjet = uneEnumeration.nextElement(); exploitation de unObjet } 9.2.3 Quelques mthodes des collections e

Voici quelques mthodes des collections parmi les plus importantes (il y en a beaucoup plus que cela) : e Collection. Toutes les collections rpondent aux messages suivants : e boolean isEmpty() est vrai si et seulement si la collection est vide, int size() renvoie le nombre dlments de la collection, ee boolean contains(Object unObjet) est vrai si et seulement si la collection contient un lment ee elt vriant elt.equals(unObjet), e
59. Cette question est cruciale pour les collections dont les oprations fondamentales sont dnies ` partir de litrateur e e a e correspondant, comme dans le cas de AbstractSequentialList (cf. section 9.2.1). 60. On a des nombres distincts parce quon les range dans un ensemble, et cette liste est trie parce quil sagit un TreeSet. e

c H. Garreta, 2000-2010

69

9.2

Collections et algorithmes

QUELQUES CLASSES UTILES

void add(Object unObjet) ajoute lobjet indiqu ` la collection ; la place ` laquelle lobjet est ea a ajout dpend du type particulier de la collection, e e void remove(Object unObjet) si la collection a des lments elt vriant elt.equals(unObjet) ee e alors lun dentre eux est enlev de la collection ; dans le cas o` il y en a plusieurs, savoir e u lequel est limin dpend du type de la collection. e e e List. Les listes ont ceci de plus que les simples collections : Object get(int i) renvoie llment qui se trouve ` la ieme place, ee a void set(int i, Object unObjet) remplace le ieme lment par lobjet indiqu, ee e void add(Object unObjet) ajoute lobjet indiqu ` la n de la liste, ea void add(int i, Object unObjet) ins`re lobjet indiqu ` la ieme place (les lments dont e e a ee lindice tait i ont, apr`s linsertion, un indice augment de 1). e e e Set. Les ensembles nont pas des mthodes additionnelles, mais un certain comportement est garanti : e boolean add(Object unObjet) si lensemble ne contient pas un lment elt vriant elt.equals(unObjet) alors cette mee e e thode ajoute cet objet et renvoie true ; sinon, lensemble reste inchang et cette mthode e e renvoie false. Map. Les dictionnaires sont des collections de paires (cl, valeur ) : e Object put(Object cle, Object valeur) ajoute au dictionnaire lassociation (cl, valeur ) indie que ; cette mthode renvoie la prcdente valeur associe ` la cl indiqu, ou null si une e e e e e a e e telle cl ne se trouvait pas dans la structure de donnes, e e Object get(Object cle) renvoie la valeur associe ` la cl indique, ou null si une telle cl e a e e e nexiste pas. Attention, obtenir null comme rsultat nimplique pas ncessairement que la cl cherche e e e e nest pas dans la structure : si le couple (cl, null) existe on obtient le mme rsultat (pour e e e savoir si une cl existe il vaut mieux utiliser containsKey), e boolean containsKey(Object cle) vrai si et seulement si un couple comportant la cl indique e e se trouve dans le dictionnaire, boolean containsValue(Object valeur) vrai si et seulement si un ou plusieurs couples comportant la valeur indique existent dans le dictionnaire. e 9.2.4 Algorithmes pour les collections

La classe Collections (notez le pluriel 61 ) est enti`rement faite de mthodes statiques qui op`rent sur des e e e collections, pour les transformer, y eectuer des recherches, en construire de nouvelles, etc. Nous prsentons e ici quelques mthodes de la classe Collections parmi les plus importantes. e A propos de relation dordre. Certaines des oprations dcrites ci-apr`s crent ou exploitent des cole e e e lections tries. Il faut savoir quil y a deux mani`res de spcier la relation dordre par rapport ` laquelle e e e a une structure est dite trie : e Linterface Comparable. Dire dune classe quelle implmente linterface Comparable cest dire que ses e instances forment un ensemble muni dune relation dordre, donne par lunique mthode de cette interface e e int compareTo(Object o) dnie par : a.compareTo(b) est ngatif, nul ou positif selon que la valeur de a est infrieure, gale ou e e e e suprieure ` celle de b. e a Linterface Comparator. Les implmentations de cette interface sont des relations 62 quon passe comme e arguments aux mthodes qui utilisent ou crent des collections ordonnes. Cette interface comporte essene e e tiellement la mthode : e int compare(Object o1, Object o2)
61. Il est rare quune classe soit dsigne par un substantif pluriel ; une classe ordinaire porte plutt le nom singulier qui e e o dcrit ses instances. On utilise des pluriels pour dsigner des classes enti`rement faites dutilitaires se rapportant a une classe e e e ` qui aurait le nom en question, au singulier. Composes de variables et mthodes statiques, ces classes ne sont pas destines a e e e ` avoir des instances, elles sont des biblioth`ques de fonctions. e 62. Ne pas confondre ces deux interfaces : un Comparable reprsente un objet sur lequel est dnie une relation dordre, un e e Comparator reprsente la relation dordre elle-mme. e e

70

c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.2

Collections et algorithmes

dnie, comme la prcdente, par : compare(a, b) est ngatif, nul ou positif selon que la valeur de a est e e e e infrieure, gale ou suprieure ` celle de b. e e e a Dans un cas comme dans lautre, ces comparaisons supportent quelques contraintes (ce qui est dit ici sur compare sapplique galement ` compareTo) : e a 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 gnralement en sorte que e e (compare(x,y) == 0) == x.equals(y) Lorsque cette derni`re contrainte nest pas satisfaite, la documentation doit comporter lavertissement e 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 lments, ce qui requiert que ee ces lments implmentent linterface Comparable et soient comparables deux ` deux. ee e a static void sort(List uneList, Comparator compar) trie uneListe selon lordre dtermin par compar. e e Dans lun et lautre cas le tri est garanti stable : deux lments quivalents (pour la relation dordre) ee e se retrouvent placs lun par rapport ` lautre dans la liste trie comme ils taient dans la liste avant e a e e le tri. static Comparator reverseOrder() renvoie un comparateur qui reprsente lordre inverse de lordre nae turel 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 donne par ordre dcroissant . e e 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 mthodes recherchent e le maximum ou le minimum dune collection donne, soit par rapport ` lordre naturel de la collection e a (dont les lments doivent alors implmenter linterface Comparable) soit par rapport ` la relation ee e a dordre reprsente par largument compar. e e Recherches dans une collection triee static int binarySearch(List uneListe, Object uneValeur) Recherche la valeur indique dans la liste e donne en utilisant lalgorithme de la recherche binaire (ou dichotomique). La liste doit tre trie see e e lon son ordre naturel, ce qui implique que ses lments implmentent linterface Comparable et sont ee e comparables deux ` deux. a static int binarySearch(List uneListe, Object uneValeur, Comparator compar) Recherche la valeur indique dans la liste donne en utilisant lalgorithme de la recherche binaire (ou dichotomique). e e La liste doit tre trie selon lordre dni par compar. e e e Dans lun et lautre cas, le cot dune recherche est de lordre de log n si la liste est base sur un vrai u e acc`s direct aux lments (i.e. le cot de la recherche est O(log n) si le cot dun acc`s est O(1)). e ee u u e static int indexOfSubList(List grandeListe, List petiteListe) Recherche le dbut de la premi`re e e occurrence de petiteListe en tant que sous-liste de grandeListe. Plus prcisment, renvoie la plus e e 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 dbut de la dere ni`re occurrence de petiteListe en tant que sous-liste de grandeListe. Plus prcisment, renvoie la e e e 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 mthodes ci-dessus la documentation indique que la technique employe est celle de la e e force brute . Peut-tre ne faut-il pas en attendre une grande ecacit... e e
c H. Garreta, 2000-2010

71

9.2

Collections et algorithmes

QUELQUES CLASSES UTILES

Utilitaires de base static List nCopies(int n, Object uneValeur) Renvoie une liste immuable forme de n copies de la e valeur uneValeur. Il sagit de copie supercielle : lobjet uneValeur nest pas clon pour en avoir n e exemplaires. static void copy(List destin, List source) Copie les lments de la liste source dans les lments ee ee correspondants de la liste destin, qui doit tre au moins aussi longue que source. Attention, cette e opration ne cre pas de structure : les deux listes doivent exister. e e 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 lments gaux ` ancienneValeur par nouvelleValeur. Renvoie ee e a true si au moins un remplacement a eu lieu, false sinon. static ArrayList list(Enumeration uneEnumeration) Construit un objet ArrayList contenant les lee ments successivement renvoys par lnumration indique, placs dans lordre dans lequel cette derni`re e e e e e e les a donns. e 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 lments de uneListe. ee static void rotate(List uneListe, int distance) Fait tourner les lments de uneListe : llee ee ment qui se trouvait ` lemplacement i se trouve, apr`s lappel de cette mthode, ` lemplacement a e e a (i + distance) modulo uneListe.size() static void shuffle(List uneListe) Rarrange pseudo-alatoirement les lments de uneListe. e e ee static Set singleton(Object unObjet) Renvoie un ensemble immuable constitu de lunique lment e ee reprsent par unObjet. e e static List singletonList(Object unObjet) Renvoie une liste immuable constitue de lunique lment e ee unObjet. static Map singletonMap(Object cl, Object valeur) Renvoie une liste associative immuable constie tue de lunique association (cle, valeur). e La classe Collections contient encore deux autres sries de mthodes, pour lesquelles nous renvoyons ` e e a la documentation ocielle : des mthodes synchronizedCollection(Collection c), synchronizedList(List l), synchronizede Map(Map m), etc., pour obtenir une version synchronise (i.e. pouvant faire face aux acc`s simultans e e e faits par plusieurs thread concurrents) dune collection donne, e des mthodes unmodifiableCollection(Collection c) unmodifiableList(List l), unmodifiablee Map(Map m), etc., pour obtenir une copie immuable dune collection donne. e 9.2.5 Algorithmes pour les tableaux

La classe Arrays (encore un pluriel) est enti`rement faite de mthodes statiques qui op`rent sur des e e e tableaux. Voici certaines de ces mthodes parmi les plus importantes : e static List asList(Object[] unTableau) Construit et renvoie une liste dont les lments sont ceux du ee 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 mthodes recherchent uneValeur dans le tableau unTableau, qui doit tre tri par rapport ` lordre e e e a naturel du type en question. Elles renvoient un entier i qui reprsente e si i 0, lemplacement dans le tableau de la valeur recherche, e si i < 0, la valeur i = (j + 1) o` j est lemplacement dans le tableau dans lequel il faudrait mettre u uneValeur si on voulait linsrer tout en gardant tri le tableau. e e

72

c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.3

Rexion et manipulation des types e

static int binarySearch(Object[] unTableau, Object uneValeur) static int binarySearch(Object[] unTableau, Object uneValeur, Comparator compar) Mme dnition que prcdemment. Le tableau doit tre tri, dans le premier cas par rapport ` lordre e e e e e e a naturel de ses lments (qui doivent alors implmenter linterface Comparable), dans le second cas par ee e rapport ` la relation dordre exprime par largument compar. a e static boolean equals(type[] unTableau, type[] unAutreTableau) Egalit de tableaux. e type est un des mots byte, short, int, long, float, double, boolean, char ou Object (autant dire nimporte quel type). Ce prdicat est vrai si et seulement si les deux tableaux pass comme arguments sont gaux (au sens e e e 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 mme valeur. e type est un des mots byte, short, int, long, float, double, boolean, char ou Object. La valeur indique est aecte ` tous les lments du tableau (premier cas) ou aux lments de rangs e e a ee ee 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 llment dindice debut jusqu` llment dindice fin (second cas). ee a ee 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 ` lordre naturel des lments du tableau ce qui, dans le cas o` type est a ee u Object, oblige ces lments ` tre dun type qui implmente linterface Comparable. ee ae e La mthode de tri employe est une variante labore du lalgorithme du tri rapide (quicksort) qui, e e e e nous dit-on, ore un cot de n log n mme dans un certain nombre de cas pourris o` le quicksort de u e u base serait quadratique. static void sort(Object[] a, int fromIndex, int toIndex, Comparator compar) Mme chose que e ci-dessus, mais relativement ` la relation dordre dnie par largument compar. a e

9.3

Rexion et manipulation des types e

La classe java.lang.Class et les classes du paquet java.lang.reflect (aux noms vocateurs, comme e Field, Method, Constructor, Array, etc.) orent la possibilit de pratiquer une certaine introspection : un e objet peut inspecter une classe, ventuellement la sienne propre, accder ` la liste de ses membres, appeler e e a une mthode dont le nom nest connu qu` lexcution, etc. e a e Une instance de la classe java.lang.Class reprsente un type (cest-`-dire un type primitif ou une e a classe). Supposons que nous ayons une variable dclare ainsi : e e Class uneClasse; Nous avons plusieurs mani`res de lui donner une valeur : e une classe-enveloppe dun type primitif (Integer, Double, etc.) poss`de une constante de classe TYPE e qui reprsente le type primitif en question ; de plus, lexpression type.class a le mme eet. Ainsi, les e e deux expressions suivantes aectent le type int ` la variable uneClasse : a uneClasse = Integer.TYPE; uneClasse = int.class; si uneClasse est lidenticateur dune classe, alors lexpression uneClasse.class a pour valeur la classe en question 63 . Lexemple suivant aecte le type java.math.BigInteger ` la variable uneClasse : a uneClasse = java.math.BigInteger.class;
63. Notez la dirence entre TYPE et class pour les classes-enveloppes des types primitifs : Integer.TYPE est le type int, e tandis que Integer.class est le type java.lang.Integer.

c H. Garreta, 2000-2010

73

9.3

Rexion et manipulation des types e

QUELQUES CLASSES UTILES

on peut aussi demander le chargement de la classe, ` partir de son nom compl`tement spci. Cest a e e e un procd plus onreux que les prcdents, o` la plupart du travail de chargement (dont la dtection e e e e e u e dventuelles erreurs dans les noms des classes) tait fait durant la compilation alors que, dans le cas pre e e sent, il sera fait pendant lexcution. Lexemple suivant aecte encore le type java.math.BigInteger e a ` la variable uneClasse : uneClasse = Class.forName("java.math.BigInteger"); enn, le moyen le plus naturel est de demander ` un objet quelle est sa classe. Lexemple suivant aecte a encore le type java.math.BigInteger ` la variable uneClasse : a Object unObjet = new BigInteger("92233720368547758079223372036854775807"); ... uneClasse = unObjet.getClass(); Pour survoler cette question assez pointue, voici un exemple qui illustre quelques unes des possibilits de e la classe Class et du paquet reflect. La mthode demoReflexion ci-dessous, purement dmonstrative, prend deux objets quelconques a et b et e e appelle successivement toutes les mthodes qui peuvent tre appeles sur a avec b pour argument, cest-`-dire e e e a les mthodes dinstance de la classe de a qui ont un unique argument de type la classe de b : e

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`me : " + exc); e } } public static void main(String[] args) { demoReflexion(new BigInteger("1001"), new BigInteger("1003")); } } Le programme prcdent ache la sortie e e 1001.compareTo(1003) = -1 1001.min(1003) = 1001 1001.add(1003) = 2004 ... 1001.gcd(1003) = 1 1001.mod(1003) = 1001 1001.modInverse(1003) = 501

74

c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.4

Entres-sorties e

9.4

Entres-sorties e

Note importante. Java 5 a introduit des outils simples et pratiques pour eectuer la lecture et lcriture e de donnes formates. Ils sont explique dans la section 12.3.4 (page 158). e e e 9.4.1 Les classes de ux

Java fournit un nombre impressionnant de classes prenant en charge les oprations dentre sortie. Voici e e une prsentation tr`s succincte des principales (la marge laisse ` gauche re`te la relation dhritage). e e e a e e Plusieurs exemples dutilisation de ces classes sont donns dans la section 9.4.2 : e Flux doctets en entree InputStream Cette classe abstraite est la super-classe de toutes les classes qui reprsentent des ux doctets en entre. e e Comporte une unique mthode, int read(), dont chaque e appel renvoie un octet extrait du ux. Un ux qui obtient les donnes lues, des octets, ` partir e a dun chier. Construction ` partir dun String (le nom du chier), a dun File ou dun FileDescriptor. Un ux qui obtient les donnes lues, des octets, ` partir e a dun tableau doctets indiqu lors de la construction. e Un ux qui obtient les donnes lues, des octets, ` partir e a dun PipedOutputStream auquel il est connect. Ce deuxi`me e e ux doit appartenir ` un thread distinct, sous peine de a blocage. Construction ` partir dun PipedOutputStream ou a a ` partir de de rien. Un ux qui obtient les donnes lues, des octets, ` partir e a dun autre InputStream, auquel il ajoute des fonctionnalits. e Ajoute aux fonctionnalits dun autre InputStream la mise e en tampon des octets lus. Construction ` partir dun InputStream. a Ajoute aux fonctionnalits dun autre InputStream la e possibilit de dlire un octet (un octet dlu est e e e retrouv lors dune lecture ultrieure). e e Construction ` partir dun InputStream. a Un objet de cette classe obtient de lInputStream sousjacent des donnes appartenant aux types primitifs de Java. e Voir DataOutputStream, plus loin. Construction ` partir dun InputStream. a Un ux capable de d-srialiser les objets pralablement e e e srialiss dans un ObjectOutputStream. e e Voir les sections srialisation et ObjectOutputStream. e Construction ` partir dun InputStream. a Un ux qui obtient les donnes lues, des octets, ` partir de e a la concatnation logique dune suite dobjets InputStream. e Construction ` partir de deux InputStream ou dune a numeration dont les lments sont des InputStream. e ee

FileInputStream

ByteArrayInputStream PipedInputStream

FilterInputStream

BufferedInputStream

PushbackInputStream

DataInputStream

ObjectInputStream

SequenceInputStream

En rsum : e e les sous-classes directes de InputStream se distinguent par le type de la source des donnes lues, e les sous classes de FilterInputStream sont diverses sortes de couches ajoutes par-dessus un autre e ux. Flux doctets en sortie OutputStream sentent
c H. Garreta, 2000-2010

Classe abstraite, super-classe de toutes les classes qui repre

75

9.4

Entres-sorties e

QUELQUES CLASSES UTILES

des ux (doctets) en sortie. Un tel ux reoit des octets et c les envoie vers un certain puits ( puits soppose ` source ) a Comporte une mthode abstraite : void write(int b), qui e crit un octet. e FileOutputStream Un ux de sortie associ ` un chier du syst`me sous-jacent. ea e Construction ` partir dun String, dun File ou dun a FileDescriptor. Un ux de sortie dans lequel les donnes sont ranges dans e e un tableau doctets. Construction ` partir de rien. a Voir PipedInputStream. Construction ` partir dun PipedInputStream ou ` partir a a de rien. Un ux qui envoie les donnes ` un autre ux (donn lors e a e de la construction) apr`s leur avoir appliqu un certain e e traitement. Construction ` partir dun OutputStream. a Un ux de sortie qui regroupe les octets logiquement crits e avant de provoquer un appel du syst`me sous-jacent en vue e dune criture physique. e Construction ` partir dun OutputStream. a Un ux de sortie destin ` lcriture de donnes des types ea e e primitifs de Java. Les donnes ne sont pas formates (traduites en textes e e lisibles par un humain) mais elles sont crites de mani`re e e portable. Construction ` partir dun OutputStream. a Un ux destin ` lcriture de toutes sortes de donnes, sous ea e e une forme lisible par un humain. Ces ux ne gn`rent jamais dexception ; ` la place, ils e e a positionnent une variable prive qui peut tre teste ` laide e e e a de la mthode checkError. e De plus, ces ux g`rent le vidage (ushing) du tampon dans e certaines circonstances : appel dune mthode println, e criture dun caract`re \n, etc. e e Construction ` partir dun OutputStream. a Un ux de sortie pour crire des donnes de types primitifs e e et des objets Java dans un OutputStream. Cela sappelle la srialisation des donnes. Les objets peuvent ensuite tre e e e lus et reconstitus en utilisant un ObjectInputStream. e Construction ` partir dun OutputStream. a Seuls les objets qui implmentent linterface Serializable e peuvent tre crits dans un ux ObjectOutputStream. La e e classe (nom et signature) de chaque objet est code, ainsi e que les valeurs des variables dinstance (sauf les variables dclares transient). e e La srialisation dun objet implique la srialisation des e e objets que celui-ci rfrence, il sagit donc de mettre en ee squence les nuds dun graphe, qui peut tre cyclique. e e Cest pourquoi cette opration, assez complexe, est e tr`s utile. e ` Flux de caracteres en entree Les ux de caract`res, en entre et en sortie. Ces ux sont comme les ux doctets, mais linformation e e lmentaire y est le caract`re (Java utilisant le codage Unicode, un caract`re nest pas la mme chose quun ee e e e octet). 76
c H. Garreta, 2000-2010

ByteArrayOutputStream

PipedOutputStream

FilterOutputStream

BufferedOutputStream

DataOutputStream

PrintStream

ObjectOutputStream

QUELQUES CLASSES UTILES

9.4

Entres-sorties e

Reader

Classe abstraite, super-classe de toutes les classes qui lisent des ux de caract`res. e Deux mthodes abstraites : int read(char[], int, int) e et void close(). Les objets de cette classe amliorent lecacit des oprae e e dentre en burisant les lectures sur un ux souse e jacent (un objet Reader donn en argument du e constructeur). Construction ` partir dun Reader. a LineNumberReader Un ux dentre buris qui garde trace des numros des e e e e lignes lues. (Une ligne est une suite de caract`res termine par \r, e e \n ou \r\n). Construction ` partir dun Reader. a Un ux qui obtient les caract`res lus ` partir dun tableau e a de caract`res interne, quon indique lors de la construction e du ux. Construction ` partir dun char[]. a Un ux de caract`res qui obtient les donnes dans un ux e e doctets (un objet InputStream donn en argument du e constructeur). Un tel objet assure donc le travail de conversion des octets en caract`res. e Construction ` partir dun InputStream. a (Classe de confort) Un ux dentre de caract`res qui e e obtient ses donnes dans un chier. e On suppose que le codage des caract`res par dfaut et la e e taille par dfaut du tampon sont adquats. (Si tel nest pas e e le cas il vaut mieux construire un InputStreamReader sur un FileInputStream) Construction ` partir dun String, dun File ou dun a FileDescriptor. Classe abstraite pour la lecture de ux ltrs ( ?) e Poss`de, ` titre de membre, un objet Reader dont il ltre e a les caract`res lus. e Flux dentre de caract`res ayant la possibilit de dlire e e e e un ou plusieurs caract`res. e Construction ` partir dun Reader. a Lquivalent, pour des ux de caract`res, dun PipedInputStream. e e Construction ` partir dun PipedWriter ou ` partir de rien. a a Un ux de caract`res dont la source est un objet String. e Construction ` partir dun String. a

BufferedReader tions

CharArrayReader

InputStreamReader

FileReader

FilterReader

PushbackReader

PipedReader StringReader

` Flux de caracteres en sortie Writer Classe abstraite, super-classe de toutes les classes qui crivent e des ux de caract`res. e Mthodes abstraites : void write(char[], int, int), e void flush() et void close(). Un ux de sortie dans lequel les caract`res logiquement e crits sont groups pour diminuer le nombre eectif dcrie e e physiques. Construction ` partir dun Writer. a CharArrayWriter
c H. Garreta, 2000-2010

BufferedWriter tures

Un ux qui met les caract`res produits dans un tableau de e 77

9.4

Entres-sorties e

QUELQUES CLASSES UTILES

caract`res. e Construction ` partir de rien. a OutputStreamWriter Un ux qui met les caract`res crits dans un OutputStream e e pralablement construit. e Un tel objet prend donc en charge la conversion des caract`res en des octets. e Construction ` partir dun OutputStream. a (Classe de confort) Un ux qui envoie les caract`res crits e e dans un chier. Construction ` partir dun String, dun File ou dun a FileDescriptor. Classe abstraite pour la dnition de ux ltrs dcriture e e e de caract`res. e Lquivalent, pour un ux de caract`res, dun e e PipedOutputStream. Voir PipedReader. Construction ` partir dun PipedReader ou ` partir de rien. a a Un ux qui met les caract`res crits dans un objet e e StringBuffer, lequel peut tre utilis pour construire un e e String. Construction ` partir de rien. a Un ux de caract`res destin ` lenvoi de reprsentations e ea e formates de donnes dans un ux pralablement construit. e e e Un PrintWriter se construit au-dessus dun OutputStream ou dun Writer pralablement cr. e ee

FileWriter

FilterWriter PipedWriter

StringWriter

PrintWriter

Autres classes File Un objet File est la reprsentation abstraite dun chier, e dun rpertoire ou, plus gnralement, dun chemin du e e e syst`me de chiers sous-jacent. e Un FileDescriptor est un objet opaque qui reprsente une e entit spcique de la machine sous-jacente : un chier e e ouvert, un socket ouvert ou toute autre source ou puits doctets. La principale utilit dun tel objet est la cration dun e e FileInputStream ou dun FileOutputStream. Un objet RandomAccessFile reprsente un chier e supportant lacc`s relatif. e Cette classe implmente les interfaces DataInput et e DataOutput, cest-`-dire quelle supporte les oprations de a e lecture et dcriture, ainsi que des oprations pour e e positionner et obtenir la valeur dune certaine position courante dans le chier Un objet de cette classe est un analyseur qui reconna des t units lexicales formes doctets ou de caract`res provenant e e e dune source de donnes. e Les units sont de quatre types : TT_NUMBER (la valeur est e un double), TT_WORD, TT_EOF et (ventuellement) TT_EOL. e Dans le mme ordre dides, voir aussi StringTokenizer. e e

FileDescriptor

RandomAccessFile

StreamTokenizer

9.4.2

Exemples

1. Ecriture et lecture dans un fichier binaire . Les deux mthodes de la classe FichierBinaire e suivante permettent denregistrer un tableau de nombres ottants (des double) dans un chier, ou bien de reconstituer un tel tableau ` partir de ses valeurs pralablement enregistres. Le chier en question est form a e e e dun nombre entier n suivi de n nombres ottants en double prcision : e 78
c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.4

Entres-sorties e

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. Mme sorte de travail qu` lexemple prcdente, e a e e mais le chier est maintenant de texte. Cest moins ecace, puisque les donnes sont exprimes sous une e e forme textuelle (donc du travail supplmentaire lors de lcriture et lors de la lecture), mais cela permet e e lexploitation ou la modication du chier par des outils gnraux (imprimantes, diteurs de texte, etc.). e e e Pour faciliter lventuelle exploitation humaine du chier, devant chaque donne ni on crit son rang i : e e e 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 donnes que prvu"); e e donnees.close(); return result; } 3. Lecture sur lentree standard. La classe Est (comme Entree STandard) ore un petit nombre de mthodes statiques destines ` eectuer simplement des oprations de lecture ` lentre standard (souvent e e a e a e le clavier) : int lireInt() : lecture dun nombre entier,
c H. Garreta, 2000-2010

79

9.4

Entres-sorties e

QUELQUES CLASSES UTILES

double lireDouble() : lecture dun nombre ottant, char lireChar() : lecture dun caract`re, e String lireString() : lecture de toute une ligne, void viderTampon() : remise ` zro du tampon dentre. a e e

Note Java 5. La classe Est montre ici reste un exemple intressant dutilisation de la biblioth`que des e e e entres-sorties, mais il faut savoir qu` partir de la version 5 de Java le service rendu par cette classe est pris e a en charge de mani`re un peu plus professionnelle par la classe java.util.Scanner de la biblioth`que e e standard (cf. 12.3.4, page 158). 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("dnomination? "); e 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(); 80
c H. Garreta, 2000-2010

// Si tous les caract`res ordinaires e // de la ligne courante ont t lus, e e // le caract`re renvoy est \n e e

QUELQUES CLASSES UTILES

9.4

Entres-sorties e

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 transformes e return entree.readLine(); // en RuntimeException (non contr^les) o e } 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`res en une suite dunits lexicales ou tokens e e des mots obissant ` une grammaire lexicale souvent dnie par un ensemble dexpressions rguli`res. e a e e e 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 sophistiqus peuvent tre raliss ` laide des classes e e e e a de manipulation dexpressions rguli`res, java.util.regex.Pattern et java.util.regex.Matcher. A ce e e 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 et value des expressions aritht e mtiques lues ` lentre standard, formes avec des nombres, les quatre oprations et les parenth`ses, et e a e e e e termines par le caract`re =. e e Il est intressant dobserver lempilement de ux dentre ralis dans le constructeur de la classe Cale e e e culateur : ` la base, il y a System.in, qui est un ux doctets (un InputStream) ; autour de ce ux on a a mis adaptateur, qui est un ux de caract`res (un InputStreamReader, donc un Reader) ; autour de e ce dernier, on a construit unites, un ux dunits lexicales (un StreamTokenizer). e

c H. Garreta, 2000-2010

81

9.4

Entres-sorties e

QUELQUES CLASSES UTILES

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 ` la fin de lexpression"); a 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(); } 82


c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.4

Entres-sorties e

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 donnes e

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 donnes e sensibles aux particularits locales (nombres, dates, etc.). e 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`te, prenant en charge lcriture en base 10 des e e nombres. Un objet de cette classe reprsente lensemble des symboles e qui interviennent dans le formatage dun nombre (sparae dcimal, sparateur de paquets de chires, etc.). e e Le constructeur par dfaut de cette classe initialise un objet e 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 ` lendroit o` le a u programme est excut) : e 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 dfaut : " + s); e ... Achage obtenu (en France) : format "brut" : 1234567.23456789 format local par dfaut : 1 234 567,235 e Comme on le voit ci-dessus, il se peut que des nombres formats en accord avec les particularits locales e e ne puissent pas tre donns ` relire aux mthodes basiques de Java, comme Integer.parseInt ou e e a e
c H. Garreta, 2000-2010

83

9.4

Entres-sorties e

QUELQUES CLASSES UTILES

Double.parseDouble. Pour reconstruire les nombres que ces textes expriment on doit employer les mthodes e correspondantes de la classe NumberFormat. Voici une possible continuation de lexemple prcdent : e e ... 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 dfaut : 1 234 567,235 e valeur "relue" : 1234567.235 Exemple 2. Utilisation de ces classes pour obtenir une mise en forme prcise qui ne correspond pas e forcment aux particularits locales. Dans lexemple suivant on crit les nombres avec exactement deux e e e dcimales, la virgule dcimale tant reprsente par un point et les chires avant la virgule groups par e e e e e e paquets de trois signals par des apostrophes : e 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 t : ee 000000001.50 000000000.00 012345678.00 Exemple 3. Des formats spciques comme les prcdents peuvent aussi tre composs ` laide de e e e e e a mthodes set... de la classe DecimalFormat : e 84
c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.4

Entres-sorties e

public class Formatage { public static void main(String[] args) { DecimalFormat formateur = (DecimalFormat) NumberFormat.getInstance(); // Modifier ce format afin quil ressemble ` 999.99[99] a 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)); } } Excution : e

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 ` droite a des nombres ou, plus exactement, un cadrage calcul ` partir de la position de la virgule. De telles mises en ea forme sont ncessaires pour constituer des colonnes de nombres correctement aligns. e e Par exemple, proposons-nous dacher une table de conversion en degrs Celsius dune srie de tempe e e ratures exprimes en degrs Fahrenheit : e e 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`s beau : e -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`me version de ce programme, dans laquelle un objet FieldPosition est utilis pour e e conna tre, dans lexpression formate dun nombre, lindice du caract`re sur lequel se termine sa partie e e enti`re (cest-`-dire, selon le cas, soit la n du nombre, soit la position de la virgule). Cet indice permet de e a calculer le nombre de blancs quil faut ajouter ` la gauche du nombre pour le cadrer proprement : a
c H. Garreta, 2000-2010

85

9.4

Entres-sorties e

QUELQUES CLASSES UTILES

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

Reprsentation des dates e

La manipulation et lachage des dates sont traits en Java avec beaucoup de soin (portabilit oblige !), e e mais la question peut sembler un peu embrouille car elle est rpartie sur trois classes distinctes de mani`re e e e un peu arbitraire : java.util.Date - Un objet de cette classe encapsule un instant dans le temps (reprsent par le nombre de e e millisecondes coules entre le 1er janvier 1970, ` 0:00:00 heures GMT, et cet instant). e e a Dautre part, ces objets ont des mthodes pour le calcul de lanne, du mois, du jour, etc., mais elles e e sont dsapprouves, ce travail doit dsormais tre donn ` faire aux objets Calendar. e e e e ea java.util.GregorianCalendar - Cette classe est une sous-classe de la classe abstraite Calendar. Ses instances reprsentent des dates, dcomposes en plusieurs nombres qui expriment lanne, le mois, le jour e e e e dans le mois, dans lanne et dans la semaine, lheure, les minutes, etc. e java.text.DateFormat - Les instances de cette classe, fortement dpendante des particularits locales, e e soccupent de lexpression textuelle des dates. Exemple 1. Voici comment mesurer le temps que prend lexcution dun certain programme (attention, e il sagit de temps coul , qui comprend donc le temps pris par dventuelles autres tches qui ont t e e e a ee entrelaces avec celle dont on cherche ` mesurer la dure) : e a e ... void unCalcul() { Date d0 = new Date(); un calcul prenant du temps... Date d1 = new Date(); System.out.println("Temps coul: " e e + (d1.getTime() - d0.getTime()) / 1000.0 + " secondes"); 86
c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.4

Entres-sorties e

} ... Exemple 2. Un programme pour savoir en quel jour de la semaine tombe une date donne : e 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 de la date. Chaque fois quon demande ` un objet Maintenant de se e a convertir en cha de caract`res, il donne une expression de la date et heure courantes : ne e class Maintenant { private static String[] mois = { "janvier", "fvrier", "mars", ... "dcembre" }; e e 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) + " ` " + c.get(c.HOUR) + " heures " + c.get(c.MINUTE); a } public static void main(String[] args) { System.out.println("Aujourdhui: " + new Maintenant()); } } Exemple 4. La mme chose, ` laide dun objet DateFormat : e a 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 srialisation e

La srialisation est un mcanisme tr`s puissant, tr`s utile et tr`s simple demploi pour sauvegarder des e e e e e objets entiers dans des chiers et de les restaurer ultrieurement. Les points cls en sont : e e pour que les instances dune classe puissent tre srialises il doit tre dit que cette classe implmente e e e e e linterface Serializable, une interface vide par laquelle le programmeur exprime quil ny a pas dopposition ` ce que les objets en question soient conservs dans un chier, a e la srialisation dun objet implique la sauvegarde des valeurs de toutes ses variables dinstance, sauf e celles dclares transient (transitoires), e e la srialisation dun objet implique en principe celle des objets quil rfrence (ses objets membres) qui e ee doivent donc tre galement srialisables, e e e le couple srialisation (sauvegarde dans un chier) dsrialisation (restauration depuis un chier) e ee comporte un mcanisme de contrle des versions, assurant que les classes servant ` la reconstitution e o a des objets sont cohrentes avec les classes dont ces objets taient instances lors de leur srialisation, e e e
c H. Garreta, 2000-2010

87

9.4

Entres-sorties e

QUELQUES CLASSES UTILES

Le service rendu par Java lors de la srialisation dun objet est important, car la tche est complexe. e a En eet, pour sauvegarder un objet il faut sauvegarder aussi les ventuels objets qui sont les valeurs de e ses variables dinstance ; ` leur tour, ces objets peuvent en rfrencer dautres, quil faut sauver galement, a ee e et ainsi de suite. Cela revient ` parcourir un graphe, qui tr`s souvent comporte des cycles, en vitant de a e e sauvegarder plusieurs fois un mme objet et sans sombrer dans des boucles innies. e A titre dexemple, voici un programme purement dmonstratif qui cre une liste cha ee circulaire et la e e n sauvegarde dans un chier. Chaque maillon porte une date (linstant de sa cration) dont on a suppos que e e la sauvegarde tait sans intrt ; pour cette raison, cette variable a t dclare transient : e ee ee e e

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`me fichier: " + e.getMessage()); e } } }

Et voici un programme qui reconstruit la liste cha ee (bien entendu, dans la liste reconstitue les maillons n e 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(); } 88
c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.5

Expressions rguli`res e e

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

9.5
9.5.1

Expressions rguli`res e e
Principe

Le lecteur est suppos conna e tre par ailleurs la notion dexpression rguli`re, dont lexplication, mme e e e succincte, dpasserait le cadre de ce cours. Disons simplement que les expressions rguli`res considres ici e e e ee sont grosso modo celles du langage Perl 64 , et donnons quelques exemples montrant leur utilisation en Java. Le paquetage concern, java.util.regex, se compose des deux classes Pattern et Matcher : e Pattern - Un objet de cette classe est la reprsentation compile 65 dune expression rguli`re. e e e e Cette classe na pas de constructeur. On cre un objet Pattern par une expresion de la forme : e Pattern motif = Pattern.compile(texteExpReg [, ags ]); o` texteExpReg est une cha de caract`res contenant lexpression rguli`re. Si cette derni`re est u ne e e e e incorrecte, linstruction ci-dessus lance une exception PatternSyntaxException, qui est une sousclasse de RuntimeException 66 . Matcher - Un objet de cette classe se charge dappliquer une expression rguli`re sur un texte, pour eectuer e e les oprations de reconnaissance, de recherche ou de remplacement souhaites. e e On cre un objet Matcher ` partir dun objet Pattern, par une expression de la forme : e a Matcher reconnaisseur = motif .matcher(texteAExaminer ); Lobjet reconnaisseur ainsi cr dispose des mthodes : ee e boolean matches() : lexpression rguli`re reconna e e t-elle la totalit du texte ` examiner ? e a boolean lookingAt() : lexpression rguli`re reconna e e t-elle le dbut du texte ` examiner ? e a boolean find([int start]) : lexpression rguli`re reconna e e t-elle un morceau du texte ` examia ner ? A la suite dun appel dune des trois mthodes ci-dessus, les mthodes int start() et int end() de e e lobjet Matcher renvoient le dbut et la n de la sous-cha reconnue, tandis que la mthode String e ne e group() renvoie la cha reconnue elle-mme. ne e On se reportera ` la documentation de lAPI pour des explications sur les (nombreuses) autres possia bilits de la classe Matcher. e 9.5.2 Exemples

1. Decouper un texte. Pour les oprations les plus simples il ny a pas besoin de crer des objets e e Matcher, des mthodes ordinaires (exemple 1) ou statiques (exemple 2) de la classe Pattern susent. Par e exemple, le programme suivant prend une cha donne en argument et lache ` raison dun mot par ligne, ne e a en considrant que les sparateurs de mots sont la virgule ( , ), le point-virgule ( ; ) et les caract`res e e e blancs de toute sorte (collectivement reprsents par \s ) : e e

64. La syntaxe prcise des expressions rguli`res acceptes par Java est donne dans la documentation de lAPI, au dbut de e e e e e e lexplication concernant la classe java.util.regex.Pattern 65. Un objet Pattern consiste essentiellement en lencapsulation des tables qui dnissent lautomate dtats ni correspondant e e ` lexpression rguli`re donne. a e e e 66. Rappelons que les RuntimeException sont des exceptions non contrles. Par consquent, si une mthode contient des oe e e appels de Pattern.compile il nest pas ncessaire de lui adjoindre une clause throws PatternSyntaxException . e

c H. Garreta, 2000-2010

89

9.5

Expressions rguli`res e e

QUELQUES CLASSES UTILES

import java.util.regex.Pattern; public class Mots { public static void main(String[] args) { Pattern motif = Pattern.compile("[,;\\s]+"); // dcoupe de la cha^ne args[0] en mots e 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 Batrice e Caroline Emile $

"Andr, Batrice e e

Caroline,

Emile"

2. Verifier la correction dune cha ne. Une autre opration simple quune mthode statique de la e e classe Pattern peut eectuer sans laide dun objet Matcher : compiler une expression rguli`re et dterminer e e e si elle correspond ` la totalit dune cha donne. a e ne e Par exemple, la mthode suivante dtermine si la cha passe en argument est lcriture correcte dun e e ne e e nombre dcimal en virgule xe : e

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

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

Note 2. Dans le cas o` la mthode prcdente est susceptible dtre frquemment appele, il est mau e e e e e e nifestement maladroit de compiler chaque fois la mme expression rguli`re. Lemploi dun objet Pattern e e e permet dviter cela : e

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 (reprsents par des balises comme <a href="http://www.luminy.univ-mrs.fr" ... >) : e e 90
c H. Garreta, 2000-2010

QUELQUES CLASSES UTILES

9.5

Expressions rguli`res e e

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 rguli`res. Voici les seules modications ` faire dans le programme prcdent : e e a e e 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 67 . Appel avec largument un chat, deux chats, trois chats dans mon jardin il ache e donc la cha un chien, deux chiens, trois chiens dans mon jardin. ne
67. Utile, hein ?

c H. Garreta, 2000-2010

91

9.5

Expressions rguli`res e e

QUELQUES CLASSES UTILES

Notez que cest recon, lobjet Matcher, qui prend soin de recopier dans la cha sortie les caract`res ne e 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 t rdig comme cela pour illustrer les mthodes appendReplacement et appendTail. ee e e e On notera cependant que, sagissant de remplacer toutes les occurrences dun motif par une cha il y a un ne, 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); }

92

c H. Garreta, 2000-2010

10

THREADS

10

Threads

Ltude des threads est ` sa place dans un cours sur la programmation parall`le et sort largement du e a e cadre de ce polycopi. Nous nous limitons ici ` donner quelques explications sur certaines notions basiques e a auxquelles on est confront dans les applications les plus courantes, par exemple lorsquon programme des e interfaces utilisateur graphiques. Un thread, ou processus lger, est lentit constitue par un programme en cours dexcution. Cela se e e e e matrialise par un couple (code, donnes) : le code en cours dexcution et les donnes que ce code traite. e e e e Si on en parle ici cest que Java supporte lexistence simultane de plusieurs threads : ` un instant donn e a e plusieurs programmes peuvent sexcuter en mme temps. e e Ce que en mme temps veut dire exactement dpend du matriel utilis. Dans un syst`me possdant e e e e e e plusieurs processeurs il est possible que divers threads sexcutent chacun sur un processeur distinct et on e est alors en prsence dun paralllisme vrai. Mais, plus couramment, les syst`mes ne bncient que dun ou e e e e e deux processeurs et il faut se contenter dun paralllisme simul : les divers threads existant ` un instant e e a donn disposent du processeur ` tour de rle. e a o Direntes raisons peuvent faire quun thread qui est en train dutiliser le processeur le c`de ` un autre e e a thread qui patiente pour lavoir : 1) le blocage du thread actif par une commande place dans le code en cours dexcution, comme wait e e (attendre) ou sleep (dormir), 2) le blocage du thread actif par le fait quil entame une opration dentre-sortie 68 , e e 3) le dblocage dun thread ayant une priorit suprieure ` celle du thread actif, e e e a 4) lpuisement dune certaine tranche de temps alloue au thread actif. e e Si tout thread cesse dtre actif d`s quun thread de priorit suprieure est prt (cas 3, ci-dessus) on dit e e e e e quon a aaire ` un paralllisme premptif. La machine Java proc`de gnralement ainsi. a e e e e e Le fonctionnement par attribution de tranches de temps (cas 4) ne fait pas partie des spcications de la e machine Java. Celle-ci en bncie ou non, selon les caractristiques du matriel sous-jacent. e e e e

10.1
10.1.1

Cration et cycle de vie dun thread e


Dclaration, cration et lancement de threads e e

Il y a deux mani`res, tr`s proches, de crer un thread : e e e en dnissant et en instanciant une sous-classe de la classe Thread dnie ` cet eet, dans laquelle au e e a moins la mthode void run() aura t rednie, e ee e en appelant le constructeur de Thread avec pour argument un objet Runnable 69 Dans un cas comme dans lautre, le thread cr est rendu vivant lors de lappel de sa mthode start(). ee e Java met alors en place tout le ncessaire pour grer le nouveau thread, puis appelle sa mthode run(). Au e e e moment de son dmarrage, le thread nouvellement cr : e ee a pour code la mthode run(), e a pour donnes celles du thread dans lequel il vient dtre cr. e e ee Exemple. Le thread purement dmonstratif suivant est tr`s simple : dix fois il ache son nom et un entier e e croissant, puis sendort pour une priode comprise entre 0 et 1000 millisecondes : e public class ThreadSimple extends Thread { public ThreadSimple(String nom) { super(nom); }
68. Cest en considrant ce type de situations quon peut comprendre pourquoi le paralllisme fait gagner du temps mme e e e lorsquil est simul : quand un thread se met en attente dune entre-sortie sur disque (opration beaucoup plus lente que le e e e travail en mmoire centrale) ou, pire, en attente dune frappe au clavier, dun vnement rseau, etc., le contrle est cd a un e e e e o e e` thread non bloqu ; ainsi, le processeur est moins souvent oisif. e 69. Un objet Runnable c.-`-d. implmentant linterface java.lang.Runnable est tout simplement un objet possdant une a e e mthode run(). e

c H. Garreta, 2000-2010

93

10.1

Cration et cycle de vie dun thread e

10

THREADS

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 mthode sleep doit toujours tre appele dans un bloc try...catch puisque cest par le e e e lancement dune exception InterruptedException que le thread endormi est rveill lorsque le temps indiqu e e e est coul. Il en est de mme, et pour la mme raison, de la mthode wait. e e e e e Voici un programme qui fait tourner en parall`le deux exemplaires de ce thread : e 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 excution, limbrication des messages Seychelles ... e parmi les messages Maurice ... peut tre dirente) : e e 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`me exemple (un peu prmatur, les interfaces graphiques ne sont tudies qu` la section suivante). e e e e e a Nous souhaitons disposer dun cadre dont la barre de titre ache constamment lheure courante ` la seconde a pr`s. Il sura pour cela de crer, en mme temps que le cadre, un deuxi`me thread qui dort 70 la plupart du e e e e temps, se rveillant chaque seconde pour mettre ` jour le texte ach dans la barre de titre : e a e 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); }
70. Quand un thread dort il ne consomme aucune ressource syst`me. e

94

c H. Garreta, 2000-2010

10

THREADS

10.2

Synchronisation

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 mthode run(), il se termine normalement et lib`re les ressources e e qui lui ont t alloues. Mais comment provoque-t-on la terminaison anticipe 71 dun thread ? ee e e La classe Thread comporte une mthode stop() dont le nom exprime bien la fonction. Mais elle est e vigoureusement dsapprouve (deprecated ), car elle laisse dans un tat indtermin certains des objets qui e e e e e dpendent du thread stopp. e e La mani`re propre et able de terminer un thread consiste ` modier la valeur dune variable que le thread e a consulte rguli`rement. Par exemple, voici la classe CadreAvecHeure montre prcdemment, complte par e e e e e ee une mthode arreterLaPendule() qui stoppe le rafra e chissement de lheure ache : e public class CadreAvecHeure extends JFrame { String titre; boolean go; public CadreAvecHeure(String titre) { comme la version prcdente e e } 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 dmarre, un thread travaille sur les donnes du thread dans lequel il a t cr. Par exemple, dans e e e e ee le programme CadreAvecHeure ci-dessus, le thread ls qui excute la mthode gererAffichageHeure e e acc`de aux donnes this (atteinte lors de lappel de setTitle) et go qui appartiennent aussi au thread e e p`re qui la cr. Cela pose le probl`me de lacc`s concurrent aux donnes, source potentielle de blocages e ee e e e
71. On notera que si un thread se compose dune boucle innie, comme dans la mthode gererAffichageHeure, sa terminaison e ne peut tre quanticipe : sans intervention extrieure, cette mthode ne se terminera jamais. e e e e

c H. Garreta, 2000-2010

95

10.2

Synchronisation

10

THREADS

et derreurs subtiles, un probl`me dlicat quon r`gle souvent ` laide de verrous protgeant les sections e e e a e 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 lments. La collection est reprsente par un objet List, ee e e laction par un objet Action (une interface expressment dnie ` cet eet). e e a 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 accder ` la liste, la mthode prcdente est correcte. Mais e a e e e sil peut arriver que, pendant quun thread parcourt la liste, un autre thread la modie en ajoutant ou en enlevant des lments, alors le parcours prcdent a des chances de devenir incohrent. Une premi`re mani`re ee e e e e e de rsoudre ce probl`me consiste ` rendre synchronise la mthode parcourir : e e a e e 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 devant la mthode parcourir est le suivant : lors dun appel e e de cette mthode, de la forme 72 e unObjet.parcourir(uneAction); un verrou sera pos sur unObjet de sorte que tout autre thread qui tentera une opration synchronise sur e e e ce mme objet (en appelant une autre mthode synchronized de cette mme classe) sera bloqu jusqu` ce e e e e a que ce verrou soit enlev. e Cela r`gle le probl`me de lacc`s concurrent ` la liste, mais peut-tre pas de mani`re optimale. En eet, e e e a e e si le traitement que reprsente la mthode agir est long et complexe, alors la liste risque de se trouver e e verrouill pendant une longue priode et ralentir lensemble du programme. e e Do` une solution bien plus lg`re : tablir une section critique (i.e. protge par un verrou) dans laquelle u e e e e e on ne fait que cloner la liste puis, le verrou tant lev, eectuer le parcours du clone, lequel ne craint pas les e e 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()); }
72. Un appel de la forme parcourir(uneAction) nest pas dirent, car il quivaut ` this.parcourir(uneAction) . e e a

96

c H. Garreta, 2000-2010

10

THREADS

10.2

Synchronisation

Iterator iter = copie.iterator(); while (iter.hasNext()) action.agir(iter.next()); } 10.2.2 Mthodes synchronises e e

Pour terminer cette prsentation des threads voici un grand classique de la programmation parall`le : e e une implmentation du mod`le dit des producteurs et des consommateurs . e e Considrons la situation suivante : un certain nombre de fois par exemple 10 chaque producteur e fabrique un produit (numrot), le dpose dans un entrept qui ne peut en contenir quun, puis dort un e e e o 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 lentrept et le consomme : o 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`me cest que les producteurs et les consommateurs ne se connaissent e pas et ne prennent aucune mesure pour prvenir les conits. e Or, lorsque lentrept est vide les consommateurs ne peuvent pas consommer et lorsquil est plein les o producteurs ne peuvent pas produire. Cest lentrept qui g`re ces conits. En revanche, il est indpendant o e e du nombre de producteurs et de consommateurs qui traitent avec lui :

c H. Garreta, 2000-2010

97

10.2

Synchronisation

10

THREADS

public class Entrepot { private int contenu; private boolean disponible = false; 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(); } } Le fonctionnement de lentrept est assez savant. Les mthodes prendre et deposer tant synchronized, o e e un seul thread peut sy trouver ` un instant donn. a e Lorsquun consommateur appelle la mthode prendre e si un produit est disponible (i.e. disponible == true) alors disponible devient false et une notication est envoye ` tous les threads qui sont en attente dune notication sur cet entrept ; en mme e a o e 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 entrept. o Lappel de notifyAll dbloque tous les threads en attente. Si parmi eux il y a des producteurs, au plus un e deux trouve disponible == false et peut donc produire, tous les autres (producteurs et consommateurs) se rebloquent (` cause du while) et attendent une nouvelle notication. a Le fonctionnement de lentrept vu du ct de la mthode deposer est rigoureusement symtrique du o oe e e prcdent. Voici un programme principal qui lance deux de ces threads : e e 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

98

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11

Interfaces graphiques

Plus encore que pour les sections prcdentes, il faut rappeler que ces notes ne cherchent pas ` tre un e e ae manuel de rfrence, mme pas succinct. Quels que soient les langages et les syst`mes utiliss, les biblioth`ques ee e e e e pour raliser des interfaces graphiques sont toujours extrmement copieuses. Celles de Java ne font pas e e exception ; nous navons pas la place ici pour expliquer les tr`s nombreuses classes et mthodes qui les e e constituent. Nous nous contenterons donc dexpliquer les principes de fonctionnement des lments dAWT et de ee Swing les plus importants et den montrer le mode demploi ` travers des exemples de taille raisonnable. a Outre un certain nombre de livres plus ou moins exhaustifs, dont louvrage (en franais, ` part le titre) : c a David Flanagan Java Foundation Classes in a Nutshell OReilly, 2000 deux rfrences absolument indispensables pour programmer des interfaces graphiques en Java sont les deux ee hypertextes dj` cits : ea e 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/, spcialement sa section Creating a GUI with e JFC/Swing.

11.1

JFC = AWT + Swing

Une caractristique remarquable du langage Java est de permettre lcriture de programmes portables e e avec des interfaces-utilisateur graphiques, alors que partout ailleurs de telles interfaces sont ralises au moyen e e de biblioth`ques spares du langage et tr`s dpendantes du syst`mes dexploitation sur lequel lapplication e e e e e e doit tourner, ou du moins de la couche graphique employe. e La premi`re biblioth`que pour raliser des interfaces-utilisateur graphiques 73 en Java a t AWT, acroe e e ee nyme de Abstract Windowing Toolkit. Fondamentalement, lensemble des composants de AWT est dni e comme la partie commune des ensembles des composants graphiques existant sur les dirents syst`mes e e sur lesquels la machine Java tourne. Ainsi, chaque composant dAWT est implment par un composant e e homologue (peer ) appartenant au syst`me hte, qui en assure le fonctionnement. e o AWT est une biblioth`que graphique originale et pratique, qui a beaucoup contribu au succ`s de Java, e e e mais elle a deux inconvnients : puisque ses composants sont censs exister sur tous les environnements e e viss, leur nombre est forcment rduit ; dautre part, mme rputs identiques, des composants appartenant e e e e e e a ` des syst`mes dirents prsentent malgr tout des dirences de fonctionnement qui nissent par limiter e e e e e la portabilit des programmes qui les utilisent. e Cest la raison pour laquelle AWT a t complte par une biblioth`que plus puissante, Swing. Apparue ee ee e comme une extension (c.-`-d. une biblioth`que optionnelle) dans danciennes versions de Java, elle appartient a e a ` la biblioth`que standard depuis lapparition de Java 2 . En Swing, un petit nombre de composants de haut e niveau (les cadres et les bo de dialogue) sont apparis ` des composants homologues de lenvironnement tes e a graphique sous-jacent, mais tous les autres composants qui, par dnition, nexistent quinclus dans un des e prcdents sont crits en pur Java 74 et donc indpendants du syst`me hte. e e e e e o Au nal, Swing va plus loin que AWT mais ne la remplace pas ; au contraire, les principes de base et un grand nombre dlments de Swing sont ceux de AWT. Ensemble, AWT et Swing constituent la biblioth`que ee e ociellement nomme JFC (pour Java Foundation Classes 75 ). e 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 rle important dans Swing, comme le syst`me o e des vnements (EventListener ), les gestionnaires de disposition (LayoutManager ), etc. e e 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.
73. Pour nommer les interfaces-utilisateur graphiques vous trouverez souvent lacronyme GUI, pour Graphics User Interface. 74. La documentation ocielle exprime cela en disant que les composants de AWT, chacun appari avec un composant e du syst`me sous-jacent, sont lourds , tandis que ceux de Swing, crits en pur Java, sont lgers . Ah, la belle langue e e e technicommerciale... ! 75. JFC est une sorte de citation de la cl`bre MFC ou Microsoft Foundation Classes, une biblioth`que de classes C++ de ee e chez Microsoft pour programmer les interfaces-utilisateur graphiques des applications destines ` Windows. e a

c H. Garreta, 2000-2010

99

11.2

Le haut de la hirarchie e

11

INTERFACES GRAPHIQUES

11.2

Le haut de la hirarchie e

Commenons par donner quelques indications sur la mani`re dont le travail se partage entre les classes c e qui constituent le haut de la hirarchie dhritage, cest-`-dire les classes dont toutes les autres hritent. e e a e Cette section 11.2 est enti`rement culturelle (elle ne contient pas dinformations techniques prcises), e e mais il vaut mieux avoir compris les concepts quelle expose avant de commencer ` utiliser les composants a graphiques. Composants (Component) La classe java.awt.Component est le sommet de la hirarchie qui nous intresse ici, cest-`-dire la supere e a classe de toutes les classes qui reprsentent des composants graphiques, aussi bien AWT que Swing. Le e comportement dun objet Component est tr`s riche, mais si on se limite aux fonctionnalits les plus repre e e sentatives du rle dun composant il faut mentionner : o Se dessiner. Puisquun composant est un objet graphique, la plus prvisible de ses mthodes est celle e e qui en produit lexposition sur un cran ou un autre organe dachage. Cette mthode se nomme paint et e e elle est toute prte pour les composants prdnis, qui prennent soin de leur apparence graphique, mais on e e e doit la rednir lorsquon cre des composants au dessin spcique. e e e Comme on le verra, cette mthode obligatoire nest jamais appele par les programmes ; au lieu de cela, e e cest la machine Java qui lappelle, chaque fois que lapparence graphique dun composant a t endommage ee e et doit tre rpare. e e e Davantage dinformations au sujet de la mthode paint et des oprations graphiques sont donnes dans e e e la section 11.6. Obtenir la taille et la position du composant. Une autre proprit fondamentale de tout composant est ee que, une fois dessin, il occupe un rectangle 76 sur lcran ou lorgane dachage. Des mthodes nommes e e e e getBounds, getSize, getLocation, etc., permettent dobtenir les coordonnes de ce rectangle. e Dnir la taille et la position du composant. On pourrait penser que puisquil y a des mthodes pour e e obtenir la taille et la position dun composant, il y en a galement pour xer ces param`tres. e e Ces mthodes existent (elles se nomment setSize, setMinimumSize, setMaximumSize, setPreferredSize, e etc.) mais la question est plus complique quon ne pourrait le penser dabord car, sauf exception, la taille e et la position dun composant dcoulent dune ngociation permanente avec le gestionnaire de disposition e e (LayoutManager) du conteneur dans lequel le composant a t plac. ee e Des explications sur les gestionnaires de disposition sont donnes ` la section 11.7 e a Dnir et obtenir les proprits graphiques. Puisque le propre dun composant est dtre dessin il est e ee e e normal quil comporte tout un ensemble de mthodes pour dnir ou consulter ses proprits graphiques, e e ee comme la couleur du fond (setBackground, getBackground), la couleur de ce qui est dessin par-dessus e (setForeground, getForeground), la police courante (setFont, getFont), etc. Les proprits graphiques dun composant dnissent les valeurs initiales du contexte graphique (objet ee e Graphics) utilis par toute oprations de peinture (i.e. lappel par la machine Java de la mthode paint). e e e Les contextes graphiques et la mthode paint sont expliqus ` la section 11.6. e e a Etre source dvnements. Puisquun composant est visible sur un cran, il est naturellement prdestin e e e e e ae ` tre la cible dactions faites par lutilisateur ` laide de la souris, du clavier ou de tout autre organe de a saisie disponible. Lorsquune telle action se produit, Java cre un vnement, un objet dcrivant le type et les circonstances e e e e de laction produite ; on dit que le composant sur lequel laction sest produite est la source de lvnement. e e Java notie alors cet vnement ` un ou plusieurs objets, appels les auditeurs de lvnement, qui sont e e a e e e censs dclencher la raction requise. e e e Ce mcanisme se manifeste au programmeur ` travers des mthodes nommes addXxx Listener (la e a e e partie Xxx dpend de lvnement en question), qui permettent dattacher des auditeurs des divers types e e e dvnements aux objets qui peuvent en tre des sources : addMouseListener, addActionListener, etc. e e e La question des vnements et de leurs auditeurs est reprise en dtail ` la section 11.5. e e e a 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 mthodes fondamentales : e Ajouter un composant. Cest la mthode add, sous la forme leConteneur .add(unComposant) qui e eectue de tels ajouts. Selon le gestionnaire de disposition en vigueur, elle peut requrir dautres arguments. e
76. On consid`re presque toujours quun composant occupe un rectangle, mme lorsquil ne semble pas rectangulaire. e e

100

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.2

Le haut de la hirarchie e

Associer au conteneur un gestionnaire de disposition. Un gestionnaire de disposition, ou layout manager, est un objet (invisible) qui conna le conteneur et la liste de ses composants et qui commande la taille et t la position de ces derniers, cela aussi bien lors de lachage initial du conteneur, au moment de sa cration e que, par la suite, chaque fois que la taille ou la forme du conteneur sont modies. e Des explications sur les gestionnaires de disposition sont donnes ` la section 11.7. e a Fentres (Window) e La classe java.awt.Window est une sous-classe de java.awt.Container. La caractristique dune fentre e e est la possibilit dtre visible sans ncessiter dtre incluse dans un autre composant, contrairement ` tous e e e e a les composants qui ne sont pas des fentres. e La classe Window apporte donc la machinerie ncessaire pour grer lexistence dun composant sur lorgane e e dachage, ce qui demande, parmi dautres choses, de grer la coexistence avec les autres fentres dont e e beaucoup nont pas de lien avec lapplication en cours, ni mme avec Java qui sont visibles sur lorgane e dachage en mme temps. Cette machinerie est mise en route ` travers des mthodes comme setVisible e a e (ou show) et pack, que nous expliquerons plus en dtail ` la section 11.4. e a Dune certaine mani`re, les fentres sont le si`ge de la vie des interfaces graphiques. Lorsquune fentre e e e e est rendue visible, un nouveau thread est cr dans lequel sexcute le programme qui dtecte les actions ee e e de lutilisateur sur la fentre et sur chacun des composants quelle contient. Cela permet ` la fentre dtre e a e e ractive mme lorsque lapplication est occupe ` dautres tches. e e e a a Les diverses fentres appartenant ` une mme application et existant ` un instant donn forment une e a e a e arborescence : sauf le cadre de lapplication, chaque fentre en rfrence une autre, sa propritaire ; ene ee e semble, les fentres constituent donc un arbre ayant pour racine le cadre de lapplication. Cela assure, par e exemple, que la destruction du cadre principal entra nera bien la destruction de toutes les fentres cres par e ee lapplication. Malgr limportance de la classe Window il est rare quelle soit explicitement mentionne dans les applicae e tions courantes : les fonctionnalits de cette classe sont presque toujours exploites ` travers les sous-classes e e a Frame et Dialog. Cadres et bo tes de dialogue (Frame, Dialog) Les classes java.awt.Frame (cadre) et java.awt.Dialog (bo de dialogue) sont des sous-classes de te 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 fentre munie dun bord, un bandeau de titre et, ventuellement, une barre de menus. e e Sur un syst`me moderne chaque application ordinaire 77 a un cadre et la plupart des applications nen ont e quun, si bien que lapplication et son cadre nissent par se confondre dans lesprit de lutilisateur ; ce nest pas fcheux, cest mme un eet recherch. a e 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 fentre qui na pas besoin de possder une fentre e e e propritaire. Il en dcoule que le point de dpart dune interface graphique est toujours un cadre, et que tout e e e composant est rattach ` un cadre 78 : e a un composant qui nest pas une fentre (Window) doit tre inclus dans un conteneur, e e un composant qui est une fentre mais pas un cadre doit rfrencer une autre fentre, sa propritaire. e ee e e Les bo de dialogue sont elles aussi des fentres munies dun bord et dune barre de titre mais, contraites e rement aux cadres, elles sont par nature nombreuses, diversies et phm`res. e e e e Les bo de dialogue sont loutil standard pour acher un message, poser une question ou demander tes des informations. Leur apparition est commande par le programme, au moment requis, et elles permettent e a ` lutilisateur de lire le message ou la question pose et, le cas chant, de faire les actions demandes (cocher e e e e des cases, remplir des champs de texte, faire des choix dans des listes, etc.) ; il y a toujours un ou plusieurs
77. Par application ordinaire nous entendons une application visible ` lcran qui interagit avec lutilisateur. Cela exclut les a e applications invisibles, les services , les dmons , etc. e 78. En particulier, la destruction dun cadre produit celle de tous les composants qui lui sont rattachs ; cela rsout les e e probl`mes de fentres orphelines survivant ` la terminaison de lapplication qui les a cres, de bouts de composant oublis et, e e a ee e plus gnralement, de certains types de fuites de mmoire qui ont empoisonn les premi`res biblioth`ques graphiques. e e e e e e

c H. Garreta, 2000-2010

101

11.3

Le point de dpart : JFrame et une application minimale. e

11

INTERFACES GRAPHIQUES

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

Le cas des composants de Swing Swing est venu apr`s AWT et, quand il est arriv, tous les noms intressants taient dj` pris : Component, e e e e ea Frame, Dialog, Button, Panel, etc. Plutt que dinventer des noms enti`rement nouveaux, forcment peu o e e signicatifs, les concepteurs de Swing ont prfr nommer les classes de Swing par les mmes noms que AWT, eee e avec un signe distinctif constant, un J en dbut du nom : JComponent, JFrame, JDialog, JButton, JPanel, e etc. Attention, loubli de ce J initial change le sens de ce quon crit, mais dune mani`re que le compilateur ne e e peut pas toujours signaler comme une erreur ; cela introduit des dysfonctionnements plus ou moins importants dans les programmes. Les sections prcdentes traitant des classes java.awt.Component, java.awt.Container, java.awt.Wine e dow, 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 des composants de Swing sont sous-classes de java.awt.JComponent ; e javax.swing.JFrame et javax.swing.JDialog sont sous-classes de java.awt.Frame et java.awt.Dialog respectivement. Enn, nos avons dj` dit que certaines des fonctions les plus fondamentales de Swing sont assures par des ea e lments de AWT qui nont pas t tendus lors de la conception de Swing : les vnements, les gestionnaires ee e ee e e de disposition, etc.

11.3

Le point de dpart : JFrame et une application minimale. e

Venons-en ` des choses plus pratiques. Pour commencer, voici une application parmi les plus rduites a e quon puisse crire : e 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 ` tous!", JLabel.CENTER); a cadre.getContentPane().add(etiquette); cadre.getContentPane().setBackground(Color.WHITE); cadre.setSize(250, 100); cadre.setVisible(true); } } Lexcution de ce programme ache le cadre montr ` la gure 9. Il est extrmement simple, mais il est e ea e vivant : lutilisateur peut en changer la taille et la position, le maximiser ou liconier, le faire passer devant ou derri`re une autre fentre, etc. e e 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 ` lextrme droite du bandeau de titre) a e fera dispara le cadre mais ne terminera pas lapplication, qui continuera ` tourner, et ` consommer des tre a a ressources, alors quelle naura plus aucun lment visible ! ee 102
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.3

Le point de dpart : JFrame et une application minimale. e

Figure 9 Une version Swing de lincontournable PRINT "HELLO"

En attendant une meilleure ide 79 on peut vacuer ce probl`me agaant en ajoutant, apr`s la cration e e e c e e du cadre, linstruction cadre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Notez que, contrairement ` ce quon aurait pu penser (et contrairement ` ce qui se passe pour les Frame de a a AWT), un JFrame ne contient pas directement les composants quon souhaite voir dans le cadre. Un JFrame est un objet complexe dont un lment, le panneau de contenu (content pane) est le conteneur auquel il faut ee ajouter des composants. Sur la gure 9, le panneau de contenu est le rectangle blanc contenant le texte Bonjour ` tous ! . On acc`de au panneau de contenu dun objet JFrame par lexpression getContentPane() 80 . a e En ralit, le programme prcdent nest pas tout ` fait minimal. Si on se contentait dun cadre vide on e e e e a pourrait faire encore plus simple en supprimant les trois lignes ` partir de JLabel etiquette = ... . Mais a les trois instructions restant alors sont obligatoires : appel de new JFrame(...) pour crer lobjet JFrame. e Si on tait, comme cest souvent le cas, en train de dnir une sous-classe de JFrame, lappel du e e constructeur de JFrame serait cach dans une instruction super(...) implicite ou explicite, e appel de setSize(...) pour donner une taille au cadre, sinon il sera rduit ` quelques pixels. e a A la place de setSize(...) on peut appeler la mthode pack(), qui donne au cadre une taille juste e susante pour contenir les composantes qui lui sont ajouts, mais il faut alors que ces composants e aient une taille minimum signicative ; de plus, il faut appeler pack apr`s avoir ajout ces composants, e e appel de setVisible() pour faire appara le cadre parmi les autres lments graphiques visibles ` tre ee a lcran et pour initier le thread charg de dtecter et traiter les actions de lutilisateur sur le cadre. e e e En pratique les cadres des applications sont destins ` tre fortement personnaliss, en recevant des e a e e composants divers et nombreux. Cest pourquoi il est plus commode de dnir une sous-classe plutt quune e o instance de JFrame. Voici une nouvelle version du programme prcdent, plus en accord avec ce qui se fait e e 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 ` tous!", JLabel.CENTER); a getContentPane().add(etiquette); getContentPane().setBackground(Color.WHITE); setSize(250, 100); setVisible(true); } public static void main(String[] args) { JFrame cadre = new Bonjour(); } }
79. Une meilleure ide serait un de ces dialogues qui sinstaurent dans beaucoup dapplications lorsque lutilisateur manifeste e des envies de dpart, genre Attention, votre travail nest pas enregistr, vous voulez vraiment quitter lapplication ? . e e 80. Cette complication dans lajout des composants aux cadres de Swing a disparu dans la version 5 du JDK, car la mthode e add de JFrame y a t surcharge an quon puisse crire unCadre.add(unComposant). e e e e

c H. Garreta, 2000-2010

103

11.4

Le thread de gestion des vnements e e

11

INTERFACES GRAPHIQUES

Note. Puisquelle nest plus mentionne par la suite, la variable locale cadre est tout ` fait superue. e a La mthode prcdente peut aussi bien scrire : e e e e public static void main(String[] args) { new Bonjour(); }

11.4

Le thread de gestion des vnements e e

On peut tre surpris par le programme prcdent : le thread 81 principal de lapplication celui qui se e e e cre quand on lance le programme, et dont la tche est dappeler la mthode main excute une unique e a e e instruction, la cration dune instance de Bonjour, puis se termine. e Lexcution de ce programme ne devrait donc durer quun instant. Pourtant, lexprience montre quune e e interface graphique est mise en place et reste apr`s la terminaison du thread principal. e Cest donc quun deuxi`me thread a t cr et se charge de faire vivre linterface graphique, ce qui e e e ee veut dire dtecter les actions de lutilisateur, notamment ` laide de la souris, et ragir en consquence, par e a e e exemple en modiant laspect de linterface. Tant que ce deuxi`me thread ne sera pas termin, linterface e e graphique existera. Ce thread est appel thread de traitement des vnements (event-dispatching thread). Il faut surtout e e e savoir deux choses ` son sujet : ` quel moment il est cr et quil est le seul habilit ` modier linterface a a ee ea graphique. Creation. Le thread de traitement des vnements est cr lorsque linterface graphique est ralise, e e ee e e cest-`-dire eectivement ache ou prte ` ltre : a e e a e un composant de haut niveau (JFrame, JDialog ou JApplet) est ralis lors de lappel dune de ses e e mthodes setVisible(true), show() ou pack(), e la ralisation dun composant de haut niveau produit la ralisation de tous les composants quil contient e e a ` ce moment-l`, a lajout dun composant ` un conteneur dj` ralis entra la ralisation du composant ajout. a ea e e ne e e ` ` Acces concurrents a linterface. Le thread de traitement des vnements est le seul habilit ` moe e ea dier linterface. Imaginez une application dans laquelle le thread principal ne se termine pas immdiatement e apr`s avoir ralis le cadre de lapplication ; ce serait une mauvaise ide que de faire que ce thread, ou un e e e e autre cr par la suite, ajoute ou modie ultrieurement des composants de linterface car plusieurs thread ee e feraient alors des acc`s concurrents aux mmes objets. Il pourrait en rsulter diverses sortes de situations e e e derreur et de blocage. La r`gle, appele r`gle du thread unique , est la suivante : e e e Lorsquun composant Swing a t ralis, tout code qui peut aecter ltat de ce composant ou ee e e e en dpendre doit tre excut dans le thread de traitement des vnements. e e e e e e Quun code soit excut dans le thread de traitement des vnements signie en pratique quil est e e e e crit dans un gestionnaire dvnements (i.e. une mthode dun EventListener, destine ` tre appele par e e e e e ae e Java en raction ` la survenue de lvnement) ou dans une mthode appele par un tel gestionnaire. e a e e e e Il y a des exceptions ` cette r`gle, cest-`-dire des oprations sur des composants de linterface qui peuvent a e a e tre appeles sans danger depuis nimporte quel thread. Elles sont toujours signales dans la documentation e e e par le texte This method is thread safe, although most Swing methods are not. Par exemple, les zones de texte JTextArea poss`dent des mthodes setText(String t) et append(String e e t) permettant de remplacer ou dallonger le texte ach dans la zone de texte. Ces oprations sont thread e e safe, car le contraire serait tr`s malcommode. e Dautres oprations thread safe bien connues sont les mthodes repaint(...), revalidate(...), etc. e e de la classe JComponent. Ces mthodes sont censes mettre ` jour lachage des composants, mais en ralit e e a e e elles ne font que poster des requtes dans la le dattente des vnements (cest le thread de traitement e e e des vnements qui les en extraira). e e A retenir. Consquence pratique de la r`gle du thread unique : lappel de setVisible(true) ou de e e show() doit tre la derni`re instruction du processus de construction dun cadre ou dune bo de dialogue. e e te
81. Un thread (cf. 10, page 93), on dit aussi l dexcution ou processus lger, est lentit constitue par un programme en e e e e cours dexcution. Les lments principaux de cette entit sont le code qui sexcute et les donnes que ce code manipule. e ee e e e Le langage Java est multithread : le lancement dune application cre un thread principal, dont le code est dtermin par e e e la mthode main, mais ce thread peut en crer un ou plusieurs autres, qui sexcuteront en parall`le (paralllisme vrai si votre e e e e e machine comporte plusieurs processeurs, paralllisme simul si elle nen comporte quun). e e On dit que les thread sont des processus lgers surtout pour indiquer quils partagent les donnes : lorsquun thread est e e cr il acc`de a toutes les variables du thread qui la cr. ee e ` ee

104

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

e 11.5 Evnements

Sil y a un appel de pack() alors celui-ci doit se trouver immdiatement avant 82 setVisible(true) ou e show(). La plus petite application avec interface graphique revisite e Respecter la r`gle du thread unique (ci-dessus) nest pas toujours commode, ni mme possible. Il existe e e des composants complexes dont la mise en place requiert quon agisse sur eux apr`s quils ont t raliss et e ee e e rendus visibles, ce qui introduit la possibilit dinter-blocages. e Une mani`re videmment correcte de rsoudre en bloc tous ces probl`mes consiste ` excuter toutes e e e e a e les oprations concernant linterface graphique dans un seul thread, forcment le thread de gestion des e e vnements. e e Cest pourquoi lquipe de dveloppement de Java promeut dsormais une nouvelle mani`re de crer et e e e e e lancer les interfaces graphiques. Le programme correct montr ` la section 11.3 tait, jusquen dcembre e a e e 2003, la version canonique dune petite application avec interface graphique, mais la forme ocielle dun tel programme est dsormais la suivante : e 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 ` tous!", JLabel.CENTER); a 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 mthode SwingUtilities.invokeLater(obj ) e prend pour argument un objet Runnable (cest-`-dire un objet possdant une mthode run()) et elle produit a e e lappel de obj .run() dans le thread de gestion des vnements 83 . e e Nous obtenons un objet runnable en crant une instance dune classe anonyme dnie comme imple e e mentation de linterface Runnable et ayant une mthode run() qui se rduit ` un appel dune mthode e e a e creerEtMontrerInterface qui, dvidence, remplace ce qui tait prcdemment la mthode main. e e e e e

11.5

e Evnements

Puisquun composant est visible sur un cran, il est naturellement prdestin ` devenir la cible dactions e e ea faites par lutilisateur ` laide de la souris, du clavier ou de tout autre organe de saisie disponible. a Au moment o` elle est dtecte par lordinateur, une action de lutilisateur provoque la cration par la u e e e machine Java dun vnement, un objet quon peut imaginer comme un rapport dcrivant la nature et e e e e e les circonstances de cette action ; on dit que le composant qui en a t la cible est la source 84 de lvnement ee en question. Lorsquun vnement est cr, le composant qui en est la source a la charge de notier ce fait ` tous les e e ee a objets qui ont t enregistr aupr`s de lui comme tant concerns par ce type dvnements et souhaitant ee e e e e e e
82. En thorie, la squence pack(); show(); nest pas en accord avec la r`gle du thread unique, puisque lappel de show e e e est un acc`s, dans le thread principal, ` un composant dj` ralis par lappel de pack. En pratique cela passe, car il y a bien e a ea e e peu de chances quun troisi`me thread fasse des acc`s aux composants dune interface qui na pas encore t rendue visible. e e e e 83. Cela nous concerne peu ici, mais il faut savoir que la mthode invokeLater(obj ) produit lappel de obj .run() uniquement e apr`s que tous les vnements en attente ont t traits (cest l` laspect later de cette mthode). e e e e e e a e 84. Attention, le mot est un peu trompeur : la vraie source de lvnement est lutilisateur (ou sa main qui tient la souris), e e mais cela nintresse notre programme qu` partir du moment o` laction est ressentie par la machine ; ` ce moment, cest bien e a u a la cible de laction de lutilisateur qui devient le point dapparition, ou source, de lvnement. e e

c H. Garreta, 2000-2010

105

11.5

e Evnements

11

INTERFACES GRAPHIQUES

donc tre prvenus lorsquils se produiraient. Bien entendu, notier un vnement cest appeler une e e e e certaine mthode, spcique de lvnement. e e e e Les objets qui demandent ` recevoir les notications des vnements dun certain type doivent donc a e e possder les mthodes correspondantes ; on garantit cela en imposant que ces objets soient des imple e e mentations dinterfaces ad hoc, nommes XxxListener , o` Xxx caractrise le type dvnement considr : e u e e e ee MouseListener, WindowListener, ActionListener, etc. En rsum : pour quun objet puisse recevoir les notications dune catgorie Xxx dvnements il faut e e e e e que sa classe implmente linterface XxxListener ; cet objet peut alors tre enregistr aupr`s dune source e e e e dvnements Xxx en tant quauditeur (listener ) des vnements Xxx. e e e e Par consquent, si un objet est source dvnements Xxx alors il doit possder la mthode addXxxListee e e e e ner 85 grce ` laquelle dautres objets lui sont enregistrs en qualit dauditeurs de ces vnements. a a e e e e 11.5.1 Exemple : dtecter les clics de la souris. e

Donnons-nous le probl`me suivant : dtecter les clics de la souris au-dessus dun panneau et en acher e e les coordonnes. e

Figure 10 Dtecter les clics e La gure 10 montre notre application et ltat de la console do` on la lance, apr`s quon a cliqu pr`s e u e e e e des quatre coins du panneau. Voici une premi`re version de ce programme (des explications sont donnes e e apr`s le listing) : e 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(); } }
85. On peut en dduire un moyen de dcouvrir lensemble des vnements dont un composant peut tre la source : chercher, e e e e e dans la documentation de sa classe, les mthodes nommes addXxxListener. e e

106

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

e 11.5 Evnements

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 prcdent met en vidence les trois lments cls dans tout processus dexploitation dactions de e e e ee e lutilisateur : les vnements quil faut dtecter et traiter ; ici, il sagit des instances de la classe MouseEvent. Notez e e e que le programme ne montre pas la cration de ces objets, pas plus que lappel des mthodes pour les e e exploiter, cela est laaire de mthodes (hrites de la classe Component) qui ne sont appeles que par e e e e la machine Java ; la source de ces vnements, une instance indirecte de la classe java.awt.Component. Ici, la source e e des vnements est lobje JPanel qui est la valeur de la variable panneau ; e e le gestionnaire de ces vnements, un auditeur dment enregistr aupr`s de la source. Ici, cet auditeur e e u e e est une instance, nomme felix, de notre classe GuetteurSouris. e On constate donc que lexpression panneau.addMouseListener(felix) joue un rle central dans cette aaire : elle indique que panneau est considr ici comme une source dvo ee e e nements souris 86 et que ces vnements, lorsquils surviennent, doivent tre notis ` lobjet felix. e e e e a Les quatre mthodes vides de la classe GuetteSouris peuvent surprendre. Il faut comprendre quelles e dcoulent de contraintes successives : e dune part, pour pouvoir tre enregistr comme auditeur dvnements souris, un objet doit appartenir e e e e a ` une classe qui implmente linterface MouseListener, cela est impos par la dclaration de la mthode e e e e addMouseListener, dautre part, linterface MouseListener se compose de cinq mthodes (abstraites), correspondant aux e cinq vnements quon peut dclencher avec une souris. e e e Note 1. Puisque la classe GuetteSouris nest utilise que dans des mthodes de la classe Cadree e AvecPanneauSensible, on aurait pu dclarer la premi`re ` lintrieur de la deuxi`me. De cette mani`re, e e a e e e GuetteSouris serait devenue un classe interne (cf. section 6.6) ` la classe CadreAvecPanneauSensible. a Note 2. Rien noblige ` ce que le rle dauditeur dune sorte dvnements soit tenu par des objets dune a o e e classe spciquement dnie ` cet eet. Nimporte quel objet peut tenir ce rle y compris celui qui est e e a o la source des vnements en question ` la condition quon en ait fait une implmentation de linterface e e a e XxxListener correspondante. Par exemple, voici une autre criture de notre exemple, dans laquelle cest le e cadre qui exploite les vnements souris : e e 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);
86. Entendons-nous bien : un JPanel est toujours une source dvnements souris. Mais ces vnements ne sont exploits par e e e e e lapplication que si un ou plusieurs auditeurs ont t enregistrs. e e e

c H. Garreta, 2000-2010

107

11.5

e Evnements

11

INTERFACES GRAPHIQUES

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 crit limplmentation dune interface Xxx Listener il est regrettable de devoir e e crire toutes les mthodes de linterface alors que seul un petit nombre dvnements possibles, voire un seul, e e e e nous intresse. e Les adaptateurs sont des implmentations toutes prtes des interfaces dauditeurs dvnements, enti`ree e e e e ment faites de mthodes vides. Chaque interface 87 Xxx Listener poss`de une classe Xxx Adapter correspone e dante. Pour crire le traitement des vnements qui nous intressent il sut alors de dnir une sous classe e e e e e de ladaptateur concern, dans laquelle seules les mthodes pertinentes sont dnies. e e e Par exemple, voici notre programme prcdent premi`re version repris dans cet esprit : e e e 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(); } }

87. Sauf les interfaces constitues dune seule mthode, comme ActionListener, pour lesquelles un adaptateur naurait aucun e e intrt. e e

108

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

e 11.5 Evnements

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 prcdent nous dnissons une e e e sous-classe de MouseAdapter dans le but exclusif den crer une unique instance. Dans un tel cas de gure, e Java permet quon dnisse la sous-classe dans la mme expression qui cre linstance. La sous-classe est e e e alors sans nom, mais cela na pas dimportance puisquon nenvisage pas de lui faire dautres instances. Cela scrit : e 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 critures compactes on peut mme se passer de la variable felix : e e ... panneau.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { System.out.println("Clic en (" + e.getX() + ", " + e.getY() + ")"); } }); ... 11.5.3 Principaux types dvnements e e

Chaque type dvnement correspond ` une interface dauditeurs. Les principales (et les seules en AWT ) e e a sont les suivantes : MouseListener Linterface MouseListener concerne les vnements isols 88 gnrs ` laide de la souris. Il sagit dve e e e ee a e e nements de bas niveau, cest-`-dire des actions avec la souris sur des composants qui ne sont pas quips pour a e e traduire ces gestes lmentaires en informations de plus haut niveau, comme cest le cas pour les boutons, ee les menus, etc. Les mthodes de cette interface sont : e
88. Par vnements isols nous entendons les vnements autres que les trains dvnements que produisent les dplacee e e e e e e e ments de la souris, voyez Mouse motion events, plus loin.

c H. Garreta, 2000-2010

109

11.5

e Evnements

11

INTERFACES GRAPHIQUES

void mousePressed(MouseEvent e) Appele lorsquun bouton de la souris a t press, le pointeur se e ee e trouvant sur le composant dont on guette les vnements. e e void mouseReleased(MouseEvent e) Appele lorsquun bouton de la souris a t relch, alors quil avait e ee a e t press quand le pointeur se trouvait sur le composant dont on guette les vnements. ee e e e void mouseClicked(MouseEvent e) Appele lorsque la souris a t clique (presse puis relche au e ee e e a e mme endroit), le curseur se trouvant sur le composant dont on guette les vnements. De par sa e e e dnition, cet vnement est toujours prcd dun vnement mouseReleased. La rciproque nest e e e e e e e e e pas vraie : un vnement mouseReleased nest suivi dun vnement mouseClicked que si la position e e e e de la souris na pas chang depuis le dernier vnement mousePressed. e e e void mouseEntered(MouseEvent e) Appele lorsque le pointeur de la souris commence ` survoler le e a composant dont on guette les vnements. e e void mouseExited(MouseEvent e) Appele lorsque le pointeur de la souris cesse de survoler le compoe sant dont on guette les vnements. e e Largument de ces mthodes est un objet MouseEvent. Les mthodes les plus intressantes dun tel objet e e e sont : getX(), getY() qui renvoient les coordonnes 89 du pointeur au moment o` lvnement a t noti, e u e e ee e getButton() qui permet de savoir quel bouton a t press. ee 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 dplace (move), lorsquon la fait bouger tout en maintenant un bouton e press on dit quon la tra (drag). Cette interface comporte donc deux mthodes : e ne e void mouseMoved(MouseEvent e) Appele lorsque la souris change de position sans quaucun bouton ne e soit press. e void mouseDragged(MouseEvent e) Appele lorsque la souris change de position avec un de ses boutons e press. e Il faut tre plutt sobre en implmentant les mthodes prcdentes, car elles ont ` traiter des vnements e o e e e e a e e qui arrivent par trains. Selon les performances du syst`me utilis, un grand nombre dappels de ces mthodes e e e est gnr pendant un seul dplacement de la souris. Il faut que la rponse soit courte pour ne pas introduire e ee e e un asynchronisme dsagrable. e e KeyListener Il se produit un vnement clavier chaque fois quune touche est presse ou relche. Tous les composants e e e a e peuvent tre sources de tels vnements, il sut quils aient le focus . Cette interface se compose de trois e e e mthodes : e void keyPressed(KeyEvent e) Appele lorsquune touche a t presse. e ee e void keyReleased(KeyEvent e) Appele lorsquune touche a t relche. e ee a e void keyTyped(KeyEvent e) Appele lorsquun caract`re a t saisi au clavier. e e ee Les vnements keyPressed et keyReleased sont de bas niveau. Chacun correspond ` une touche unique, e e a et fournit un code numrique (le code de touche virtuelle, ou VK code). En particulier, keyPressed est le e seul moyen de dtecter la pression dune touche ne produisant pas de caract`re (comme Shift , Ctrl , e e etc.). Lvnement keyTyped, au contraire, est assez labor, puisquil est capable dagrger plusieurs touches e e e e e presses ensemble pour former un unique caract`re : A majuscule, Control-C, etc. e e Largument de ces mthodes est un objet KeyEvent, dont les mthodes les plus intressantes sont : e e e char getKeyChar() Renvoie le caract`re associ ` lvnement clavier (compte tenu des ventuelles touches e ea e e e de modication) Dans le cas de keyPressed et keyReleased il peut nexister aucun caract`re Unicode e reprsentant la touche concerne, la valeur KeyEvent.CHAR_UNDEFINED est alors renvoye. e e e int getKeyCode() Dans le cas de keyPressed et keyReleased, renvoie le code de touche virtuelle correspondant ` la touche presse ou relche. Dans le cas de keyTyped, le rsultat est KeyEvent.VK_UNDEFINED. a e a e e Sur beaucoup de syst`mes, si lutilisateur maintient une touche presse, un ot dvnements keyPressed e e e e est gnr. e ee
89. On notera que, dans le cas des vnements MouseExited et, surtout, MouseReleased, ces coordonnes peuvent tre ngae e e e e tives.

110

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

e 11.5 Evnements

FocusListener Les vnements qui nous intressent ici concernent lacquisition ou la perte du focus par un composant. e e e A tout moment, un seul composant a le focus ; par dnition, cest ` lui que sont adresss les vnements du e a e e e clavier. Gnralement, un composant acquiert le focus lorsquil subit un clic de la souris ; le composant qui e e avait le focus ` ce moment-l` le perd. La pression successive de la touche tabulation fait galement circuler a a e le focus parmi les composants placs sur un mme conteneur. e e void focusGained(FocusEvent e) Appele lorsque le composant en question acquiert le focus (cest-`-dire e a que les actions sur le clavier lui seront dsormais adresses). e e void focusLost(FocusEvent e) Appele lorsque le composant perd le focus (un autre composant la pris). e

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 mthode : e void actionPerformed(ActionEvent e) Appele lorsquune action a t faite (ce que action veut dire e ee dpend du composant : presser un bouton, cocher ou dcocher une case ` cocher, faire un choix dans e e a un menu, etc.). Largument de cette mthode est un objet ActionEvent, muni de la mthode e e String getActionCommand() Renvoie une cha qui identie laction en question. En r`gle gnrale, il ne e e e sagit dune cha crite sur le composant sur lequel laction de lutilisateur sest eectue : le titre ne e e dun bouton press ou dune case coche, le texte de llment de liste ou de litem de menu choisi, etc. e e ee

Figure 11 Trois boutons

Exemple : voici la dnition dune classe Panneau tr`s na qui est un conteneur portant trois boutons e e ve (voyez la gure 11) et, en mme temps, lauditrice des actions dont ces boutons sont la source : e 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); }

c H. Garreta, 2000-2010

111

11.5

e Evnements

11

INTERFACES GRAPHIQUES

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`re dcrire une classe fonctionnellement identique ` la prcdente, en utilisant les e e a e e rfrences des boutons plutt que leurs cha ee o nes action command 90 : 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); } }

90. Cette mani`re de faire est plus ecace, puisquon remplace les comparaisons equals par des comparaisons == , e mais cela oblige ` dclarer des collections de variables dinstance. a e

112

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

e 11.5 Evnements

ItemListener Il se produit un vnement ditem lorsquun item est slectionn ou dselectionn. Par item nous e e e e e e entendons ici un lment dune liste droulante, dune liste de choix, une case ` cocher, etc. Une seule ee e a mthode dans cette interface : e void itemStateChanged(ItemEvent e) Appele lorsquun item a t slectionn ou dselectionn. e ee e e e e AdjustmentListener Cette interface concerne les actions faites sur des barres de dlement. Une seule mthode : e e void adjustmentValueChanged(AdjustmentEvent e) Appele lorsque le curseur de la barre de dlement e e a t dplac (quelle quen soit la raison : on a tir le curseur, on a cliqu sur une des `ches de la ee e e e e e barre ou bien on a cliqu sur la barre en dehors du curseur). e En gnral, ` la suite dun tel vnement on interroge la barre de dlement ` laide de la mthode e e a e e e a e getValue de la classe Scrollbar. Dans le cas o` lon dispose de plusieurs barres de dlement on peut u e utiliser la mthode Object getSource() pour identier celle qui est la source de lvnement. e e e Ces vnements ne sont pas dun usage aussi frquent quon pourrait le penser car, dans la plupart des ape e e plications, les barres de dlement des fentres sont gres par la machinerie interne des objets JScrollPane. e e ee TextListener Les vnements de cette interface notient les modications du texte en cours de saisie dans un champ e e ou une zone de texte. Une seule mthode : e void textValueChanged(TextEvent e) Appele lorsque le texte concern a chang. e e e On notera que les champs de texte (JTextField et JPasswordField) produisent galement un vnement e e e action lorsque lutilisateur presse la touche Entre , ce qui est souvent lvnement rellement guett. e e e e e WindowListener Les vnements que cette interface concerne sont les actions sur une fentre : ouverture et fermeture et, e e e dans le cas dun cadre ou dun dialogue, les actions sur les lments de la barre de titre. Ce qui donne les ee mthodes : e void windowClosing(WindowEvent e) Appele lorsque lutilisateur essaye de fermer la fentre en agissant e e sur son menu syst`me ou sa case de fermeture. Dans le cas du cadre principal dune application e cest ici quon doit mettre lventuel code de conrmation avant terminaison, voir lexemple ci-dessous. e void windowActivated(WindowEvent e) Appele lorsque la fentre est rendue active. e e void windowDeactivated(WindowEvent e) Appele lorsquune fentre cesse dtre la fentre active. e e e e void windowClosed(WindowEvent e) Appele lorsque la fentre a t ferme, suite ` un appel de sa me e ee e a e thode dispose. Ne pas confondre cet vnement, qui na de sens que pour une fentre lle (apr`s la e e e e fermeture du cadre principal il ny a plus dapplication) avec lvnement windowClosing. e e void windowOpened(WindowEvent e) Appele lorsquune fentre est rendue visible pour la premi`re fois. e e e void windowIconified(WindowEvent e) Appele lorsquune fentre est minimise (iconie). e e e e void windowDeiconified(WindowEvent e) Appele lorsquune fentre qui avait t minimise (iconie) e e ee e e retrouve une taille normale. 11.5.4 Exemple : fermeture prudente du cadre principal

Voici une illustration classique de la mani`re de dtecter et traiter les vnements Window : demander e e e e a ` lutilisateur une conrmation avant de fermer le cadre principal et mettre n ` lapplication (voyez la a gure 12). Bien sr, dans une vraie application, au lieu des quatre lignes ` partir de JPanel panneau = new u a JPanel(); on verrait lajout au cadre de choses plus intressantes quun simple panneau vide. e Tr`s intressant, cet exemple montre galement lemploi des tr`s utiles bo de question (JOptionPane). e e e e tes

c H. Garreta, 2000-2010

113

11.6

Peindre et repeindre

11

INTERFACES GRAPHIQUES

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 mthode paint e

Les composants graphiques doivent tre peints (sur lcran) : une premi`re fois lors de leur achage e e e initial, ensuite chaque fois quils ont t totalement ou partiellement modis, eacs, agrandis, etc. ee e e Tout composant qui nest pas une fentre est forcment inclus dans un conteneur qui, sil nest pas luie e mme une fentre, doit ` son tour tre inclus dans un autre conteneur, lui-mme peut-tre inclus dans un e e a e e e troisi`me, etc. Cette cha dinclusions se poursuit jusqu` une fentre, le seul conteneur qui nest pas oblig e ne a e e dtre inclus dans un autre. Or, la gestion que fait la machine Java des fentres (en comptition avec les autres e e e 114
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.6

Peindre et repeindre

fentres, Java ou non, visibles ` lcran) lui permet de dtecter des situations comme celle-ci : une fentre qui e a e e e tait totalement ou partiellement masque par une autre, vient dtre dcouverte et, par consquent, tous ou e e e e e certains des composants placs dans cette fentre doivent tre redessins. La machine Java met alors dans e e e e une certaine le dattente de choses ` faire une requte indiquant quil faut repeindre les composants qui a e se trouvent dans la partie endommage, quil faut restaurer 91 . e Aussi longtemps que lapparence standard dun composant vous convient, vous navez pas ` vous proca e cuper de sa peinture : le composant prend soin de lui mme. L` o` cette question devient intressante cest e a u e lorsquon consid`re des composants personnaliss , dont lapparence graphique souhaite nest pas celle e e e que leur classe prvoit par dfaut. Souvent cela veut dire que le composant est un panneau (JPanel) et quon e e doit y montrer un dessin form de tracs lmentaires (segments, arcs, rectangles et ovales pleins, etc.) ou e e ee bien une image obtenue ` partir dun chier dun format reconnu par Java, comme GIF ou JPEG. a Cest la mthode paint qui a la responsabilit de peindre un composant. Tous les composants en ont une e e version, ne serait-ce que celle quils ont hrite de la classe Component. Pour quun composant ait un dessin e e personnalis il faut et il sut de rednir cette mthode dans la classe du composant 92 . e e e La mthode paint nest jamais explicitement appele par le programme ; au lieu de cela, cest la machine e e Java qui se charge de lappeler, chaque fois que lapparence du composant doit tre refaite. Cela arrive e principalement dans trois sortes de situations, dont seule la troisi`me est ` notre porte : e a e le composant doit tre repeint suite ` un vnement extrieur ` notre application, voire mme ` la e a e e e a e a machine Java (exemple : une autre fentre est apparue devant le composant, puis a disparu), e le composant doit tre repeint ` cause dun vnement qui sadresse bien ` linterface graphique de notre e a e e a application mais qui est pris en charge par un lment ou une super-classe du composant (exemple : ee lutilisateur a chang la taille de la fentre, en agissant sur son bord), e e le composant doit tre repeint car les donnes dont il exhibe une reprsentation ont chang (la machine e e e e Java ne peut pas deviner cela, nous sommes les seuls ` le savoir). a Largument de la mthode paint tant un objet de type Graphics, il nous fait pour commencer expliquer e e 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 ncessaires e pour eectuer des oprations graphiques. Les contextes graphiques sont instances de la classe Graphics, ou e dune de ses sous-classes comme Graphics2D. Ltat dun tel objet se manifeste ` travers un ensemble de mthodes get (les mthodes set correspone a e e dantes existent) dont les plus importantes sont : Shape getClip() donne la zone de coupe courante, cest-`-dire la rgion en dehors de laquelle les oprations a e e graphiques sont sans eet, Rectangle getClipRect() donne lenveloppe rectangulaire de la zone de coupe (voir ci-dessus), Color getColor() donne la couleur qui sera employe par les oprations graphiques, aussi bien pour tracer e e des traits que pour remplir des gures ou pour dessiner des textes, Font getFont() donne la police de caract`res employe pour crire des textes, e e e FontMetrics getFontMetrics() un objet FontMetrics qui reprsente un ensemble de mesures ` propos de e a la police de caract`res courante. e Le comportement dun objet Graphics est constitu par ses oprations graphiques. Parmi les princie e pales : void clearRect(int x, int y, int width, int height) eace le rectangle spci en le peignant avec e e 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 plaant ` un endroit dni par dx et dy, c a e Graphics create() cre un contexte graphique qui est un clone de celui sur lequel cette mthode est e e appele, e
91. Ces requtes sont aectes de la priorit la plus basse possible, si bien que la machine ne soccupera de repeindre les e e e composants que lorsque elle naura vraiment rien dautre ` faire ; de plus, Java ne conserve dans la le dattente quun exemplaire a au plus dune telle requte. On vite ainsi les sries de peintures successives que provoquerait la prise en charge prioritaire de e e e ces requtes, entra e nant un travail inutile et des clignotements dsagrables. e e 92. Consquence pratique : si un composant doit avoir un dessin personnalis, alors il devra tre instance dune classe e e e spcialement dnie ` cet eet. e e a

c H. Garreta, 2000-2010

115

11.6

Peindre et repeindre

11

INTERFACES GRAPHIQUES

(x,y) arcAngle startAngle

height

width

Figure 13 Trac dun arc e

void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) trace un arc dellipse mesurant arcAngle degrs et commenant au point dni par startAngle degrs e c e e (lorigine est ` 3 heures ). Cette ellipse est inscrite dans le rectangle de largeur width et de hauteur a height dont le coin suprieur gauche est le point de coordonnes x et y (cf. gure 13). e e boolean drawImage(Image img, int x, int y, ImageObserver observer) dessine limage img en plaant son coin suprieur gauche au point de coordonnes x, y. c e e observer est un objet destinataire des notications sur ltat davancement de limage qui par exemple e dans le cas dimages obtenues sur le web peut se charger tr`s lentement ; si la question est sans intrt e ee (par exemple sil sagit dimages qui narrivent pas par le rseau) on peut mettre ici nimporte quel e 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 suprieur gauche est plac au point de coordonnes x et y. e e e void drawOval(int x, int y, int width, int height) trace le bord dune ellipse dnie par son envee loppe 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 str de telle mani`re que le coin infrieur ne e e gauche de lenveloppe rectangulaire du premier caract`re soit sur le point de coordonnes x et y, e e void fillRect(int x, int y, int width, int height) peint lintrieur dun rectangle (cf. drawRect) e en utilisant la couleur courante, void fillOval(int x, int y, int width, int height) peint lintrieur dune ellipse (cf. drawOval) en e utilisant la couleur courante, 116
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.6

Peindre et repeindre

void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) peint lintrieur dun rectangle aux coins arrondis (cf. drawRoundRect) en utilisant la couleur courante, e void translate(int x, int y) place lorigine des coordonnes sur le point de coordonnes x et y (relatives e e a ` lorigine prcdente). e e A propos de Graphics2D La classe Graphics2D tend la classe Graphics en permettant un contrle beaucoup plus sophistiqu de e o e la gomtrie, les syst`mes de coordonnes, les transformations graphiques, la couleur, laspect des textes, etc. e e e e Il faut savoir que la valeur du param`tre de type Graphics pass ` la mthode paint est en ralit un e ea e e e objet Graphics2D. Lorsque les oprations amliores de la classe Graphics2D sont ncessaires, la mthode e e e e e paint commence donc de la mani`re suivante, qui est donc lgitime : e e public void paint(Graphics g) { super.paint(g); Graphics2D g2d = (Graphics2D) g; ... oprations graphiques mettant en uvre lobjet g2d e (toutes les oprations des classes Graphics et Graphics2D sont donc lgitimes) e e ... } 11.6.3 Exemple : la mauvaise mani`re de dessiner e

Figure 15 Gribouillages...

Donnons-nous le probl`me suivant (voyez la gure 15) : dessiner une ligne polygonale que lutilisateur e dnit en cliquant successivement sur les points quil souhaite placer comme sommets de la construction. e Premi`re version, nous expliquons plus loin en quoi elle nest pas bonne : e 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()); } }); }

c H. Garreta, 2000-2010

117

11.6

Peindre et repeindre

11

INTERFACES GRAPHIQUES

private int xPrec = -1; private int yPrec;

// coordonnes du e // clic prcdent e e

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 : ` partir du second, chaque clic dtect provoque le trac dun a e e e segment joignant le point o` il sest produit au point o` sest produit le clic prcdent. On dessine donc ` u u e e a fonds perdu , ce qui est le dfaut de cette mani`re de faire : si la ligne polygonale est endommage, notre e e e application ne sera pas capable de la redessiner 93 .

11.6.4

Exemple : la bonne mani`re de dessiner. e

On laura compris, la bonne mani`re de dessiner ne consiste pas ` tracer les lments graphiques au fur e a ee et ` mesure que leurs param`tres sont connus, mais au contraire ` mmoriser linformation requise pour tout a e a e (re-)dessiner chaque fois que cela est ncessaire : e

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();

93. Dans certains cas, le syst`me sous-jacent prend sur lui de mmoriser le contenu des fentres an dtre en mesure de les e e e e restaurer lorsquelles auront t partiellement ou totalement masques. Cest gentil mais na car cela ignore le fait que limage e e e f ` montrer nest peut-tre pas la mme que celle qui a t sauvegarde. a e e e e e

118

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.7

Gestionnaires de disposition

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 raction ` un clic de la souris nest plus le dessin dun segment, mais e a uniquement la mmorisation des coordonnes du clic suivie dun appel de la mthode repaint 94 pour e e e indiquer que le dessin du composant nest plus valide (puisque la ligne polygonale poss`de dsormais un e e sommet de plus, que la gure ne montre pas encore). Le dessin eectif est laaire de la mthode paint, dont le programmeur doit crire la dnition mais e e e jamais lappel, car la plupart des appels de cette mthode sont imprvisibles. La cration dun sommet de la e e e ligne polygonale est une exception : repaint ayant t appele, lappel de paint est pour une fois prvisible, ee e e mais les autres situations qui requi`rent le travail de paint (masquage de la fentre, redimensionnement, e e etc.) ne peuvent pas tre explicitement prdites et places parmi les instructions du programme. e e e Note 1. Presque toujours la version rednie de la mthode paint commence, comme ici, par appeler e e la version hrite : e e super.paint(g); Cela est est ncessaire car, sinon, le fond de lcran ne serait pas repeint et de curieux dysfonctionnements e e appara traient. Note 2. La mthode paint est la seule (bonne) mthode pour peindre les composants de AWT. Pour e e les composants de Swing, cependant, la mthode paint consiste en des appels successifs de trois mthodes e e dlgues paintComponent, paintBorder et paintChildren. Cest pourquoi, dans le cas o` notre composant ee e u a un bord et comporte des sous-composants, il vaut souvent mieux rednir la mthode paintComponent au e e lieu de sen prendre ` paint. La dirence nest pas bien grande : a e public class UnAutreGribouillis extends JPanel { ... public void paintComponent(Graphics g) { super.paintComponent(g); ... le reste de la mthode est identique ` paint, ci-dessus e a ... } ... }

11.7

Gestionnaires de disposition

Le placement des composants dans les conteneurs est laaire des gestionnaires de disposition, ou layout managers, qui se chargent :
94. Contrairement ` ce quon pourrait penser, la mthode repaint ne provoque pas un appel immdiat de paint. Au lieu de a e e cela, elle se limite ` mettre dans la le des choses ` faire une requte de peinture, sil ny en avait pas dj` une. Ce nest a a e ea que quand toutes les autres requtes de cette le auront t traites (cest-`-dire quand la machine Java naura rien dautre ` e e e e a a faire) que la mthode paint sera eectivement appele et le composant redessin. e e e

c H. Garreta, 2000-2010

119

11.7

Gestionnaires de disposition

11

INTERFACES GRAPHIQUES

du placement initial des composants, lors des appels de la mthode add, e le cas chant, de donner une taille et une forme ` chaque composant, en fonction de sa taille prfre , e e a eee de son contenu et de sa disposition relativement aux autres composants dans le mme conteneur, e 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, vacuons une question tr`s secondaire : il est possible (mais non recommand) de se e e e passer compl`tement de gestionnaire de disposition. Cela doit tre explicitement demand, par linstruction e e e conteneur .setLayout(null); A la suite de cette commande, chaque composant devra tre explicitement dimensionn et positionn lors de e e e son ajout au conteneur (bonjour les calculs avec des pixels !). Les mthodes pour cela sont e void setLocation(int x, int y), void setLocation(Point p) dnit la position du coin suprieur gauche e e du composant (ou plutt de son enveloppe rectagulaire), relativement ` une origine qui est place au o a e coin suprieur gauche du conteneur, e void setSize(int width, int height), void setSize(Dimension d) dnit les dimensions du compoe sant (ou plutt de son enveloppe rectangulaire), o void setBounds(int x, int y, int width, int height), void setBounds(Rectangle r) remplit simultanment les fonctions de setLocation et celles de setSize. e Lorsque les composants ont t placs manuellement il y a intrt ` interdire les changements de taille et ee e ee a de forme du conteneur. Cela sobtient par lexpression conteneur .setResizable(false); Attention. Certains programmeurs dbutants, rebuts par la dicult quil y a parfois ` obtenir dun e e e a gestionnaire de disposition quil fasse ce quon veut, choisissent de placer manuellement les composants. Lexprience montre que, sauf de rares exceptions, se passer de gestionnaire de disposition nest pas la e mani`re la plus simple de raliser une interface graphique. e e 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 dfaut les composants sont centrs horizontalement et carts entre eux de 5 pixels, mais on peut e e e e changer cela au moment de linstanciation. Par exemple, le panneau de la gure 16 a t construit par la ee squence suivante : e ... 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 dfaut dun JPanel est FlowLayout. e 120
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.7

Gestionnaires de disposition

11.7.2

BorderLayout

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

Figure 17 Un panneau avec un gestionnaire BorderLayout Le nord et le sud, lorsquils sont prsents, prennent toute la largeur du conteneur et ont la plus petite e hauteur qui convient aux composants quils contiennent. Lest et louest, lorsquils sont prsents, prennent e toute la hauteur du conteneur moins les parties ventuellement occupes par le nord et le sud, et ont la largeur e e minimale qui respecte les composants quils contiennent. Enn, le centre prend toute la place restante. Par exemple, le panneau de la gure 17 a t construit par la squence ee e ... 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 dfaut du panneau de contenu dun JFrame ou dun JDialog est e 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 cration du gestionnaire. Toutes les cases de cette e grille ont les mmes dimensions. e

Figure 18 Un panneau avec un gestionnaire GridLayout ` 4 colonnes a Par exemple, le panneau de la gure 18 a t construit par la squence suivante : ee e
c H. Garreta, 2000-2010

121

11.7

Gestionnaires de disposition

11

INTERFACES GRAPHIQUES

... 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 prcdents. Il se base e e sur un quadrillage imaginaire du conteneur tel que lespace occup par chaque composant soit une rgion e e rectangulaire forme par la runion dun certain nombre de cases de ce quadrillage. e e Lors de son ajout au conteneur, chaque composant est associ ` une certaine contrainte qui spcie e a e quelles cases du quadrillage imaginaire le composant occupe et comment il les occupe. Ensemble, toutes ces contraintes dnissent les dimensions des lignes et des colonnes du quadrillage. e Les contraintes sont des instances de la classe GridBagConstraints, dont les principaux champs sont : gridx : numro de la colonne du quadrillage (la premi`re colonne porte le numro 0) o` se place langle e e e u suprieur gauche du composant. e gridy : numro de la ligne du quadrillage (la premi`re ligne porte le numro 0) o` se place langle suprieur e e e u e gauche du composant. gridwidth : nombre de colonnes du quadrillage sur lesquelles le composant stend. e gridheight : nombre de lignes du quadrillage sur lesquelles le composant stend. e weightx : nombre exprimant la largeur de la colonne que le composant occupe ; peu importe lunit, pourvu e que ce soit la mme pour toutes les colonnes. e Mettez 0 si ce composant stend sur plusieurs colonnes ou si la largeur peut se dduire de la contrainte e e dun autre composant de cette colonne. weighty : nombre exprimant la hauteur de la ligne que le composant occupe ; peu importe lunit, pourvu e que ce soit la mme pour toutes les lignes. e Mettez 0 si ce composant stend sur plusieurs lignes ou si la hauteur peut se dduire de la contrainte e e dun autre composant de cette ligne. fill : indication de la mani`re dont le composant doit remplir sa zone. Les valeurs possibles sont : e 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`rement. Les valeurs possibles sont : e GridBagConstraints.NORTH (au nord), GridBagConstraints.NORTHEAST (au nord-est), GridBagConstraints.EAST (` lest), GridBagConstraints.SOUTHEAST (au sud-est), etc. a 11.7.5 Exemple : un panneau muni dun GridBagLayout

A titre dexemple 95 , proposons-nous de construire un panneau contenant les huit composants montrs e sur la gure 19. La gure 20 montre le quadrillage (qui nexiste que dans la tte du programmeur) par rapport auquel e les composants sont placs. Pour chacun on doit construire une contrainte ; cela est rapidement pnible, ` e e a moins de se donner une mthode auxiliaire comme notre mthode ajout : e e import javax.swing.*; import java.awt.*; public class TestGridBagLayout extends JFrame {
95. Cet exemple est dmonstratif mais inutilisable. Dune part, ce nest pas raliste de mettre ce type de composants dans le e e cadre principal dune application ; cet exemple correspond plus ` une bo de dialogue (JDialog) qu` un cadre (JFrame). a te a Dautre part, cet exemple est construit avec des composants anonymes, ce qui rend impossible la rcupration des informae e tions que lutilisateur donne en saisissant des textes dans les champs de texte ou en pressant les boutons.

122

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.7

Gestionnaires de disposition

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);
c H. Garreta, 2000-2010

123

11.8

Composants prdnis e e

11

INTERFACES GRAPHIQUES

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("Indiffrent"), e 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 ` 10 la largeur de chaque colonne et la hauteur de chaque ligne, le e a panneau tout entier ayant une largeur de 30 (cela se dduit des composants Nom, Soleil et OK ) et une e hauteur de 40 (cela dcoule de Nom, Prnom, Soleil et Indirent). Lunit de mesure est sans importance, e e e e 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`re de monter de telles interfaces, plus souple et avec de lexprience e e plus simple, consiste ` imbriquer plusieurs panneaux (objets JPanel) les uns dans les autres, chacun muni a dun gestionnaire adquat. e A ce propos on consultera avec prot lexemple montr ` la section 11.8.2, Construire une bo de e a te dialogue. 11.7.7 Bordures

Il est possible de crer une bordure autour dun composant. La mani`re la plus simple est de la faire e e fabriquer par lusine de bordures (BorderFactory) selon le schma : e unComposant.setBorder(BorderFactory.createXxx Border(param`tres de la bordure)) e Ci-dessus, Xxx reprsente des mots qui identient le type de bordure souhait. La gure 21 montre e e diverses sortes de bordures, et le jargon avec lequel elles sont nommes dans la classe BorderFactory. e

11.8

Composants prdnis e e

Nous ne ferons pas ici une prsentation systmatique des direntes, et nombreuses, classes de compoe e e sants disponibles dans AWT et Swing. Cela est tr`s bien fait dans le tutoriel Java (http://java.sun.com/ e 124
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.8

Composants prdnis e e

Figure 21 Des bordures, sans et avec titres

tutorial/). En particulier, ` la section A Visual Index to the Swing Components (leon Using Swing Coma c ponents de la squence Creating a GUI with JFC/Swing) on trouve une prsentation extrmement parlante e e e de tous les composants disponibles. Au lieu de cela nous allons montrer le mode demploi de certains des composants les plus utiliss, ` travers e a une application tr`s na grant le carnet dadresses dun club sportif. e ve e

Figure 22 Cadre avec menus

11.8.1

Exemple : mise en place et emploi de menus

La premi`re version de notre programme illustre la mise en place des menus, voyez la gure 22. Les e actions sur les menus sont dtectes, mais les ractions en sont, pour le moment, des appels de mthodes e e e e 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);
c H. Garreta, 2000-2010

125

11.8

Composants prdnis e e

11

INTERFACES GRAPHIQUES

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("Crer..."); e 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) {

126

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.8

Composants prdnis e e

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 ragir aux actions faites sur les menus nous avons choisi de donner un auditeur distinct ` e a chaque item de menu. Une autre solution aurait consist ` donner le mme auditeur ` tous les item. Cela ea e a nous aurait oblig ` crire une mthode actionPerformed ressemblant ` ceci 96 : eae e a ... 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("Crer...")) e 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 dveloppement dune interface-utilisateur graphique. e En Java la chose est rendue encore plus pnible par la prsence des gestionnaires de disposition qui, tout en e e tant tr`s utiles pour grer les changements de taille et de forme des conteneurs, manifestent souvent une e e e grande rticence ` placer les composants selon la volont du programmeur. e a e Pour illustrer cette question nous allons ajouter ` notre application une bo de dialogue pour saisir a te les informations qui caractrisent un membre du club. Pour commencer, nous ne nous occupons ici que e dassembler les composants, nous verrons ` la section suivante comment utiliser la bo pour acqurir des a te e informations.
96. Cette mani`re de dtecter les actions sur les menus est certainement moins ecace que la prcdente. Mais lecacit e e e e e a-t-elle une quelconque importance, quand il sagit de ragir ` des gestes de lutilisateur ? e a

c H. Garreta, 2000-2010

127

11.8

Composants prdnis e e

11

INTERFACES GRAPHIQUES

Figure 23 Bo de dialogue de saisie te

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

panneauHaut panneauBis panneauTer panneauBas

panneauGauche

panneauDroite

Figure 24 Imbrication de panneaux pour raliser la boite de dialogue de la gure 23 e 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;

128

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.8

Composants prdnis e e

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("Prnom")); e 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 montrs dans les sections suivantes e ... } Le constructeur de BoiteDialogueMembre ne se termine pas par le couple pack(); setVisible(true); habituel. Ces oprations sont ` la charge de celui qui cre une bo de dialogue, on verra pourquoi. e a e te
c H. Garreta, 2000-2010

129

11.8

Composants prdnis e e

11

INTERFACES GRAPHIQUES

Le troisi`me argument, true, de lappel du constructeur de JDialog e super(cadre, "Saisie dun membre", true); fait que la bo de dialogue est modale : aussi longtemps quelle est visible ` lcran, lutilisateur ne peut te a e pas agir sur une autre partie de linterface graphique de lapplication. Linterface Sports, mentionne prcdemment, sert juste ` mettre en place un ensemble de constantes 97 e e e a communes ` plusieurs classes : a 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", "Athltisme", e "Randonne", "Foot", "Basket", "Volley", "Ptanque" }; e e long[] valSport = { TENNIS, SQUASH, NATATION, ATHLETISME, RANDONNEE, FOOT, BASKET, VOLLEY, PETANQUE }; } 11.8.3 Exemple : saisie de donnes e

Dans la bo de dialogue que nous dveloppons ici les seuls composants dont les vnements sont dtects te e e e e e et traits sont les deux boutons OK et Annuler 98 . La pression du bouton OK dclenche la validation des e e informations portes par les champs de la bo de dialogue et, en cas de succ`s, la fermeture de cette bo ; e te e 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", "Donne manquante", JOptionPane.ERROR_MESSAGE); e else if (champPrenom.getText().length() == 0) JOptionPane.showMessageDialog(this, "Le champ prnom est vide", e "Donne manquante", JOptionPane.ERROR_MESSAGE); e else if ( ! sexeMasculin.isSelected() && ! sexeFeminin.isSelected()) JOptionPane.showMessageDialog(this, "Le sexe nest pas indiqu", e "Donne manquante", JOptionPane.ERROR_MESSAGE); e else if (zoneAdresse.getText().length() == 0) JOptionPane.showMessageDialog(this, "Ladresse nest pas indique", e "Donne manquante", JOptionPane.ERROR_MESSAGE); e
97. Ne pas oublier que toutes les variables dune interface sont, par dnition, statiques et nales (i.e. des constantes de e classe). 98. Nous lavons dj` dit, nous dveloppons ici un exemple na Dans une application plus srieuse nous pourrions dtecter ea e f. e e les frappes au clavier an de vrier les ventuelles contraintes sur les textes taps. e e e

130

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.8

Composants prdnis e e

else return true; return false; } } La validation des donnes faite ici est sommaire : nous nous contentons de vrier que tous les champs e e ont t renseigns. Dans les cas rels il y a souvent ` faire des validations plus nes. ee e e a Il est important de bien comprendre le fonctionnement de la mthode finDuDialogue. Lorsque lutilisae teur presse le bouton Annuler, ou bien lorsquil presse le bouton OK et que les donnes sont trouves valides, e e alors lappel de dispose() dtruit lobjet graphique correspondant ` la bo de dialogue (i.e. tout ce qui se e a te voit ` lcran), mais lobjet Java (i.e. linstance de la classe BoiteDialogueMembre) nest pas encore dtruit a e e car, comme nous allons le voir, il est la valeur dune certaine variable (la variable locale dial de la mthode e creerMembre de la classe ClubSportif). Notez que si lutilisateur appuie sur le bouton OK et que les donnes ne sont pas valides alors il ne se e passe rien : la mthode finDuDialogue retourne sans voir appel dispose, donc la bo de dialogue est e e te toujours visible. Il faut voir enn que, la bo tant modale, cest lappel de dispose fait dans finDuDialogue qui met n te e au blocage de lapplication qui tait en place depuis lappel de setVisible(true) fait par le constructeur e de BoiteDialogueMembre. Voyons maintenant comment les instances de BoiteDialogueMembre rendent service ` la classe ClubSportif, a 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 lments sont des objets Membre e e ... 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.sportsPratiqus = 0; e for (int i = 0; i < valSport.length; i++) if (dial.casesSports[i].isSelected()) unMembre.sportsPratiqus |= valSport[i]; e membres.add(unMembre); } } ... } La mthode creerMembre mrite une explication. Elle commence par la dclaration dune variable locale e e e dial et la construction dun objet BoiteDialogueMembre ; ensuite, elle appelle les mthodes pack() et e setVisible(true). Or, on va attendre tr`s longtemps le retour de ce dernier appel, car la bo de dialogue e te tant modale, cette expression qui a pour eet de la rendre visible a galement pour eet de bloquer le thread e e dans lequel la mthode creerMembre tait en train de sexcuter. Ainsi, le contrle natteindra le point e e e o que lorsque la mthode dispose de la bo de dialogue aura t appele nous avons vu plus haut dans e te ee e quelles conditions cela se produit.
c H. Garreta, 2000-2010

131

11.8

Composants prdnis e e

11

INTERFACES GRAPHIQUES

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, ` la n de la mthode creerMembre, la variable dial sera a e dtruite) et il ny a aucune dicult ` rcuprer les valeurs de ses membres. e ea e e Notons au passage lendroit, signal par le rep`re , o` il faut donner aux champs de texte et aux cases e e u a ` cocher des valeurs initiales lorsque la saisie ne doit pas se faire ` partir de zro, par exemple dans le cas a e de la modication dun membre (voyez la section 11.8.6). Est apparue galement dans notre application une petite classe auxiliaire nomme Membre 99 . Le rle de e e o cette classe est vident : mmoriser les informations qui caractrisent un membre de notre club. Notez que, e e e comme la mthode creerMembre le montre, les sports pratiqus sont stocks chacun sur un bit de lentier e e e long sportsPratiqus (cela limite ` 64 le nombre de sports possibles, on peut penser que cest susant...) : e a public class String String boolean String long } 11.8.4 Membre implements Serializable { nom; prenom; sexeMasculin; adresse; sportsPratiqus; e

Exemple : choisir un chier

Figure 25 Boite de dialogue denregistrement de chier

Pour montrer dautres bo tes de dialogue, en particulier les bo tes prtes ` lemploi oertes par Swing e a pour choisir un chier (voir la gure 25), nous allons ajouter ` notre application la possibilit de sauver et a e restaurer les membres du club dans un chier. Cest pour avoir le droit den crire les instances dans un chier (on dit plutt srialiser ) que nous avons e o e dclar que la classe Membre implmente linterface java.io.Serializable. Il sagit dune interface vide, qui e e e nentra donc aucune obligation sur la classe qui limplmente ; lnonc implements Serializable ne e e e sert uniquement ` indiquer que le programmeur donne le feu vert ` la srialisation des instances de la classe. a a e Pour obtenir les fonctionnalits indiques il nous sut dcrire les deux mthodes enregistrerFichier e e e e et ouvrirFichier :
99. Une fois de plus, ne pas oublier que nous dveloppons un exemple na dans lequel seule linterface utilisateur nous e f, intresse. Dans un cas rel, la classe Membre serait bien plus complexe et comporterait probablement des mthodes pour garantir e e e la cohrence de linformation. e

132

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.8

Composants prdnis e e

public class ClubSportif extends JFrame implements Sports { ... private void enregistrerFichier() { JFileChooser dial = new JFileChooser(); dial.setDialogTitle("Enregistrer les membres"); dautres personnalisations de la bo de dialogue pourraient appara ici te tre 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`me fichier", JOptionPane.ERROR_MESSAGE); e } } private void ouvrirFichier() { JFileChooser dial = new JFileChooser(); dial.setDialogTitle("Restaurer les membres"); dautres personnalisations de la bo de dialogue pourraient appara ici te tre 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`me fichier", JOptionPane.ERROR_MESSAGE); e } } ... } 11.8.5 Exemple : une table pour acher des donnes e

Figure 26 Le tableau des membres du club

c H. Garreta, 2000-2010

133

11.8

Composants prdnis e e

11

INTERFACES GRAPHIQUES

Pour en nir avec notre exemple nous allons lui ajouter une table achant la liste des membres du club avec certaines informations associes, comme montr sur la gure 26. e e Une table (classe JTable) est un composant relativement complexe obissant au mod`le de conception e e MVC dont le principe est de diviser le travail entre deux ojets : le mod`le et la vue. Le premier dtient les e e donnes, la seconde en fait une prsentation graphique. Le modele MVC est comment avec plus de soin ` e e e a section 11.9. Ici cest surtout sur le mod`le que nous allons travailler ; la vue sera un objet JTable dont le comportement e par dfaut nous sura enti`rement. e e Les devoirs dun mod`le de table sont dnis par linterface TableModel, dont une implmentation pare e e tielle tr`s utile est AbstractTableModel. Do` notre classe ModeleTableClub : e u 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.sportsPratiqus & valSport[j - 3]) != 0); e } } Dans la classe ModeleTableClub nous [re-]dnissons celles des mthodes imposes par linterface TableModel e e e que la classe abstraite AbstractTableModel ne dnit pas ou ne dnit pas comme il nous faut. e e 134
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.8

Composants prdnis e e

Les mthodes prcdentes sont assez faciles ` comprendre : e e e a ModeleTableClub : le constructeur sert ` mmoriser une rfrence sur le vecteur de membres que le tableau a e ee est cens reprsenter ; e e getRowCount : le nombre de lignes du tableau nest autre que le nombre de membres du club ; getColumnCount : le nombre de colonnes du tableau dpend que des champs que nous avons dcid de e e e reprsenter (ici, le nom, le prnom, le sexe et les sports pratiqus) ; e e e getColumnName : donne le nom de chaque colonne, cest-`-dire ce quil faut acher dans la premi`re ligne ; a e getColumnClass : donne le type des informations de chaque colonne (suppose homog`ne), cela permet den e e donner une prsentation adapte comme, pour un boolen, une case ` cocher ; e e e a getValueAt : cette mthode est la plus importante : getValueAt(i, j) renvoie llment qui se trouve ` la e ee a ligne i et la colonne j du tableau. En plus de lajout de la classe prcdente, nous devons modier notre programme ` plusieurs endroits : e e a 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() { prcdent contenu du constructeur e e 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 rpercutent dans e le mod`le. Deux mani`res de faire cela : pour de petits changement, comme lajout dun unique membre, il e e sut de le notier au mod`le. Par exemple, la mthode creerMembre se terminera maintenant ainsi : e e ... membres.add(unMembre); modeleTable.fireTableRowsInserted(membres.size() - 1, membres.size() - 1); Pour de plus grands changements, comme lors du chargement dun chier, on peut carrment remplacer e le mod`le par un mod`le neuf. Ainsi, dans la mthode ouvrirFichier on trouvera maintenant e e e ... membres = (Vector) ois.readObject(); modeleTable = new ModeleTableClub(membres); table.setModel(modeleTable); // // // // ce vecteur contient les membres du club ses lments sont des objets Membre e e le "mod`le" de la table e la "vue" de la table

11.8.6

Exemple : slection et modication dans une table e

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

135

11.9

Le mod`le MVC (Mod`le-Vue-Controleur) e e

11

INTERFACES GRAPHIQUES

private void modifierMembre() { int rang = table.getSelectedRow(); if (rang < 0) { JOptionPane.showMessageDialog(this, "Il faut dabord slectionner un membre", e "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.sportsPratiqus & valSport[i]) != 0; e 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.sportsPratiqus = 0; e for (int i = 0; i < valSport.length; i++) if (dial.casesSports[i].isSelected()) unMembre.sportsPratiqus |= valSport[i]; e modeleTable.fireTableRowsUpdated(rang, rang); } }

11.9

Le mod`le MVC (Mod`le-Vue-Controleur) e e

Le mod`le MVC est un mod`le de conception, ou design pattern, qui consiste ` maintenir une sparation e e a e nette entre les donnes manipules par lapplication (le mod`le), les prsentations qui en sont faites (les vues) e e e e et les dispositifs par lesquels les actions de lutilisateur sont dtectes (les contrleurs). e e o Puisque lutilisateur a une tendance naturelle ` agir sur les composants quil voit, les vues sont le plus a souvent associes ` des contrleurs. Laspect le plus intressant de cette mthodologie est la sparation de la e a o e e e vue et du mod`le, qui garantit que le codage interne et le traitement des donnes ne sont pas pollus par des e e e questions de prsentation ; cela permet, par exemple, que des prsentations direntes dun mme mod`le e e e e e (textuelle, graphique, sonore, etc.) soient donnes, conscutivement ou simultanment. e e e Bien entendu, sparation nest pas totale indpendance : chaque changement du mod`le doit tre noti e e e e e a ` la vue an que celle-ci puisse tre mise ` jour et re`te constamment ltat actuel du mod`le. e a e e e Les composants de Swing saccordent au mod`le MVC : chaque composant est considr comme une vue e ee (ou plutt comme un couple vue-contrleur), et il doit tre associ ` un mod`le qui joue le rle de source o o e ea e o des donnes pour le composant. e Les mthodes quun objet doit possder pour tre le mod`le dun composant sont dnies par une interface e e e e e associe ` ce composant : ButtonModel, ListModel, TableModel, TreeModel, etc. e a Pour les composants les plus lmentaires, ces mod`les sont tr`s simples. Le programmeur peut presque ee e e toujours ignorer cette question, car il a la possibilit dutiliser, souvent sans le savoir, des mod`les par dfaut. e e e Par exemple, cest un tel mod`le qui est mis en place lorsquon cre un bouton par une instruction simple, e e comme new JButton("Oui") . La section suivante dveloppe un exemple avec un composant bien plus complexe, nomm JTree, dans e e lequel lexistence du mod`le et sa sparation davec la vue ne peut tre ignore. e e e e 136
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.9

Le mod`le MVC (Mod`le-Vue-Controleur) e e

11.9.1

Exemple : les vues arborescentes (JTree)

Figure 27 Reprsentation arborescente (JTree) dun ensemble de mots e

Donnons-nous le probl`me suivant (cf. gure 27) : acher larborescence de tous les mots dau plus e quatre lettres forms avec les trois lettres a, b et c 100 . Nous allons le traiter de quatre mani`res direntes, e e e correspondant aux divers choix que nous pouvons faire pour le mod`le (la structure darbre sous-jacente ` e a la vue JTree) et pour les nuds dont cet arbre se compose : Souvent on na aucun prrequis ` propos des nuds implmentant larbre, lesquels nont pas besoin e a e dtre tr`s sophistiqus. On peut alors utiliser des objets de la classe prdnie DefaultMutableTreeNode e e e e e pour les nuds et un objet DefaultTreeModel pour le mod`le. Ci-apr`s, cest la version 3, celle o` on e e u travaille le moins. Parfois on a dj` une dnition de la classe des nuds, dcoulant dautres parties de lapplication, ea e e mais on peut laugmenter et notamment lui ajouter ce qui lui manque pour tre une implmentation e e de linterface TreeNode. Il nous sut alors de prendre pour mod`le un objet DefaultTreeModel, associ e e a ` de tels nuds enrichis. Cest notre version 1 ci-apr`s. e Il peut arriver quon nous impose par ailleurs une dnition prcise de la classe des nuds, ` laquelle e e a on nous interdit dajouter quoi que ce soit. On doit alors dnir notre propre classe du mod`le, ime e plmentant linterface TreeModel, sachant manipuler ces nuds spciques. Nous avons fait cela ` la e e a version 2. Enn, lorsquon dcide comme dans la situation prcdente de dnir notre propre classe du mod`le, e e e e e il peut arriver que cette classe puisse tre purement calculatoire , cest-`-dire quelle ne repose sur e a aucune structure de donnes sous-jacente. Cest le cas de notre version 4. e Construction dune structure de donnees sous-jacente. Pour commencer, supposons que les nuds de larborescence nous soient imposs par ailleurs : ce sont les instances dune certaine classe Arbuste. e Chacun comporte une cha de caract`res, un vecteur mmorisant lensemble des ls et une rfrence sur ne e e ee le pere :

100. Oui, bon, daccord, ce nest pas tr`s utile. Mais cest un exemple, non ? e

c H. Garreta, 2000-2010

137

11.9

Le mod`le MVC (Mod`le-Vue-Controleur) e e

11

INTERFACES GRAPHIQUES

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 formes avec les m lettres a, b, c... e public class Essai { public static Arbuste creerMots(String debut, int large, int profond) { Arbuste res = new Arbuste(debut); if (profond > 0) for (int i = 0; i < large; i++) res.ajouterFils(creerMots(debut + (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) lachage produit par ce programme : e 138
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.9

Le mod`le MVC (Mod`le-Vue-Controleur) e e

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 crer un composant e JTree. Un tel composant constitue une vue ; pour le crer il faut lui associer un mod`le, qui doit tre une e e e implmentation de linterface TreeModel. Or il existe une implmentation de TreeModel toute prte : la classe e e e DefaultTreeModel, qui na besoin pour fonctionner que dune arborescence faite de nuds implmentant e linterface TreeNode. Notre premi`re approche consiste donc ` faire en sorte que nos objets Arbuste implmentent linterface e a e TreeNode. Pour cela il nous faut ajouter ` notre classe Arbuste les mthodes de linterface TreeNode (notez a e que certaines sont de simples renommages des mthodes qui existent dj` dans notre classe) : e ea import java.util.*; import javax.swing.tree.*; public class Arbuste implements TreeNode { ici apparaissent les membres de la version prcdente de Arbuste, e e auxquels il faut ajouter les mthodes imposes suivantes : e e 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 reprsent ` la gure 27 : e ea import javax.swing.*; import javax.swing.tree.*; public class Essai { public static Arbuste creerMots(String debut, int large, int profond) { Arbuste res = new Arbuste(debut); if (profond > 0) for (int i = 0; i < large; i++) res.ajouterFils(creerMots(debut + (char)(a + i), large, profond - 1)); return res; }
c H. Garreta, 2000-2010

139

11.9

Le mod`le MVC (Mod`le-Vue-Controleur) e e

11

INTERFACES GRAPHIQUES

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 que larbre puisse tre modi ` la suite de son achage, par exemple en e e ea raction ` des actions de lutilisateur, alors il aurait fallu que notre classe Arbuste implmente linterface e a e MutableTreeNode, une sous-interface de TreeNode qui spcie des mthodes supplmentaires pour ajouter e e e 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 implmentation de TreeNode. Cela nous obligera ` adopter une deuxi`me e a e mani`re de construire la vue arborescente : ne pas utiliser un mod`le par dfaut (classe DefaultTreeModel) e e e mais un mod`le que nous aurons dni expr`s pour travailler avec des objets Arbuste. Cest notre classe e e e ModeleArbuste, enti`rement faite de mthodes imposes par linterface TreeModel : e e e 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); } 140
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.9

Le mod`le MVC (Mod`le-Vue-Controleur) e e

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

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

Vue arborescente, version 3. A loppos de la prcdente, une autre mani`re daborder ce probl`me e e e e e consiste ` penser que des nuds aussi banaux que les ntres existent srement tout prts dans la biblioth`que, a o u e e ce qui devrait nous dispenser dcrire la classe Arbuste. e En eet, si tout ce quon demande ` un nud est de porter une information (peut importe son type, a pourvu que ce soit un objet), davoir des ls et ventuellement davoir un p`re, alors la classe Defaulte e MutableTreeNode 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 de notre programme (il est maintenant beaucoup plus e court) : import javax.swing.*; import javax.swing.tree.*; public class Essai { public static DefaultMutableTreeNode creerMots(String debut, int large, int profond) { DefaultMutableTreeNode res = new DefaultMutableTreeNode(); res.setUserObject(debut); if (profond > 0) for (int i = 0; i < large; i++) res.insert(creerMots(debut + (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`re de traiter ce probl`me ; elle consiste ` e e a examiner le mod`le dni ` la version 2, cens manipuler un arbre fait de nuds Arbuste, et se dire quun tel e e a e mod`le pourrait aussi bien faire semblant de manipuler un arbre qui, en tant que structure de donnes, e e nexiste pas. Voici la classe qui ralise un tel mod`le. Puisquil ny a pas darbre, les nuds se confondent avec les e e informations associes : e
c H. Garreta, 2000-2010

141

11.10

Images

11

INTERFACES GRAPHIQUES

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`res versions de Java la manipulation des images obit ` un mod`le de production et cone e a e sommation. Ayant pour objet premier les images provenant du Web, ce mod`le suppose que lexploitation e dune image est un processus, ventuellement de longue dure, impliquant un producteur, comme un chier e e sur un serveur loign, un consommateur, par exemple linterface graphique dune application qui ache e e limage, et un observateur , cest-`-dire un objet qui supervise lopration et qui reoit les notications a e c concernant ltat davancement du transfert de limage. e A ct de ce mod`le, passablement complexe, lquipe de dveloppement de Java fait maintenant la oe e e e promotion dun mod`le dit en mode immdiat, centr sur la notion dimage en mmoire : fondamentalement, e e e e on sintresse moins au transfert de limage (pour lequel le mod`le producteur/consommateur reste pertinent) e e qu` ce quon peut faire avec limage lorsque, une fois transfre, elle est stocke dans la mmoire du syst`me. a ee e e e 142
c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.10

Images

11.10.1

Exemple : utiliser des icnes o

Figure 28 Six boutons et une (grande) tiquette dcors dicnes e e e o Les icnes sont des images de taille xe, souvent petites, gnralement utilises pour dcorer certains o e e e e composants comme les tiquettes et les boutons. e Lapplication tr`s simple montre 101 a la gure 28 est faite dune grande tiquette portant un texte e e ` e ( Htesse de lair ` la Bardaf ) et une icne (Natacha, un personnage de BD des annes 70). Le texte o a o e peut se placer ` gauche, dans lalignement ou ` droite de licne, ainsi quen haut, ` la mme hauteur ou en a a o a e bas de licne (les composants tiquettes de Swing objets JLabel permettent de faire cela). Lapplication o e comporte en outre une barre doutils dtachable avec six boutons, disposs en deux groupes de trois boutons e e mutuellement exclusifs, qui commandent la position du texte par rapport ` licne. Les boutons sont blancs a o quand ils sont au repos (non slectionns) et rouges quand ils sont slectionns. e e e e Ce programme utilise treize chiers contenant chacun une icne : six icnes de boutons blancs (chiers o o bhgauche.gif, bhcentre.gif, etc.), six icnes de boutons rouges, dont les noms sont de lg`res altrations o e e e des prcdents (chiers bhgaucheR.gif, bhcentreR.gif, etc.) et le dessin central (chier natacha.jpg). e e Tous ces chiers sont placs dans un rpertoire ayant le nom relatif images. e e 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 };
101. Limperfection des moyens de reprographie habituellement inigs ` ce genre de polycopis nous dissuade de montrer ici e a e de vraies photographies, qui auraient pourtant t tout ` fait adaptes ` lillustration de notre propos. e e a e a

c H. Garreta, 2000-2010

143

11.10

Images

11

INTERFACES GRAPHIQUES

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^tesse de lair ` la Bardaf", icone, JLabel.CENTER); o a 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. Il faut donc e explicitement leur associer des cha nes action command an de pouvoir les distinguer dans la mthode e actionPerformed. Comme nimporte quel ensemble de six cha nes distinctes fait laaire, nous avons utilis e les noms des chiers images, qui ont le mrite dexister et dtre deux ` deux dirents. e e a e 11.10.2 Exemple : charger une image depuis un chier

Apr`s les icnes, qui sont des images simplies quon ne souhaite pas transformer, intressons-nous aux e o e e images (quelconques) en mmoire, ou buered images. e De telles images ont deux principales raisons dtre 102 : soit ce sont des images calcules , cest-`e e a
102. Une bonne raison de sintresser aux images en mmoire est le double buering. Lorsquon dessine directement sur lcran e e e

144

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.10

Images

dire construites pixel ` pixel par le programme (les fameuses images de synth`se), soit ce sont des images a e traites , cest-`-dire produites ` lextrieur du programme (par exemple des photographies) mais devant e a a e subir des transformations gomtriques, des modications des couleurs, etc. Bien entendu, dans un cas e e comme dans lautre, il est en gnral ncessaire que ces images, une fois construites en mmoire, puissent e e e e tre aches sur un cran. e e e

Figure 29 Acher une image

La gure 29 correspond ` une application tr`s simple qui montre une premi`re mani`re dobtenir une a e e e image en mmoire : la charger depuis un chier (qui est nomm 103 ici XGorce_020613.gif et est plac dans e e e un certain rpertoire images) : e 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 mthodes intressantes sont le constructeur et la mthode paint : le premier e e e obtient limage ` partir dun chier, la seconde lache. a Remarque pointue. Ce programme fait ce quon lui demande de faire et il semble sans myst`re car, ` e a moins davoir une vue exceptionnelle, lutilisateur ne voit pas que d`s le dmarrage limage est (re-)dessine e e e un grand nombre de fois. On peut sen apercevoir en ajoutant dans la mthode paint la ligne e System.out.println(compteur++);
une image tr`s complexe, les tapes de la construction sont perceptibles et lachage devient dsagrable pour lutilisateur, e e e e particuli`rement dans le cas danimations. Le double buering est la technique consistant ` dessiner non pas sur lcran, mais e a e sur une portion de mmoire quon met ` lcran en une seule opration, donc de mani`re instantane, lorsque le trac est e a e e e e e enti`rement ni. e 103. Xavier Gorce dessine un strip quotidien dans LeMonde.fr, dans lequel les animaux de la fort et, plus rcemment, les e e manchots de la banquise commentent lactualit ou font des remarques philosophiques. e

c H. Garreta, 2000-2010

145

11.10

Images

11

INTERFACES GRAPHIQUES

(compteur est une variable dinstance prive). Le programme ache limage et, en plus, il ache des nombres e qui permettent de constater que paint a t appele plus de vingt fois avant que le programme ne se calme ! ee e Cela montre le caract`re asynchrone du mod`le producteur/consommateur, dont rel`ve la mthode e e e e 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 immdiatement, avant que les donnes qui constituent limage ne soient acquises 104 . Par consquent, lappel e e e de paint qui est fait lors de lachage initial de linterface ne dessine pratiquement rien. Ce qui sauve ce programme est le quatri`me argument (this) de lappel de drawImage : e g.drawImage(uneImage, 5, 5, this); il indique que lobservateur de cette image est le panneau AfficherUneImage lui-mme, qui devient ainsi e le destinataire des notications concernant la progression du chargement. Chacune de ces notications provoque un appel de repaint, donc lachage dun nouvel tat de limage, jusqu` ce que cette derni`re soit e a e enti`rement charge ; cela se passe assez vite et lutilisateur croit voir lachage en une fois dune image e e unique 105 . Charger une image range avec les classes e Dans lexemple prcdent on charge une image ` partir dun chier spci par son chemin dans un e e a e e syst`me de chiers donn (probablement celui qui entoure le dveloppement) : e e e 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 frquent o` e u lapplication doit sexcuter dans un environnement inconnu, distinct de celui de son dveloppement ? e e Si le chier de limage est un chier variable appartenant au syst`me dans lequel lapplication sexcute e e il ny a pas de probl`me : le chemin sera saisi durant lexcution, soit sous forme de texte, soit ` laide dun e e a FileChooser (cf. 11.8.4). Mais comment indiquer un chier constant , fourni par le dveloppeur de lapplication, rang avec les e e classes de celle-ci, par exemple dans larchive jar utilise pour distribuer lapplication ? La solution consiste e a ` obtenir ladresse du chier par la mthode getResource de la classe (nous disons bien la classe) en cours e dexcution. Le travail est alors dlgu ` lobjet class loader qui a charg cette classe, en quelque sorte cela e ee ea e revient ` chercher le chier l` o` on a trouv la classe . a a u e Par exemple, si nous avons archiv les classes de notre application avec un rpertoire images contenant e e le chier en question, il sura de remplacer la ligne montre prcdemment par : e e e URL url = AfficheurdImages.class.getResource("images/XGorce.021108.gif"); uneImage = Toolkit.getDefaultToolkit().getImage(url); Note. Dans une mthode dinstance (c.-`-d. non statique), la premi`re des lignes ci-dessus peut scrire e a e e galement e URL url = getClass().getResource("images/XGorce.021108.gif"); 11.10.3 Exemple : construire une image pixel par pixel

La mthode createImage(ImageProducer producteur) de la classe java.awt.Component renvoie une e image correspondant aux donnes (les pixels) fournies par lobjet producteur. Le type de limage (i.e. le e mode de codage des pixels) est celui qui correspond ` lenvironnement graphique utilis, logiciel et matriel. a e e Comme producteur on peut prendre un objet MemoryImageSource, consistant essentiellement en un tableau de nombres, chacun dcrivant un pixel selon le codage RGB. e Par exemple, le programme suivant dessine une image en noir et blanc calcule pixel par pixel (voyez la e gure 30) : le centre de limage est blanc, puis les pixels sassombrissent au fur et ` mesure quon sloigne a e du centre, proportionnellement au carr de la distance au centre : e
104. Cest la raison pour laquelle, dans le constructeur, nous ne pouvons pas donner ` notre panneau la taille eective requise a par limage (ce qui aurait t bien pratique !) mais uniquement une taille convenue comme 500 150. Cest que, immdiatement e e e apr`s lappel de createImage, limage nest quamorce et elle na pas de taille dnie. e e e 105. 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.

146

c H. Garreta, 2000-2010

11

INTERFACES GRAPHIQUES

11.10

Images

Figure 30 Une image de synth`se ! e

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); } }

c H. Garreta, 2000-2010

147

12

JAVA 5

12

Java 5

Si chaque version de Java a apport au langage un lot dlments nouveaux, Java 5 a t une avance e ee ee e particuli`rement signicative. Il y aurait beaucoup ` dire ` propos des nouveauts de cette version, mais nous e a a e nous limiterons ici aux points susamment importants pour mriter de gurer dans un polycopi succinct e e comme celui-ci. Au moment o` ce document est produit la version courante de Java est la version 6, ociellement u dnomme JavaTM Platform Standard Edition 6 (ou, entre dveloppeurs, JDK 1.6 ) mais les versions 5 et 1.4 e e e sont encore assez rpandues. Vous pouvez spcier quelles extensions vous autorisez dans votre programme e e en lanant la compilation avec loption -source : c 1.4 1.5 ou 5 javac -source Classe.java 1.6 ou 6 Par dfaut, la compilation se fait en accord avec la version 6. Si vous compilez avec loption -source 1.4 e alors les extensions expliques ci-apr`s ne seront pas admises ; cela peut savrer utile, certaines prescriptions e e e de la version 5 provoquant parfois des messages davertissement copieux et obscurs lors de la compilation de sources dorigine 1.4.

12.1

Types numrs e e e

On a souvent besoin densembles nis de donnes conventionnelles, comme { nord, sud, est, ouest }, e { lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche }, etc. Quel que soit le domaine dapplication, ces donnes partagent certains traits caractristiques : e e 1. Elles sont tr`s symboliques et munies de noms naturels et signicatifs. Cest pourquoi il est regrettable e de les reprsenter ` laide de simples nombres, comme on le fait quand on na pas dautre moyen : 0 e a pour nord, 1 pour sud, 2 pour est, etc. 2. Ce sont des donnes atomiques comme des nombres , ce qui devrait leur donner un faible encome brement et permettre un traitement tr`s rapide. Cest pourquoi il est regrettable de les reprsenter par e e des cha nes de caract`res, comme on le fait parfois : "nord" pour nord, "sud" pour sud, etc. e 3. Ces donnes constituent des ensembles nis, souvent de taille rduite, ce qui devrait permettre certaines e e oprations et certaines optimisations par exemple, pour la reprsentation de leurs sous-ensembles e e auxquelles il faudra renoncer si on reprsente ces donnes par des nombres ou des cha e e nes de caract`res. e 4. Enn, et surtout, elles constituent des ensembles disjoints davec les autres types de donnes (un point e cardinal nest pas interchangeable avec un jour de la semaine !). Cela devrait permettre, de la part du compilateur, un puissant contrle de type quon naura pas si on reprsente ces donnes par des o e e nombres ou des cha nes. En Java, jusqu` la version 1.4, on implmentait presque toujours les donnes symboliques par des suites a e e de constantes numriques : e 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`re de faire est en accord avec les deux premi`res proprits ci-dessus, mais pas avec les deux e e ee 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 mme pas un type : le compilateur ne pourra pas nous aider e si par inadvertance nous aectons la valeur NORD ` une variable jourDeLaSemaine (dont les valeurs attendues a LUNDI, MARDI, etc., sont galement reprsentes par des constantes enti`res). e e e e Java 5 corrige ces dfauts en introduisant les nouveaux types numrs ou enums, expliqus ci-apr`s. e e e e e e 12.1.1 Enums

La dclaration dun type numr se compose au moins des lments suivants (cela senrichira par la e e ee ee suite) : qualieurs enum identicateur { identicateur , identicateur , ... identicateur } Deux exemples : public enum PointCardinal { NORD, SUD, EST, OUEST } public enum JourSemaine { LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE } 148
c H. Garreta, 2000-2010

12

JAVA 5

12.1

Types numrs e ee

Note. Les deux dclarations prcdentes dnissant des types publics, elles doivent tre crites dans e e e e e e deux chiers spars, respectivement nomms PointCardinal.java et JourSemaine.java. e e e Exemples dutilisation ultrieure : e PointCardinal direction = PointCardinal.NORD; ... JourSemaine jourDePresence = JourSemaine.MERCREDI; Notez bien que la dclaration dun type enum nest pas quun artice pour donner des noms expressifs ` une e a poigne de nombres entiers. Les dclarations prcdentes crent bien deux types nouveaux, PointCardinal e e e e e et JourSemaine, distincts entre eux et distincts de tous les autres types, dont lemploi pourra tre nement e contrl par le compilateur. oe Pour faire comprendre la nature des lments dun type enum disons pour commencer (car en fait cest ee plus riche que cela) que la dclaration e public enum PointCardinal { NORD, SUD, EST, OUEST } a dj` tout leet quaurait eu la dclaration suivante : ea e 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() {} // pour emp^cher la cration dautres instances e e } 12.1.2 Mthodes des types numrs e e e e

Un type numr appara donc comme une classe dont les seules instances sont les valeurs du type e ee t numr. En ralit, tout type numr est sous-classe de la classe java.lang.Enum, qui introduit quelques e ee e e e ee mthodes bien utiles : e String name(), String toString() Ces deux mthodes renvoient la valeur en question, exprime sous forme de cha de caract`res ; par e e ne e exemple PointCardinal.NORD.name() est la cha "NORD". La seconde est plus intressante car elle ne e est implicitement appele par Java pour convertir une valeur en cha ; de plus, elle peut tre rednie. e ne e e Cela scrit comme ceci : e 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 numration valueOf(String nom) e e Renvoie la valeur du type numr dont le nom est donn. Ce nom doit tre crit exactement comme e ee e e e dans la dnition du type numr. Par exemple, PointCardinal.valueOf("EST") vaut PointCardinal.EST. e e ee static numration[] values() e e Renvoie un tableau contenant toutes les valeurs du type numr. Par exemple, le code e ee PointCardinal[] directions = PointCardinal.values(); for (int i = 0; i < directions.length; i++) System.out.print(directions[i] + " "); ache le texte NORD SUD EST OUEST .
c H. Garreta, 2000-2010

149

12.1

Types numrs e ee

12

JAVA 5

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 rciproque est facile ` obtenir : PointCardinal.values()[0] vaut PointCardie a nal.NORD, PointCardinal.values()[1] vaut PointCardinal.SUD, etc. 12.1.3 Aiguillages commands par des types numrs e e e e

Bien quelles ne soient pas des nombres ou des caract`res, les valeurs des types numrs peuvent servir e e ee a ` piloter des aiguillages. Par exemple, supposons avoir la dclaration e public enum CategorieVehicule { BERLINE, COUPE, FAMILIALE; } voici un tel aiguillage : ... CategorieVehicule categorie; ... switch (categorie) { case BERLINE: code correspondant au cas o` categorie vaut CategorieVehicule.BERLINE u break; case COUPE: code correspondant au cas o` categorie vaut CategorieVehicule.COUPE u break; case FAMILIALE: code correspondant au cas o` categorie vaut CategorieVehicule.FAMILIALE u break; default: throw new AssertionError("\nErreur de programmation: cas " + categorie + " non trait dans switch"); e } Notez que, puisque le switch est command par une expression de type CategorieVehicule, ` lintrieur e a e de celui-ci le compilateur laisse crire BERLINE, COUPE ou FAMILIALE au lieu de CategorieVehicule.BERLINE, e CategorieVehicule.COUPE ou CategorieVehicule.FAMILIALE. Notez galement que lutilisation de la clause default, comme ci-dessus, est recommande. En procdant e e e ainsi, si plus tard on ajoute des valeurs au type numr en oubliant dajouter les case correspondants dans e ee les switch concerns, on en sera prvenu (hlas, on ne sera prvenu qu` lexcution, on aurait sans doute e e e e a e prfr ltre durant la compilation...). eee e 12.1.4 Dictionnaires et ensembles bass sur des types numrs e e e e

Dictionnaires. Le nouveau type EnumMap (en ralit cest une classe paramtre mais pour commencer e e e e nous passerons cet aspect sous silence voyez la n de cette section) a t introduit pour permettre la ee construction de tables associatives dont les cls sont les valeurs dun type numr, avec optimisation de e e ee lespace et du temps dacc`s. Cela semploie comme ceci : e 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); ... 150
c H. Garreta, 2000-2010

12

JAVA 5

12.2

Emballage et dballage automatiques e

Ensembles. De mani`re analogue ` EnumMap, le type EnumSet (encore une classe paramtre, voyez la e a e e n de cette section) a t introduit en vue de la dnition densembles compacts et ecaces 106 dont les ee e lments sont les valeurs dun type numration donn. ee e e e Les ensembles EnumSet supportent, comme toutes les collections, les oprations fondamentales contains e (test dappartenance), add et remove (ajout et suppression dun lment), plus quelques oprations de fabriee e cation particuli`rement commodes : e static EnumSet of(Object premierElement, Object... autresElements) Construction dun ensemble form des lments indiqus (il sagit dune mthode avec nombre variable e ee e e darguments, cf. 12.3.3). static EnumSet allOf(Class typeElements) Construction dun ensemble form de tous lments du type numr indiqu. e ee e ee e static EnumSet complementOf(EnumSet s) Construction dun ensemble form de tous les lments du type numr en question qui ne sont pas e ee e ee 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 dans les lignes prcdentes, pour ne pas les alourdir, mais en tre e e ralit EnumMap et EnumSet sont des classes paramtres (cf. 12.5) et leurs dclarations compl`tes prennent e e e e e e 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 dballage automatiques e


Principe

En Java, les donnes de types primitifs, byte, short, int, long, float, double, char et boolean, ne sont e pas des objets. Cela est ainsi pour des raisons videntes decacit, car traiter ces types de donnes comme le e e e font les langages les plus simples permet dutiliser des oprations cbles (cest-`-dire directement prises e a e a en charge par le matriel) extrmement optimises. Cependant, dun point de vue mthodologique, ce nest e e e e pas satisfaisant : cest regrettable pour la clart des ides, car cela introduit deux poids et deux mesures (ce qui est vrai e e pour les objets ne lest pas forcment pour les donnes primitives, et rciproquement), multiplie les cas e e e particuliers, alourdit les spcications, etc., e dun point de vue pratique cest encore plus regrettable, car cela interdit demployer sur des donnes e de types primitifs les puissants outils de la biblioth`que Java comme les collections, qui ne travaillent e quavec des objets. Ce second dfaut tant considrable, il a bien fallu lui trouver un rem`de. Cela a consist (cf. 9.1.1) e e e e e en la dnition de huit classes Byte, Short, Integer, Long, Float, Double, Character et Boolean, en e correspondance avec les huit types primitifs ; chaque instance dune de ces classes se compose dune unique donne membre qui est une valeur du type primitif que linstance enveloppe . e Lopration consistant ` construire un tel objet enveloppant une valeur v dun type primitif sappelle e a emballage de la valeur v ; lopration rciproque sappelle dballage de la valeur v . Ainsi, par exemple, e e e pour des valeurs de type int, ces oprations peuvent (et, jusqu` Java 1.4, doivent) scrire : e a e
106. On nous assure que ces ensembles sont raliss avec des tables de bits, ils sont donc aussi peu encombrants et dun e e traitement aussi ecace que les ensembles quon peut raliser soi-mme avec des lments reprsents par des puissances de 2 e e ee e e et les oprateurs de bits & et |. e

c H. Garreta, 2000-2010

151

12.2

Emballage et dballage automatiques e

12

JAVA 5

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

// emballage de unInt // dballage de unInt e

La bonne nouvelle est quen Java 5 ces deux oprations sont devenues automatiques, cest-`-dire insres e a ee par le compilateur l` o` elles sont ncessaires, sans que le programmeur nait ` sen occuper explicitement. a u e a Plus prcisment : e e dans un endroit o` un objet est attendu on peut mettre une expression dun type primitif ; ` lexcution, u a e sa valeur sera convertie en objet par construction dune instance de la classe enveloppe correspondant a ` ce type primitif, dans un endroit o` une valeur dun type primitif est attendue on peut mettre une expression dont le u type est la classe-enveloppe correspondante ; ` lexcution, lobjet sera converti dans le type primitif a e requis par appel de la mthode typeValue(), o` type est le nom de ce type primitif. e u Exemple. Un important domaine dapplication de lemballage et dballage automatiques est la mise e en uvre de collections contenant des donnes primitives. Par exemple, voici comment on peut raliser e e simplement une le dattente dentiers en Java 5 : Dclaration et cration : e e List file = new LinkedList(); // Opration introduire un entier v dans la le (v e file.add(v); // Opration extraire un entier u de la le : e int u = (Integer) file.remove(0); // ou Vector, ou toute autre implmentation de List e a t dclare int) : ee e e add ajoute ` la n de la liste a extraction de llment de tte ee e

Note. Avec les collections gnriques expliques plus loin (cf. 12.5) les oprations prcdentes deviene e e e e e nent encore plus simples et, surtout, plus ables : List<Integer> file = new LinkedList<Integer>(); ... file.add(v); // ici il est vrifi que la conversion de v e e ... // donne un Integer int u = file.remove(0); // ce qui sort de la file est un Integer 12.2.2 Oprations drives et autres consquences e e e e

Le mcanisme de lemballage et dballage automatiques est simple et puissant, mais il faut prendre garde e e quil a de nombreuses consquences, dont certaines subtiles. e Arithmetique. Par exemple, avec la dclaration e Integer nombre; le code suivant est lgitime e nombre = nombre + 1; le compilateur le traduira en : nombre = new Integer(nombre.intValue() + 1); De mme, il est possible dcrire e e nombre++ cette expression ayant la valeur et leet quaurait lappel dune fonction ctive ressemblant ` ceci : a 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 dlicat. Donnons-nous la situation suivante : e 123; 123; 12345; 12345;

152

c H. Garreta, 2000-2010

12

JAVA 5

12.2

Emballage et dballage automatiques e

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`me expression (c == d) sache false. En eet, c et d sont des objets construits e sparment et on a dj` expliqu (cf. 3.6.3) que, pour les objets, == exprime lidentit (galit des rfrences), e e ea e e e e ee non lquivalence. Pour tester lquivalence (galit des valeurs) il aurait fallu crire c.equals(d). e e e e e En revanche, on sera peut-tre tonn en constatant que les trois autres expressions achent true. Pour e e e les deux premi`res (a == 123 et c == 12345) la question est la mme : il sagit de savoir si la comparaison e e a == 123 porte sur deux valeurs primitives ([a converti en int] et 123) ou bien sur deux objets (a et [123 transform en Integer]). Cest le premier qui se produit : la comparaison des valeurs tant en gnral plus e e e e intressante que la comparaison des rfrences, le compilateur prf`re travailler dans le type primitif. Do` le e ee ee u rsultat true : a et c convertis en int sont bien respectivement gaux aux nombres auxquels on les compare. e e Il reste le troisi`me cas, a == b, qui sache true faisant penser que, bien que construits sparment, a e e e et b sont le mme objet. Et cest bien ce qui se passe ! En eet, dans certains cas rputs frquents, avant e e e e de provoquer un appel de new, Java examine si la valeur en question na pas dj` t emballe, auquel cas eaee e lobjet-enveloppe prcdemment construit est rutilis. Ainsi, les deux lignes e e e e Integer a = 123; Integer b = 123; ont le mme eet que e Integer a = new Integer(123); Integer b = a; ce qui explique lgalit trouve. e e e Les cas rputs frquents , cest-`-dire les valeurs pour lesquelles la machine cherche ` savoir si elles e e e a a ont dj` t emballes avant de crer un nouvel objet, sont les petites valeurs ; plus prcisment : eaee e e e e les boolens false et true, e les valeurs de type byte, short et int comprises entre -128 et 127, les caract`res dont le code est compris entre \u0000 (0) et \u007F (127) e 12.2.3 La rsolution de la surcharge en Java 5 e

Dans quelle mesure le mcanisme de lemballage et dballage automatiques complique-t-il celui de la e e rsolution de la surcharge que Java emploie par ailleurs ? Supposons, par exemple, disposer dune certaine e mthode traitement surcharge : e e void traitement(double x) { ... } ... void traitement(Integer y) { ... } a loccasion dun appel comme int z; ... traitement(z); laquelle des deux mthodes doit-on activer ? Autrement dit, le type Integer est-il considr plus proche du e ee type int que le type double, ou le contraire ? Les concepteurs de Java 5 ont dcid de privilgier une certaine e e e forme de compatibilit avec Java 1.4, ainsi la conversion vers le type primitif (ici double) est prfre. La e eee r`gle prcise est la suivante : e e En Java 5 la rsolution de la surcharge se fait en trois temps : e 1. Le compilateur cherche dabord ` rsoudre lappel dune mthode surcharge sans utiliser lemballage a e e e et dballage automatiques ni les arguments variables (cf. 12.3.3). Si lappel peut tre rsolu ainsi, e e e alors les r`gles appliques auront t les mme quen Java 1.4. e e ee e 2. Si la premi`re tape a chou, alors le compilateur cherche ` rsoudre lappel en se permettant des e e e e a e emballages et des dballages, mais sans considrer les mthodes avec des arguments variables. e e e 3. Enn, si ltape 2 a chou aussi, alors le compilateur cherche ` rsoudre lappel en considrant les e e e a e e mthodes avec des arguments variables. e
c H. Garreta, 2000-2010

153

12.3

Quelques outils pour simplier la vie du programmeur

12

JAVA 5

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 entits ? La directive import que nous connaissons e permet de mentionner une classe publique sans avoir ` prxer son nom par celui de son paquetage. Cest a e bien, mais cela nempche pas que les autres entits manipules dans les programmes, comme les membres e e e des classes, ont tendance ` avoir des noms ` rallonges. Ne pourrait-on pas faire dautres simplications du a a mme genre ? e Pour les membres ordinaires non statiques on ne peut pas grand chose : ils doivent tre prxs par e e e un objet car cela est dans leur nature mme de membres dinstance, cest-`-dire ncessairement lis ` un e a e e a objet. Seule simplication, bien connue : quand cet objet est this, la plupart du temps il peut tre omis. e Il nen est pas de mme pour les membres de classe (membres qualis static), cela a permis de simplier e e leur emploi en Java 5. Jusqu` Java 1.4, ces membres doivent tre crits prxs par le nom de leur classe ; il a e e e e sagit dviter dventuelles collisions de noms, ce qui est un risque potentiel qui nest pas toujours eectif : e e les membres de classes direntes ont une petite tendance ` avoir des noms dirents. Ne pourrait-on pas, e a e lorsquil ny a pas de collision, permettre que les noms des membres statiques soient utiliss sans prxe ? e e 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`re forme, le nom du membre statique indiqu pourra tre utilis seul, cest-`-dire non e e e e a prex par le nom de la classe. Dans la deuxi`me forme, tous les membres statiques de la classe indique e e e pourront tre utiliss seuls. e e Exemple. Le programme Sinus ache le sinus dun angle donn en degrs. Version traditionnelle : e e 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 imports est plus lg`re (en faisant abstraction des directives import) : e e e 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 rv`le prcieuse pour simplier lemploi des types numrs (cf. e e e e ee 12.1.1), puisque les valeurs de ces derniers sont des membres (implicitement) statiques. Par exemple, tant e donn le type e public enum JourSemaine { LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE } dans un programme o` on doit utiliser ces valeurs, lcriture de la directive u e import static JourSemaine.*; permettra dcrire LUNDI, MARDI, etc. au lieu de JourSemaine.LUNDI, JourSemaine.MARDI, etc. e Note 2. Bien entendu, lemploi de import static fait rappara e tre le risque de conits de noms que lcriture explicite des noms des classes cherchait ` viter. Il faut signaler cependant que ce risque est minimis e ae e par le fait que le compilateur ne se dclare en situation de conit que lorsquil est eectivement plac devant e e un acc`s ` une variable ou un appel de mthode reprsentant pour lui une ambigu e insoluble. e a e e t Pour illustrer cette bonne volont du compilateur, imaginez deux classes A et B ainsi dnies e e 154
c H. Garreta, 2000-2010

12

JAVA 5

12.3

Quelques outils pour simplier la vie du programmeur

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 mthode fon sera traite comme une mthode surcharge ordinaire : sur la rencontre dun appel comme e e e e fon(u), lune ou lautre dnition sera choisie selon le type de u. e 12.3.2 Boucle for amliore e e

Une nouvelle construction, dite boucle for amliore, a t ajoute au langage dans le but dallger e e ee e e lcriture de deux sortes de boucles extrmement frquentes : le parcours dun tableau et le parcours dune e e e collection. 1 Si tableau est un tableau dlments dun certain type TypeElement, qui peut tre un type primitif, ee e un tableau ou une classe, la boucle for (int i = 0; i < tableau.length; i++) exploiter( tableau[i] ) peut scrire plus simplement : e for (TypeElement elt : tableau) exploiter( elt ) 2 Si liste est une structure de donnes susceptible dtre parcourue au moyen dun itrateur cest-` e e e a dire si liste implmente la nouvelle interface java.lang.Iterable la boucle e for (Iterator iter = liste.iterator(); iter.hasNext(); ) exploiter( (TypeElement)iter.next() ) peut scrire plus simplement : e 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 lment dun vecteur donn, en prenant soin de parcourir non pas le vecteur en ee e question mais le rsultat du clonage 107 de ce dernier (notez que la spcication de la boucle for amliore e e e e garantit que lopration v.clone() sera eectue une seule fois, en commenant la boucle) : e e c Vector v = new Vector(); ... for (Object o : (Vector) v.clone()) traitement(o);
107. Parcourir un clone au lieu de parcourir la structure elle-mme para bizarre, mais cest ce quon doit faire sil est possible e t que le traitement modie le vecteur par exemple, en lui ajoutant ou en lui supprimant des lments. ee

c H. Garreta, 2000-2010

155

12.3

Quelques outils pour simplier la vie du programmeur

12

JAVA 5

Mise en garde. On peut trouver beaucoup de qualits ` la nouvelle boucle for amliore, mais il faut e a e e raliser quelle ne peut pas remplacer en toute circonstance la boucle for ordinaire, tout simplement parce e quelle nore pas un acc`s (indice, pointeur, etc.) ` la position dans la structure de llment en cours e a ee dexploitation. Ainsi, un code aussi simple que le suivant ne gagne pas en concision ni en ecacit lorsquon le transforme e an de lcrire en utilisant la boucle for amliore : e e e int i; ... for (i = 0; i < tab.length; i++) if ( condition( tab[i] ) ) break; utilisation de la valeur de i Objets itrables e Peut-on parcourir ses propres structures avec la nouvelle boucle for amliore ? Autrement dit, quelle e e proprit doit avoir un objet U pour pouvoir gurer dans une expression for ( dclaration : U ) ? La ee e rponse est simple, il sut que notre objet implmente linterface java.lang.Iterable : e e public interface Iterable<T> { Iterator<T> iterator(); } Par exemple, voici la dnition dune classe Intervalle 108 dont les instances reprsentent des intervalles e e de nombres entiers et peuvent, ` ce titre, tre utilises dans des boucles for amliores 109 : a e e e e 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 110 (notez quil y a dballage automatique des valeurs successivement produites par e litrateur, puisque i est dclare int) : e e e ... 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
108. Les amateurs de serpents reconna tront lobjet xrange du langage Python 109. Nous utilisons ici les types gnriques cf. 12.5 Iterable<Integer> et Iterator<Integer> qui, avec le dballage e e e automatique quils induisent, rendent cet exemple plus intressant. e 110. Il sagit ici dun exemple purement dmonstratif. Pour parcourir les entiers compris entre deux bornes inf et sup il est e sans doute plus ecace dutiliser une boucle for classique : for (int i = inf; i <= sup; i++) ...

156

c H. Garreta, 2000-2010

12

JAVA 5

12.3

Quelques outils pour simplier la vie du programmeur

12.3.3

Mthodes avec une liste variable darguments e

Java 5 permet dappeler une mme mthode 111 avec un nombre darguments eectifs qui varie dun appel e e a ` un autre. Ces arguments variables doivent partager un type commun, qui peut tre une super-classe de e leurs types eectifs. Dans la dclaration de la mthode, ce type commun doit appara suivi de trois points e e tre ... et un identicateur. Exemple : void afficherScores(int dossard, String nom, Number... scores) { corps de la mthode e } A lintrieur de la mthode, lidenticateur associ aux arguments variables (ici scores) est le nom dun e e e tableau dont les lments sont les arguments eectifs gurant dans lappel. Voici une criture possible de ee e 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 mthode devra tre appele avec pour arguments un entier, une cha de caract`res et un nombre e e e ne e 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 crire les appels de cette mthode plus simplement, en mettant ` prot lemballage automatique e e a (cf. 12.2) : afficherScores(102, "Dubois", 10, 15, 20.5); Dautre part, ce mcanisme peut aussi tre utilis avec des listes variables darguments de types primitifs. e e e La dclaration de la mthode afficherScores aurait pu tre e e e void afficherScores(int dossard, String nom, double... scores) { le corps de la mthode reste le mme e e } Remarque 1. Quand une mthode comporte une liste variable darguments elle peut tre appele de e e e deux mani`res : e en faisant correspondre ` largument variable un certain nombre darguments individuels distincts a (ayant des types compatibles avec la dclaration), e en faisant correspondre ` largument variable un unique tableau (dlments ayant un type compatible). a ee Ainsi, les deux appels suivants sont quivalents : e int[] tab = { 10, 20, 30, 25, 15 }; ... afficherScores(102, "Dubois", 10, 20, 30, 25, 15); afficherScores(102, "Dubois", tab); A lintrieur de la mthode, rien ne permet de distinguer le premier appel du second. e e Remarque 2. La possibilit davoir des listes variables darguments interf`re manifestement avec le e e mcanisme de la surcharge. Imaginez deux mthodes distinctes avec les prototypes suivants : e e void calcul(int x, int y) { ... } void calcul(int... z) { ... } La question est : comment est rsolu un appel tel que que calcul(a, b) ? La rponse ` t donne au e e aee e 12.2.3 : le compilateur essaie dabord de rsoudre la surcharge sans prendre en compte les mthodes avec e e liste variable darguments ; il ne consid`re ces mthodes que lorsquune telle rsolution choue. Ici, lappel e e e e calcul(a, b) activera donc la premi`re mthode, tandis que des appels comme calcul(a) ou calcul(a, e e b, c) activeraient la deuxi`me. e
111. Attention, nous ne parlons pas ici de surcharge, cest-`-dire de la possibilit dappeler des mthodes distinctes ayant le a e e mme nom, mais bien dappeler une mme mthode avec un nombre darguments qui di`re dun appel ` un autre. e e e e a

c H. Garreta, 2000-2010

157

12.3

Quelques outils pour simplier la vie du programmeur

12

JAVA 5

12.3.4

Entres-sorties simplies : printf et Scanner e e

La mthode printf e Les vieux routiers de la programmation en C nen croiront pas leurs yeux : ` loccasion de la version 5 a on a incorpor ` Java leur ch`re fonction printf ! Mais oui ! Exemple (inutile mais dmonstratif) : ea e e ... 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 mthode printf appartient aux classes PrintStream (ux doctets en sortie reprsentant des donnes e e e mises en forme) et PrintWriter (ux de caract`res en sortie reprsentant des donnes mises en forme). Dans e e e 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`re forme permet de prciser quelles particularits locales doivent tre employes, la deuxi`me e e e e e e utilise les particularits locales courantes. Dans tous les cas la mthode renvoie comme rsultat le ux sur e e e lequel elle a t appele (cela permet les cascades, genre : ux .printf(...).printf(...)). ee e Largument format est une cha compose de caract`res ordinaires, qui seront simplement recopis ne e e e dans le ux de sortie, parmi lesquels se trouvent un certain nombre de spcications de format qui indiquent e comment faut-il mettre en forme les donnes, reprsentes par largument variable args, places ` la suite e e e e a de largument format. Les spcications de format se prsentent ainsi (les crochets expriment le caract`re facultatif de ce quils e e e encadrent) : %[drapeau][largeur ][.precision]type Les principaux drapeaux sont - : commande le cadrage ` gauche, a + : prcise que les donnes numriques doivent toujours avoir un signe, e e e espace : indique que les nombres positifs doivent tre prcds dun blanc, e e e e 0 : spcie que les espaces libres prcdant les nombres doivent tre remplis avec 0, e e e e Largeur et prcision sont des entiers : le premier prcise le nombre total de caract`res que la donne doit e e e e occuper une fois mise en forme ; le second le nombre de chires apr`s la virgule. e Les principales indications de type sont : %% : pour indiquer le caract`re % e %b, %B : pour acher un boolen sous la forme false, true [resp. FALSE, TRUE]. e %c, %C : pour acher un caract`re dont la donne correspondante (qui doit tre de type Byte, Short, e e e Character ou Integer) exprime le code interne. %d : pour acher un entier crit en base 10. e %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 ` sa valeur. a %n : pour acher lindicateur de n de ligne de la plate-forme utilise (cest plus able que \n). e 158
c H. Garreta, 2000-2010

12

JAVA 5

12.3

Quelques outils pour simplier la vie du programmeur

%s, %S : pour acher une cha de caract`res. ne e %x, %X : pour acher un nombre en hexadcimal. e Il y a aussi de nombreuses pas moins de 32 ! spcications de format concernant la date et lheure. e Vous trouverez toutes les informations sur la mthode printf dans la documentation de lAPI, ` loccasion e a de la classe java.util.Formatter. La classe Scanner La classe java.util.Scanner est faite de mthodes pour lire simplement un ux de donnes formae e tes. Ensemble, ces mthodes rendent le mme genre de services que la fonction scanf bien connue des e e e programmeurs C. On construit un objet Scanner au-dessus dun ux doctets ou de caract`res pralablement ouvert ; dans e e le cas le plus simple de la lecture ` la console, ce ux est System.in. a Les mthodes de la classe Scanner les plus intressantes sont certainement : e e byte nextByte() Lecture de la prochaine valeur de type byte (cest-`-dire : consommation de tous les caract`res se a e prsentant dans le ux dentre qui peuvent faire partie dune donnes de ce type, construction et e e e 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`res se prsentant dans le ux dentre jusqu` une marque de n de ligne et e e e a renvoi de la cha ainsi construite. La marque de n de ligne est consomme, mais nest pas incorpore ne e e a ` la cha produite. ne BigInteger nextBigInteger() Lecture du prochain grand entier. BigDecimal nextBigDecimal() Lecture du prochain grand dcimal. e Exemple tr`s simple : e public class TestScanner { public static void main(String[] args) { Scanner entree = new Scanner(System.in); System.out.print("nom et prnom? "); e String nom = entree.nextLine(); System.out.print("^ge? "); a int age = entree.nextInt(); System.out.print("taille (en m)? "); float taille = entree.nextFloat(); System.out.println("lu: " + nom + ", " + age + " ans, " + taille + " m"); } } Excution de ce programme : e
c H. Garreta, 2000-2010

159

12.4

Annotations

12

JAVA 5

nom et prnom? Tombal Pierre e a ^ge? 32 taille (en m)? 1,72 lu: Tombal Pierre, 32 ans, 1.72 m Erreurs de lecture. Les erreurs lors de la lecture de donnes sont des fautes que le programmeur ne e peut pas viter, quel que soit le soin apport a la conception de son programme. Il doit donc se contenter de e e` faire le ncessaire pour les dtecter lors de lexcution et y ragir en consquence. En Java cela passe par le e e e e e mcanisme des exceptions : e ... 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 prcdent, comment dans le cas dune erreur de lecture il convient de nete e toyer le tampon dentre (cest le rle de linstruction entree.nextLine();) an que la tentative suivante e o puisse se faire avec un tampon vide. Tests de presence de donnees. La classe Scanner ore aussi toute une srie de mthodes boolennes e e e pour tester le type de la prochaine donne disponible, sans lire cette derni`re : e e boolean hasNext() Y a-t-il une donne disponible pour la lecture ? e boolean hasNextLine() Y a-t-il une ligne disponible pour la lecture ? boolean hasNextByte() La prochaine donne ` lire est-elle de type byte ? e a boolean hasNextShort() La prochaine donne ` lire est-elle de type short ? e a boolean hasNextInt() La prochaine donne ` lire est-elle de type int ? e a boolean hasNextLong() La prochaine donne ` lire est-elle de type long ? e a boolean hasNextFloat() La prochaine donne ` lire est-elle de type float ? e a boolean hasNextDouble() La prochaine donne ` lire est-elle de type double ? e a boolean hasNextBigInteger() La prochaine donne ` lire est-elle un grand entier ? e a boolean hasNextBigDecimal() La prochaine donne ` lire est-elle un grand dcimal ? e a e

12.4
12.4.1

Annotations
Principe

Les annotations, on dit aussi mta-donnes, sont un mcanisme permettant daccrocher des informations e e e priphriques aux classes et mthodes. Ces informations ne modient pas la smantique des programmes, e e e e mais sadressent ` des outils qui auraient ` manipuler ces derniers. Pour cette raison, les annotations ne a a disparaissent pas lors de la compilation 112 ; au contraire, elles sont reconnues et traites par le compilateur e
112. Cela est une dirence notable entre les annotations et, par exemple, les commentaires de documentation (adresss a e e ` loutil javadoc) dont il ne reste aucune trace apr`s la compilation. e

160

c H. Garreta, 2000-2010

12

JAVA 5

12.4

Annotations

et sont conserves avec les classes produites sauf instruction contraire. En contrepartie, cela les oblige ` e a obir ` une syntaxe aussi contraignante que celle des programmes. e a Pour pouvoir tre utilises, les annotations doivent dabord tre dclares par un texte, dnissant ce e e e e e e quon appelle un type annotation, qui est bizarrement voisin dune dclaration dinterface : e public @interface nomTypeAnnotation { dclaration des lments de lannotation e ee } Les lments dune annotation sont des donnes, analogues ` des variables nales (i.e. des constantes), ee e a mais il faut les dclarer par des expressions qui ressemblent ` des dclarations de mthodes : e a e e type nomElement(); avec la particularit quon peut indiquer une valeur par dfaut : e e type nomElement() default valeur ; Par exemple, voici un type annotation ` quatre lments destine ` signaler les mthodes dune classe a ee e a e dont on estime quelles peuvent tre amliores : e e e public @interface AmeliorationRequise { int identification(); String synopsis(); String auteur() default "(plusieurs)"; String date() default "non indique"; e } Lorsquun type annotation a un seul lment, celui-ci doit se nommer value : ee public @interface Copyright { String value(); } Enn, un type annotation peut aussi navoir aucun lment ; elle est alors dite annotation de marquage ee (marker annotation) : public @interface Test { } Voici une classe dont les mthodes ont t annotes en utilisant les trois types annotations prcdents. e ee e e e Notez que dans le cas dune annotation ` un seul lment, on peut crire annotation(valeur ) au lieu de a ee e annotation(value = valeur ) dans le cas dune annotation sans lments, on peut crire annotation au lieu de annotation() ee e public class ObjetAnnote { @Test public void unePremiereMethode(arguments) { corps de la mthode e } @Copyright("Editions Dupuis, 2004") public void uneAutreMethode(arguments) { corps de la mthode e } @AmeliorationRequise(identification = 80091, synopsis = "Devrait ^tre interruptible", e date = "11/09/2004") // ici auteur aura la valeur "(plusieurs)" public void uneTroisiemeMethode(arguments) { corps de la mthode e } autres mthodes e }

c H. Garreta, 2000-2010

161

12.4

Annotations

12

JAVA 5

12.4.2

Exploitation des annotations

A lexcution, lacc`s aux annotations portes par un excutable (ensemble de classes) se fait ` travers e e e e a les mthodes de linterface java.lang.AnnotatedElement, dont voici une dnition succincte : e e package java.lang.reflect; public interface AnnotatedElement { // renvoie un tableau contenant toutes les annotations portes par cet lment : e ee Annotation[] getAnnotations(); // renvoie le tableau des annotations faites directement (non hrites) sur cet lment : e e ee Annotation[] getDeclaredAnnotations(); // renvoie true si et seulement si cet lment porte une annotation ayant le type indiqu : ee e boolean isAnnotationPresent(Class<? extends Annotation> annotationType); // renvoie lannotation de cet lment ayant le type indiqu, ou null si elle nexiste pas ee e <T extends Annotation> T getAnnotation(Class<T> annotationType); } Bien entendu, cette interface est dsormais implmente par la plupart des classes qui constituent le e e e mcanisme de la rexion de Java (cf. 9.3) : Class, Constructor, Field, Method, Package, etc. Un e e exemple est montr ` la n de la section 12.4.1. ea Voyons cela a travers deux exemples simples : ` Exemple 1. Le programme suivant essaie toutes les mthodes portant lannotation Test dans une classe e quelconque, donne par son nom (en supposant que toutes ces mthodes sont statiques et sans argument) ; e e le point important dans cet exemple est la mthode isAnnotationPresent : e 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 + " chec: " + ex.getCause()); e nbrEchecs++; } } } System.out.println(nbrSucces + " succ`s et " + nbrEchecs + " checs"); e e } }

Exemple 2. Le programme suivant ache les valeurs de toutes les proprits de toutes les annotations ee attaches ` toutes les mthodes dune classe donne par son nom : e a e e import java.lang.annotation.Annotation; import java.lang.reflect.Method;

162

c H. Garreta, 2000-2010

12

JAVA 5

12.4

Annotations

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 tait appel avec pour argument le nom de la classe ObjetAnnote montre ` la page e e e a 161, ce programme acherait : unePremiereMethode Test uneAutreMethode Copyright value : Editions Dupuis, 2004 uneTroisiemeMethode AmeliorationRequise identification : 80091 synopsis : Devrait ^tre interruptible e auteur : (plusieurs) date : 11/09/2004 12.4.3 Annotations prdnies e e

Un petit nombre (appel ` grandir ?) dannotations sont prdnies et peuvent tre utilises sans autre ea e e e e prcaution : e @Deprecated Le compilateur achera un avertissement lors de tout emploi dun membre ainsi annot 113 . e @Override Indique que la mthode ainsi annote doit rednir une mthode hrite : si tel nest pas le e e e e e e 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 llment de code ainsi annot. ee e Par exemple, cette annotation permet que le clonage dun vecteur gnrique puisse se faire en sie e lence 114 : Vector<String> a = new Vector<String>(); ... @SuppressWarnings("unchecked") Vector<String> b = (Vector<String>) a.clone(); ...

12.4.4

Mta-annotations e

Les annotations dnies par lutilisateur peuvent tre annotes ` leur tour, par des annotations appeles e e e a e alors mta-annotations. Les types des mta-annotations sont prdnis ; ` lheure actuelle il y en a quatre : e e e e a
113. Lannotation @Deprecated rend donc un service qui tait assur prcdemment par la marque @deprecated crite dans un e e e e e commentaire /** ... */ ` ladresse de loutil javadoc. a 114. A propos des conversions unchecked voir lexplication des types bruts ` la section 12.5.2 a

c H. Garreta, 2000-2010

163

12.5

Gnricit e e e

12

JAVA 5

@Documented Indique que lannotation que cette mta-annotation annote doit tre prise en compte par e e loutil javadoc et dautres outils similaires, comme cela est fait pour les autres lments (classes, ee interfaces, etc.) qui composent le programme source. @Inherited Indique que lannotation concerne est automatiquement hrite. Si un membre est ainsi e e e annot et ses descendants (sous-classes, mthodes rednies, etc.) ne le sont pas, alors ces derniers e e e prendront automatiquement cette annotation. @Retention Indique jusqu` quel point du processus de dveloppement lannotation concerne doit tre a e e e conserve. Les valeurs possibles sont e RetentionPolicy.SOURCE : lannotation sera limine par le compilateur (lequel aura cependant e e vu lannotation, contrairement ` ce qui arrive pour un commentaire), a RetentionPolicy.CLASS : le compilateur laissera lannotation dans la classe compile mais la mae chine virtuelle lliminera lors du chargement de la classe, e RetentionPolicy.RUNTIME : lannotation sera conserve dans la classe compile et retenue par la e e machine virtuelle, si bien quelle sera accessible par les mcanisme de la rexion pendant e e lexcution du programme. e La valeur par dfaut est RetentionPolicy.CLASS. e @Target Indique sur quel type dlment lannotation porte. Plusieurs types peuvent tre indiqus en ee e e mme temps (la valeur de cette mta-annotation est un tableau de tels types). Les types possibles sont e e ElementType.ANNOTATION_TYPE : type annotation, ElementType.CONSTRUCTOR : constructeur, ElementType.FIELD : champ (variable dinstance), ElementType.LOCAL_VARIABLE : variable locale, ElementType.METHOD : mthode, e ElementType.PACKAGE : paquetage, ElementType.PARAMETER : param`tre dune mthode, e e ElementType.TYPE : classe, interface ou type numration (enum). e e La valeur par dfaut est tous les types. e

12.5

Gnricit e e e

Emblmatique de Java 5, la gnricit est peut-tre la plus importante des extensions du langage faites e e e e e a ` loccasion de cette version. Il sagit dobtenir en Java rien moins que les services que rendent les templates en C++, cest-`-dire la possibilit de dnir et demployer des classes et des mthodes paramtres par des a e e e e e types qui interviennent dans leur dnition. e Par exemple, une classe Truc tant dnie par ailleurs, cela nous permettra de dclarer une collection v e e e comme tant de type liste de trucs (cela scrira List<Truc>) au lieu du simple type List, cest-`-dire liste e e a dobjets quelconques. Les bnces obtenus sont faciles ` entrevoir : e e a lors dajouts dlments ` v, la vrication que ceux-ci sont bien de type Truc, ee a e lors dacc`s ` des lments de v, la certitude que les objets obtenus sont de type Truc. e a ee Voici ` quoi cela ressemblera : a // dclaration et cration de la liste e e List<Truc> liste = new Vector<Truc>(); ... // remplissage de la liste for (int i = 0; i < n; i++) { liste.add(expression); // ici il est contrl que expression est un Truc oe } ... // exploitation des lments de la liste ee 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 tant de type Truc e exploitation du truc q } En permettant aux compilateurs deectuer des contrles de type nombreux et ns, la gnricit augmente o e e e signicativement la qualit et la abilit des programmes. Hlas, dans certains langages elle en augmente e e e aussi la complication, parfois de mani`re considrable. On apprendra donc avec soulagement quen Java : e e 164
c H. Garreta, 2000-2010

12

JAVA 5

12.5

Gnricit e e e

la gnricit est totalement prise en charge au moment de la compilation et nentra aucune modie e e ne cation de la machine java, la gnricit est totalement compatible avec le langage prexistant : l` o` un objet ` lancienne est e e e e a u a attendu on peut mettre une instance dune classe gnrique, et rciproquement 115 . e e e 12.5.1 Classes et types paramtrs e e

Pour commencer il nous faut trois nouveaux concepts : 1 Une classe paramtre est une dclaration de classe dans laquelle le nom de la classe est suivi des signes e e e < > encadrant une liste de types param`tres (ventuellement) contraints spars, lorsquil y en a plusieurs, e e e e 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`re facultatif de ce quils encadrent) : e extends classeOuInterface [ & interface ... & interface ] cette expression doit tre comprise, selon que classseOuInterface est une classe ou une interface, respectivee ment comme extends classe implements interface, ... interface ou bien comme implements interface, interface, ... interface 2 Les types variables (ou types param`tres) sont les identicateurs constituant la liste des types para e m`tres dune classe paramtre (A, B et C 116 dans lexemple prcdent). A lintrieur de la classe, cest-`-dire e e e e e e a dans les dnitions de ses membres, ces identicateurs jouent le rle de types. Exemple : e o 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 paramtr est le nom dune classe paramtre suivi des signes < > encadrant une liste de e e e e vrais types. Cela reprsente donc le choix dun lment dans lensemble (inni) de types dni par la e ee e classe paramtre. De telles formules apparaissent le plus souvent dans des dclarations de variables et de e e e mthodes. Exemple 117 : e Machin<String, Integer, Vector<Truc>> unMachin = new Machin<String, Integer, Vector<Truc>>("un exemple", 100); Attention. Lopration consistant ` produire un type paramtr ` partir dune classe paramtre (en e a e ea e e remplaant les types param`tres par des types eectifs) est souvent appele instanciation de la classe parac e e mtre. On prendra garde ` lambigu e ainsi introduite, ce terme dsignant aussi la cration dun objet ` e e a t e e a partir [dun constructeur] de sa classe :
115. 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. 116. La recommandation ocielle est de donner ` ces types param`tres des noms tr`s courts, en majuscules et sans signicaa e e tion : A, B, C ou T1, T2, T3, etc. Cela an qu` lintrieur dune classe paramtre on puisse distinguer du premier coup dil a e e e les types param`tres des vrais types, qui ont gnralement des noms signicatifs, et des membres, qui sont crits plutt en e e e e o minuscules. 117. Les programmeurs C++ noteront avec plaisir que le compilateur Java ne prend pas toujours deux > conscutifs pour une e occurrence de loprateur >>. Mais oui, lhumanit progresse ! e e

c H. Garreta, 2000-2010

165

12.5

Gnricit e e e

12

JAVA 5

new Integer(1000) : instanciation de la classe Integer ; le rsultat est un objet, e Vector<Integer> : instanciation de la classe paramtre Vector<E> ; le rsultat est une classe. e e e Ce discours devient critique lorsque ces deux oprations sont invoques dans la mme expression : e e e new Vector<Integer>() : instanciation de la classe paramtre Vector<E> et instanciation de e e la classe ainsi obtenue. Utilisation des classes paramtres e e On laura compris, le plus beau domaine dutilisation des classes et types paramtrs est celui des cole e lections. On ne stonnera donc pas, en consultant la documentation de lAPI, de dcouvrir que toutes les e e interfaces et les classes collections de la biblioth`que ont t remplaces par une nouvelle forme paramtre, e ee e e e Collection<E>, Vector<E>, Iterator<E>, etc. Ces nouvelles classes se combinent tr`s bien avec lemballage/dballage automatiques (cf. section 12.2) e e et permettent lcriture de programmes plus simples et plus ables que par le pass. Voici un exemple que e e nous avons dj` montr : le programme suivant compte le nombre dapparitions de chaque mot donn dans ea e e la ligne de commande. En introduisant une table associative (objet Map) dont les cls sont ncessairement e e des cha nes de caract`res et les valeurs ncessairement des Integer le programmer augmente sensiblement e e la abilit de son programme : e 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 dnition dune classe paramtre, voici celle de la classe Paire dont les instances e e e reprsentent des paires de choses : e 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); }

166

c H. Garreta, 2000-2010

12

JAVA 5

12.5

Gnricit e e e

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 t dit, pour ce qui est de la gnricit, Java 5 est compatible avec les versions prcdentes ee e e e e e du langage. Il faut donc que les nouvelles classes paramtres puissent tre utilises par des programmes e e e e qui ne pratiquent pas la gnricit et, inversement, il faut que danciennes classes dj` crites puissent tre e e e eae e employes dans des programmes qui exploitent massivement la gnricit. e e e e Cest pourquoi toute classe paramtre est considre par le compilateur comme compatible avec sa e e ee version sans param`tres, appele le type brut (raw type) correspondant ` la classe paramtre. Par exemple, e e a e e Paire est le type brut associ ` la classe paramtre Paire<P, S>. ea e e Ainsi, avec la classe dnie ci-dessus, les quatre lignes suivantes sont acceptes par le compilateur e e ... 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 ` un avertissement signalant un appel a sans contrle du constructeur de la classe Paire<P, S>. Dans le cas de p2, le compilateur est galement o e chagrin en constatant une aectation sans contrle 118 de p2 (dclar de type Paire<P, S>) par un objet e o e e du type brut Paire. On peut supprimer ces messages davertissement (apr`s avoir acquis la certitude quils ne signalent pas e une erreur) en utilisant une annotation @SuppressWarnings comme expliqu ` la section 12.4 : ea ... @SuppressWarnings("unchecked") Paire<String, Number> p2 = new Paire("deux", 2); ... Note. A lexcution tous les types paramtrs construits au-dessus dun mme type brut sont considrs e e e e ee comme dnissant la mme classe. Par exemple, le code suivant ache true : e e ... 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 paramtrs et jokers e e

La gnricit est une notion plus complexe quil ny para il faut de la prudence y compris dans des e e e t, situations qui paraissent pourtant videntes. Par exemple, si la classe Chat est une sous-classe de la classe e Mammifere, il semble naturel de penser que List<Chat> est une sous-classe de List<Mammifere> (si un chat est une sorte de mammif`re alors une liste de chats est une sorte de liste de mammif`res, cela para clair !). e e t Cest pourtant compl`tement erron. Pour le voir il sut de se rappeler que A sous-classe de B e e signie tout ce quon peut demander ` un B on peut le demander ` un A . Or, il y a des choses quon a a peut demander ` une liste de mammif`res et pas ` une liste de chats : par exemple, linsertion dun chien. a e a Pour tre plus prcis, supposons que des classes Animal, Mammifere, Chat et Chien aient t dnies, e e ee e avec les relations dhritage que leurs noms sugg`rent : e e class Animal { ... }
118. Cette aectation est sans contrle parce que les concepteurs de Java 5 ont voulu que la gnricit soit traite durant la o e e e e compilation et quelle ne modie ni le code produit ni la machine virtuelle. Si la gnricit avait t traite ` lexcution il aurait e e e e e e a e t facile de contrler de telles oprations. e e o e

c H. Garreta, 2000-2010

167

12.5

Gnricit e e e

12

JAVA 5

class Mammifere extends Animal { ... } class Chat extends Mammifere { ... } class Chien extends Mammifere { ... } Considrons dautre part une mthode qui prend pour argument une liste de mammif`res : e e e void uneMethode(List<Mammifere> menagerie) { ... } et envisageons divers appels possibles de cette mthode : e void uneAutreMethode() { List<Animal> listeAnimaux = new Vector<Animal>(); List<Mammifere> listeMammiferes = new Vector<Mammifere>(); List<Chat> listeChats = new Vector<Chat>(); code qui ins`re des lments dans les listes prcdentes e ee e e uneMethode(listeMammiferes); uneMethode(listeAnimaux); uneMethode(listeChats); } Lappel (a) est correct. Lappel (b) est erron et ce nest pas une surprise : une liste danimaux pouvant e contenir des poissons ou des oiseaux ne peut pas prendre la place dune liste de mammif`res. Ce qui est e peut-tre surprenant est que lappel (c) soit incorrect galement : pour comprendre pourquoi il sut de e e raliser que uneMethode peut contenir linstruction (lgitime, dapr`s la dclaration de menagerie) : e e e e menagerie.add(new Chien()); Ce serait tout ` fait incohrent de laisser faire lajout dun chien dans une liste de chats ! a e Jokers Bon, daccord, une liste de chats nest pas une liste de mammif`res. Mais alors, comment faire pour e quune mthode puisse prendre pour argument aussi bien une liste de mammif`res quune liste de chats, ou e e une liste de chiens, etc. ? Ou bien, comment signier que largument dune mthode est, par exemple, une e liste dune sorte de mammif`res ? e Les syntaxes nouvelles ? (signiant une classe quelconque) et ? extends uneClasse (signiant une sous-classe quelconque de uneClasse ) ont t introduites ` cet eet. Exemple : ee a void uneMethode(List<? extends Mammifere> menagerie) { ... } Maintenant, lappel (c) qui posait probl`me est devenu lgal : e e void uneAutreMethode() { ... uneMethode(listeMammiferes); uneMethode(listeAnimaux); uneMethode(listeChats); ... } (a) (b) (c) OK ERREUR ERREUR

// OK // ERREUR // OK

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

168

c H. Garreta, 2000-2010

12

JAVA 5

12.5

Gnricit e e e

void uneMethode(List<? extends Mammifere> menagerie) { ... Mammifere mam = menagerie.get(i); // Pas de probl`me : ce qui sort de la liste peut e ... // certainemnt tre vu comme un Mammifere e menagerie.add(new Chien()); ... } Symtrique de la prcdente, la syntaxe nouvelle ? super uneClasse (signiant une super-classe e e e quelconque de uneClasse ) permet, par exemple, de dnir des listes quon pourra modier ` laide dobjets e a de type uneClasse : void uneTroisiemeMethode(List<? super Mammifere> menagerie) { ... } Les appels lgitimes ne seront pas les mmes que prcdemment : e e e e void uneAutreMethode() { ... uneTroisiemeMethode(listeMammiferes); uneTroisiemeMethode(listeAnimaux); uneTroisiemeMethode(listeChats); ... } // ERREUR (ben oui, menagerie est peut-tre e // une liste de chats... !)

// OK // OK // ERREUR

Ce quil est permis de faire ` lintrieur de la mthode change aussi : a e e void uneTroisiemeMethode(List<? super Mammifere> menagerie) { ... Mammifere mam = menagerie.get(i); // ERREUR ( menagerie est peut-tre e ... // une liste de simples animaux) ... menagerie.add(new Chien()); // Pas de probl`me : un chien peut certainement e ... // prendre la place dun lment de menagerie ee } 12.5.4 Limitations de la gnricit e e e

Cette section obscure et incertaine peut tre ignore en premi`re lecture. e e e Contrairement ` dautres langages, comme C++, o` les classes gnriques sont instancies dabord et a u e e e compiles ensuite, en Java les classes gnriques sont compiles dabord et pour autant que cela veuille e e e e dire quelque chose instancies plus tard. Dautre part, on nous assure que la machine virtuelle Java na e pas subi la moindre modication lors de lintroduction de la gnricit dans le langage. e e e Cela explique pourquoi certaines oprations impliquant des types param`tres sont possibles, et dautres e e non. Pour le dire simplement : un type param`tre T ne peut tre employ que pour crire des expressions e e e e qui peuvent tre compiles sans conna e e tre les dtails prcis (structure, taille, mthodes...) du type que T e e e reprsente 119 . Ainsi, un type param`tre peut tre utilis : e e e e dans des dclarations de membres, de variables locales ou darguments formels, e dans des conversions de type (casts). En revanche, un type param`tre ne peut pas tre employ e e e en reprsentation dun type primitif, e comme type des lments dans la dnition dun tableau, ee e intervenant dans la dnition dun membre statique, e en position de constructeur dune classe, comme dans new T() , dans une comparaison comme T == une classe dans le rle dun objet (instance de la classe Class), comme dans T.getName() o A titre dexemple, voici quelques bons et mauvais usages des types param`tres : e
119. Si cela vous aide, dites-vous que le code produit par la compilation dune classe paramtre est le mme que celui quon e e e aurait obtenu si on avait remplac tous les types param`tres par Object en faisant abstraction des avertissements et erreurs e e ` propos des types que cela aurait soulev. a e

c H. Garreta, 2000-2010

169

12.5

Gnricit e e e

12

JAVA 5

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`me e // *** ERREUR *** // OK // *** ERREUR *** // Tr`s bien e

// Parfait (du moins pour la compilation)

// *** ERREUR ***

// *** ERREUR ***

12.5.5

Mthodes gnriques e e e

Comme les classes paramtres, les mthodes peuvent elles aussi dpendre dune liste de types param`tres. e e e e e Ces param`tres, encadrs par les signes < >, doivent tre placs immdiatement devant le type du rsultat e e e e e e de la mthode, selon le schma suivant : e e qualieurs < types-param`tres > type-du-rsultat nom-mthode ( arguments ) e e e Par exemple, la mthode suivante prend pour arguments une liste dobjets dun certain type T, un type e inconnu durant la compilation, et renvoie llment qui est au milieu de la liste ; largument est donc de type ee List<T> et le rsultat de type T : e

public static <T> T elementCentral(List<T> liste) { int n = liste.size(); if (n > 0) return liste.get(n / 2); else return null; } Tr`s souvent 120 , les types param`tres des mthodes gnriques apparaissent dans les types de leurs e e e e e arguments formels (cest le cas dans la mthode ci-dessus). Elles ont alors cette particularit : pour les e e instancier il sut de les appeler ; le compilateur dduit les types param`tres des arguments eectifs gurant e e dans lappel. Exemples dappels de la mthode prcdente (les variables i et s ont t dclares par ailleurs) : e e e ee e e

120. Il nest pas formellement requis que les types param`tres dune mthode paramtre apparaissent dans les dclarations e e e e e des arguments. Cependant, ` lusage, on saperoit que cela est une obligation de fait pour obtenir des mthodes correctes et a c e utiles.

170

c H. Garreta, 2000-2010

12

JAVA 5

12.5

Gnricit e e e

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 mthode elementCentral le compie lateur aura pris T Integer et, lors du deuxi`me, T String. e Un autre exemple de mthode gnrique a t donne par la mthode makeInstance de la classe Paire e e e ee e e (cf. page 166) : 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`res de construire des paires dobjets : soit en explicitant les types des e membres de la paire (la variable p a t dclare par ailleurs) : ee e e p = new Paire<Double, String>(246.5, "Km"); soit en laissant le compilateur dduire ces types des arguments dun appel de makeInstance : e p = Paire.makeInstance(246.5, "Km");

c H. Garreta, 2000-2010

171

Index
+ (concatnation de cha e nes), 21 .TYPE, 73 .class, 73 = (copie supercielle), 17 == (comparaison supercielle), 20 abs, 62 abstract, 51, 52 AbstractCollection, 66 AbstractList, 66 AbstractMap, 67 AbstractSequentialList, 66 AbstractSet, 67 AbstractTableModel, 134 abstraite (classe), 52 abstraite (mthode), 51 e acos, 63 ActionListener, 111 actionPerformed, 111 Adaptateurs, 108 add, 70 addActionListener, 126 addMouseListener, 107 AdjustmentListener, 113 adjustmentValueChanged, 113 aiguillage et type numr, 150 e e e algorithme, 70 analyse lexicale, 81 annotations, 160 anonyme (classe), 39 anonyme (tableau), 15 appendReplacement, 92 appendTail, 92 arguments variables, 157 Array, 73 ArrayIndexOutOfBoundsException, 13 ArrayList, 66, 72 Arrays, 72 asin, 63 asList, 72 assert, 59 AssertionError, 59 atan, 63 atan2, 63 auditeur dvnements, 106 e e AWT, 99 base (classe de), 41 BigDecimal, 64 BigInteger, 63 binarySearch, 7173 bo de dialogue, 101 te boolnne (constante), 9 e Boolean, 62 boolean, 10 BorderFactory, 124 BorderLayout, 121 boucle for amliore, 155 e e break, 23 brut (type), 167 buered image, 144 BufferedInputStream, 75 BufferedOutputStream, 75 BufferedReader, 76 BufferedWriter, 77 Byte, 61 byte, 10 ByteArrayInputStream, 75 ByteArrayOutputStream, 75 caract`re, 9 e case, 150 catch, 56 ceil, 62 CENTER, 121 cha de caract`res (constante), 21 ne e char, 10 Character, 62 CharArrayReader, 76 CharArrayWriter, 77 class, 28 classe, 28 classe drive, 41 e e classe de base, 41 clearRect, 115 clonage, 17 clone, 17 Cloneable, 18 CloneNotSupportedException, 18 Collection, 52, 65, 69 Collections, 70 commentaire, 8 Comparable, 70 comparaison dobjets, 20 Comparator, 70 compare, 70 compareTo, 70 compile, 89, 91 Component, 100 concatnation de cha e nes, 21 constant (membre), 36 constante (littrale), 9 e constante de classe, 36 constructeur, 35, 44 Constructor, 73 Container, 100 contains, 69 containsKey, 70 containsValue, 70 contrle (exception), 58 oe conversion (entre objets), 15, 46 conversion (entre types primitifs), 10 copie dobjet, 17 copy, 72 copyArea, 115 cos, 63

INDEX

INDEX

create, 115 createImage, 146 DataInputStream, 75 DataOutputStream, 75 Date, 86 DateFormat, 86 dballage automatique, 152 e DecimalFormat, 83 DecimalFormatSymbols, 83 DefaultMutableTreeNode, 141 Deprecated, 163 Dialog, 101 directe (sous-classe ou super-classe), 41 DO NOTHING ON CLOSE, 113 Documented, 164 Double, 62 double, 10 double buering, 144 drawArc, 116 drawImage, 116 drawLine, 116 drawOval, 116 drawRect, 116 drawRoundRect, 116 drawString, 116 dynamique (liaison), 42 dynamique (type), 15 E, 62 EAST, 121 emballage automatique, 152 enableassertions, 60 encapsulation, 28 end, 91 enti`re (constante), 9 e entres-sorties, 75 e enum, 148 Enumeration, 69 EnumMap, 150, 151 EnumSet, 151 equals, 20, 22, 73 Error, 57 tiquette, 23 e vnement, 100, 105 e e vnements (thread de traitement), 104 e e event-dispatching thread, 104 excutable (classe), 25 e Exception, 57 exception, 56 exception contrle, 58 oe EXIT ON CLOSE, 103 exp, 62 expression rguli`re, 89 e e extends, 168 extends, 41 false, 9 chier binaire, 78 chier compil, 24 e chier de texte, 79
c H. Garreta, 2000-2010

chier source, 24, 25 Field, 73 File, 78 FileDescriptor, 78 FileInputStream, 75 FileOutputStream, 75 FileReader, 76 FileWriter, 77 fill, 72, 73 FilterInputStream, 75 FilterOutputStream, 75 FilterReader, 76 FilterWriter, 77 final, 36, 50, 51 nal (membre), 36 nale (classe), 51 nale (mthode), 50 e finalize, 37 finally, 56 find, 91 Float, 61 float, 10 floor, 62 ottante (constante), 9 FlowLayout, 120 focusGained, 111 FocusListener, 111 focusLost, 111 for (boucle for amliore), 155 e e Format, 83 formatage de donnes, 83 e forName, 74 Frame, 101 gnralisation, 46 e e gnrique (classe), 165 e e gnrique (mthode), 170 e e e gestionnaire de disposition, 101, 119 get, 70 getActionCommand, 111, 127 getAnnotations, 162 getBounds, 100 getClass, 74 getContentPane, 102, 103 getDeclaredAnnotations, 162 getDefaultToolkit, 145 getImage, 145 getResource, 146 goto, 23 Graphics, 115 Graphics2D, 115 GregorianCalendar, 86 GridBagConstraints, 122 GridBagLayout, 122 GridLayout, 121 HashMap, 67 HashSet, 67 hasMoreElements, 69 hasNext, 68, 160 hasNextBigDecimal, 160 173

INDEX

INDEX

hasNextBigInteger, 160 hasNextByte, 160 hasNextDouble, 160 hasNextFloat, 160 hasNextInt, 160 hasNextLine, 160 hasNextLong, 160 hasNextShort, 160 hritage, 40, 41 e icne, 143 o identicateur, 8 IdentityHashMap, 68 image, 142 ImageIcon, 144 implements, 52 import, 24, 25 import static, 154 indexOfSubList, 71 Inherited, 164 initialisation dun objet, 34 initialisation dun tableau, 14 InputStream, 75 InputStreamReader, 76 instance, 28 int, 10 Integer, 25, 61 interface, 52, 161 interface-utilisateur graphique, 99 intern, 22 interne (classe), 38 InterruptedException, 94, 97 introspection, 73 intValue, 61 invokeLater, 105 IOException, 57 isAnnotationPresent, 162 isEmpty, 69 ItemListener, 113 itemStateChanged, 113 Iterable, 156 Iterator, 65, 68 jar, 27 jar (chier), 27 java.awt, 99 java.lang, 25 java.lang.AnnotatedElement, 162 java.lang.Class, 73 java.lang.reflect, 73 java.math, 63 java.text, 83 java.util, 64 javadoc, 8 javax.swing, 99 JButton, 128 JCheckBox, 128 JDialog, 128 JFC, 99 JFileChooser, 132 JFrame, 102, 103 174

JMenu, 126 JMenuBar, 126 JMenuItem, 126 jokers (dans les types paramtrs), 167 e e JOptionPane, 130 JRadioButton, 128 JTable, 134 JTextArea, 128 JTextField, 128 JTree, 137 KeyListener, 110 keyPressed, 110 keyReleased, 110 keyTyped, 110 lang, 25 lastIndexOfSubList, 71 layout manager, 101, 119 length, 13 liaison dynamique, 42 liaison statique, 42 LineNumberReader, 76 LinkedHashMap, 68 LinkedHashSet, 67 LinkedList, 66 List, 65, 70 list, 72 listener, 100, 106 Long, 61 long, 10 main, 25 MANIFEST.MF, 27 manifeste (chier), 27 Map, 65, 70 masquage dun membre, 42 Matcher, 89 matcher, 90, 91 matches, 90 Math, 25, 62 max, 62, 71 membre dinstance, 29 message, 28 mta-donnes, 160 e e Method, 73 mthode, 28 e mthode dinstance, 29 e mthode de classe, 31 e mthode virtuelle, 48 e min, 62, 71 mod`le-vue-contrleur, 136 e o modale (bo de dialogue), 102 te mode immdiat (mod`le), 142 e e MouseAdapter, 108 mouseClicked, 107, 110 mouseDragged, 110 mouseEntered, 107, 110 mouseExited, 107, 110 MouseListener, 107, 109 MouseMotionListener, 110
c H. Garreta, 2000-2010

INDEX

INDEX

mouseMoved, 110 mousePressed, 107, 110 mouseReleased, 107, 110 MutableTreeNode, 140 name, 149 nCopies, 72 new, 11, 12, 14, 35 next, 68 nextBigDecimal, 159 nextBigInteger, 159 nextByte, 159 nextDouble, 159 nextElement, 69 nextFloat, 159 nextInt, 159 nextLine, 159 nextLong, 159 nextShort, 159 NORTH, 121 notifyAll, 97 null, 12 NullPointerException, 13 NumberFormat, 83 Object, 42 Object (classe), 25 ObjectInputStream, 75 ObjectOutputStream, 75 objet, 28 observateur dune image, 142 ordinal, 149 OutputStream, 75 OutputStreamWriter, 77 Override, 163 pack, 103, 104 package, 24, 25 paint, 100, 115 paquet de classes, 24 paquets et rpertoires, 26 e paramtr (type), 165 e e paramtre (classe), 165 e e param`tre (type), 165 e parseInt, 25, 61 particularisation, 46 passage par rfrence, 12 ee passage par valeur, 12 Pattern, 89 PI, 62 PipedInputStream, 75 PipedOutputStream, 75 PipedReader, 76 PipedWriter, 77 Pixel, 41 Point, 41 polymorphisme, 46 pow, 63 primitif (type), 10 printf, 158 PrintStream, 75
c H. Garreta, 2000-2010

PrintWriter, 77 priv (membre), 33 e private, 33 processus lger, 93 e producteur-consommateur, 97 protg (membre), 33 e e protected, 33, 45 public, 25, 29, 33 public (membre), 33 publique (classe), 25 PushbackInputStream, 75 PushbackReader, 76 put, 70 random, 62 RandomAccessFile, 78 Reader, 76 recherche (algorithme), 71 recherche des mthodes, 42 e rednition des mthodes, 32, 43 e e rednition et surcharge, 32, 43 e rfrence, 11 ee r`gle du thread unique, 104 e rguli`re (expression), 89 e e relation dordre, 70 remove, 70 rpertoires et paquets, 26 e replaceAll, 72, 92 Retention, 164 reverse, 72 reverseOrder, 71 rint, 62 rotate, 72 round, 62 run, 93 Runnable, 93 RuntimeException, 57 Scanner, 159 smantique des rfrences, 11 e ee smantique des valeurs, 11 e SequenceInputStream, 75 srialisation, 87 e Set, 65, 70 set, 70 setBorder, 124 setDefaultCloseOperation, 103 setJMenuBar, 126 setLayout, 120 setResizable, 120 setSize, 100, 102, 103 setVisible, 101104 Short, 61 short, 10 show, 104 shuffle, 72 sin, 63 singleton, 72 singletonList, 72 singletonMap, 72 size, 69 175

INDEX

INDEX

sleep, 94 sort, 71, 73 SortedMap, 66 SortedSet, 65 sous-classe, 41 SOUTH, 121 split, 89 Stack, 67 start, 91, 93, 98 static, 30 statique (liaison), 42 statique (type), 15 stop, 95 StreamTokenizer, 78 String, 21, 25 StringBuffer, 21 StringReader, 76 StringWriter, 77 super, 42, 169 super(), 44 super-classe, 41 SuppressWarnings, 163 surcharge dun membre, 42 surcharge des mthodes, 32 e surcharge et rednition, 32 e swap, 72 Swing, 99 SwingUtilities, 105 switch, 150 symboliques, donnes, 148 e synchronized, 96 synchronizedCollection, 72 synchronizedList, 72 synchronizedMap, 72 System, 25 tableau, 12 tan, 63 Target, 164 TextListener, 113 textValueChanged, 113 this, 30, 35, 36 this(), 36 Thread, 93 thread, 93 thread safe (mthode), 104 e throw, 57 Throwable, 57 throws, 57 Toolkit, 145 toString, 21, 43, 48 transient, 87 translate, 117 TreeMap, 68 TreeModel, 140 TreeNode, 139 TreeSet, 67 tri (algorithme), 71 true, 9 try, 56 type primitif, 10 176

Unicode, 8 unit de compilation, 24 e unmodifiableMap, 72 unmodifiableCollection, 72 unmodifiableList, 72 UnsupportedOperationException, 69 valueOf, 21, 61, 62, 149 values, 149 variable (type), 165 variable dinstance, 28, 29 variable de classe, 31 variables (listes darguents), 157 Vector, 66 virtuelle (mthode), 48 e wait, 97 WeakHashMap, 68 WEST, 121 Window, 101 windowActivated, 113 windowClosed, 113 windowClosing, 113 windowDeactivated, 113 windowDeiconified, 113 windowIconified, 113 WindowListener, 113 windowOpened, 113 Writer, 77

c H. Garreta, 2000-2010

You might also like