Cours JAVA

Support cours pour tout savoir sur Java


Télécharger Support cours pour tout savoir sur Java

★★★★★★★★★★2 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Télécharger aussi :


D?veloppons en Java Développons en Java
Jean Michel DOUDOUX

Table des matières


 Historique des versions...........................................................................................................................................3


 1.3. Les différentes éditions de Java.......................................................................................................................8
 1.3.8. Les extensions du JDK.........................................................................................................................10
 1.6. L'installation du JDK......................................................................................................................................12
 1.6.4. Les éléments du JDK 1.3 sous Windows.............................................................................................16

2.2. L'exécution d'un programme et d'une applet...................................................................................................18
2.2.2. L'exécution d'une applet........................................................................................................................19

3.4. La déclaration et l'utilisation de variables.......................................................................................................21
3.4.1. La déclaration de variables...................................................................................................................21
3.4.6. Les comparaisons..................................................................................................................................25
3.5. Les opérations arithmétiques...........................................................................................................................25
3.5.1. L'arithmétique entière...........................................................................................................................25
3.5.3. L'incrémentation et la décrémentation..................................................................................................27
3.7. Les structures de contrôles..............................................................................................................................28
3.7.3. Les débranchements..............................................................................................................................30
3.8. Les tableaux.....................................................................................................................................................30
3.8.2. L'initialisation explicite d'un tableau....................................................................................................31
Développons en Java
?630

Table des matières

3.8.3. Le parcours d'un tableau.......................................................................................................................32
3.9. Les conversions de types.................................................................................................................................32
3.9.3. La conversion d'un entier int en entier long..........................................................................................33
3.10. La manipulation des chaines de caractères...................................................................................................33
3.10.5. La modification de la casse d'une chaine............................................................................................35

4.1. Le concept de classe........................................................................................................................................36
4.1.1. La syntaxe de déclaration d'une classe..................................................................................................37
4.2. Les objets.........................................................................................................................................................37
4.2.8. L'opérateur instanceof...........................................................................................................................41
4.3. Les modificateurs d'accès................................................................................................................................41
4.3.7. Le mot clé native...................................................................................................................................44
4.4. Les propriétés ou attributs...............................................................................................................................44
4.4.3. Les constantes.......................................................................................................................................45
4.5. Les méthodes...................................................................................................................................................45
4.5.9. Les accesseurs.......................................................................................................................................49
4.6. L'héritage.........................................................................................................................................................49
4.6.7. Des conseils sur l'héritage.....................................................................................................................52
4.7. Les packages...................................................................................................................................................52
4.7.3. La collision de classes...........................................................................................................................54
Développons en Java
?629

Table des matières

4.7.4. Les packages et l'environnement système.............................................................................................54
4.8. Les classes internes.........................................................................................................................................54
4.8.4. Les classes internes statiques................................................................................................................64
4.9. La gestion dynamique des objets....................................................................................................................65

5.1. Présentation du package ..................................................................................................................71
5.1.1. La classe Object....................................................................................................................................71
5.1.1.5. La méthode clone().....................................................................................................................72
5.1.5. La classe System...................................................................................................................................76
5.1.5.2. Les variables d'environnement et les propriétés du système......................................................76
5.1.6. La classe Runtime.................................................................................................................................78
5.2. Présentation rapide du package awt java.........................................................................................................78
5.2.2. Le package ......................................................................................................................79
5.4. Le package .........................................................................................................................................79
5.4.2. La classe Random.................................................................................................................................80
5.4.7. Les expressions régulières....................................................................................................................84
5.4.7.1. Les motifs...................................................................................................................................84
5.4.7.2. La classe Pattern.........................................................................................................................86
5.4.7.3. La classe Matcher.......................................................................................................................87
5.5. Présentation rapide du package .........................................................................................................89
5.6. Présentation rapide du package java.applet.....................................................................................................89

6.3. Les fonctions de comparaisons.......................................................................................................................90
6.4. Les arrondis.....................................................................................................................................................91
6.4.3. La méthode floor(double).....................................................................................................................92
6.4.4. La méthode ceil(double).......................................................................................................................92
6.4.5. La méthode abs(x).................................................................................................................................93
6.6. Les Exponentielles et puissances....................................................................................................................93
6.6.1. La méthode pow(double, double).........................................................................................................93
6.6.3. La méthode exp(double).......................................................................................................................94
6.6.4. La méthode log(double)........................................................................................................................94
6.7. La génération de nombres aléatoires...............................................................................................................95
Développons en Java
?628

Table des matières

6.7.1. La méthode random()............................................................................................................................95

7.4. Les exceptions personnalisées.........................................................................................................................99

8.3. La création et l'exécution d’un thread...........................................................................................................104
8.3.3. Modification de la priorité d’un thread...............................................................................................106
8.6. Exclusion mutuelle........................................................................................................................................108
 8.6.4. La synchronisation : les méthodes wait() et notify()..........................................................................109


9.1. Les opérations sur le contexte graphique......................................................................................................111
9.1.7. La copier une aire rectangulaire..........................................................................................................113

10.1. Les composants graphiques.........................................................................................................................115
10.1.12. La classe Canvas.............................................................................................................................128
10.3. Les conteneurs.............................................................................................................................................130
10.3.4. Le conteneur Dialog..........................................................................................................................133
10.4. Les menus....................................................................................................................................................134
10.4.2. Les méthodes de la classe Menu.......................................................................................................136
Développons en Java
?627

Table des matières

10.4.4. Les méthodes de la classe CheckboxMenuItem...............................................................................137

11.2. Le positionnement des composants.............................................................................................................139
11.2.5. La mise en page GridBagLayout......................................................................................................145
11.5. Afficher une image dans une application....................................................................................................147

12.2. Intercepter les actions de l'utilisateur avec Java version 1.1.......................................................................148
12.2.6. Les différentes implémentations des Listener...................................................................................154
12.2.6.4. Une classe interne anonyme....................................................................................................156
12.2.7. Résumé..............................................................................................................................................157

13.4. Les composants Swing................................................................................................................................160
13.4.1. La classe JFrame...............................................................................................................................160
13.4.1.4. Les évenements associées à un JFrame..................................................................................165
13.4.3. Les panneaux : la classe Jpanel.........................................................................................................168
13.5. Les boutons.................................................................................................................................................168
13.5.6. Les boutons radio : la classe JRadioButton......................................................................................173

14.1. L'intégration d'applets dans une page HTML.............................................................................................174
14.2. Les méthodes des applets............................................................................................................................175
14.2.5. La méthode update().........................................................................................................................175
Développons en Java
?626

Table des matières

14.2.7. Les méthodes size() et getSize().......................................................................................................177
14.2.14. La méthode setStub()......................................................................................................................178
14.3. Les interfaces utiles pour les applets...........................................................................................................179
14.3.3. L'interface MouseListener pour répondre à un clic de souris...........................................................179
14.5. Applet et le multimédia...............................................................................................................................180
14.5.3. Animation d'un logo..........................................................................................................................182
14.7. Les droits des applets..................................................................................................................................184


15.2. Les interfaces des collections......................................................................................................................187
15.2.2. L'interface Iterator.............................................................................................................................189
15.3. Les listes......................................................................................................................................................190
15.3.4. Les tableaux redimensionnables : la classe ArrayList......................................................................192
15.4. Les ensembles.............................................................................................................................................193
15.4.4. La classe TreeSet..............................................................................................................................194
15.5. Les collections gérées sous la forme clé/valeur..........................................................................................195
15.5.5. La classe HashMap...........................................................................................................................197
15.6. Le tri des collections...................................................................................................................................197
15.6.2. L'interface Comparator.....................................................................................................................198
15.8. Les exceptions du framework.....................................................................................................................200

16.3. Les flux de caractères..................................................................................................................................203
16.3.3. Les flux de caractères avec un fichier...............................................................................................205
16.3.3.1. Les flux de caractères en lecture sur un fichier.......................................................................205
Développons en Java
?625

Table des matières

16.3.3.2. Les flux de caractères en écriture sur un fichier.....................................................................206
16.3.4. Les flux de caractères tamponnés avec un fichier.............................................................................206
16.3.4.3. La classe PrintWriter...............................................................................................................209
16.4. Les flux d'octets...........................................................................................................................................210
16.4.1. Les flux d'octets avec un fichier........................................................................................................211
16.4.1.2. Les flux d'octets en écriture sur un fichier..............................................................................212
16.4.2. Les flux d'octets tamponnés avec un fichier.....................................................................................213
16.6. Les fichiers à accès direct............................................................................................................................216

17.1. Les classes et les interfaces de la sérialisation............................................................................................218
17.1.3. La classe ObjectInputStream............................................................................................................220
17.3. La sérialisation personnalisée......................................................................................................................222
17.3.1. L'interface Externalizable.................................................................................................................222

18.2. Les adresses internet....................................................................................................................................224
18.2.1. La classe InetAddress........................................................................................................................224
18.3. L'accès aux ressources avec une URL.........................................................................................................225
18.3.4. La classe HttpURLConnection.........................................................................................................228
18.4. Utilisation du protocole TCP.......................................................................................................................228
18.4.2. La classe Socket................................................................................................................................231
18.5. Utilisation du protocole UDP......................................................................................................................232
18.5.3. Un exemple de serveur et de client...................................................................................................233
18.7. Les interfaces de connexions au réseau.......................................................................................................235

19.5. La connection à une base de données..........................................................................................................241
19.5.2. L'établissement de la connection.......................................................................................................241
19.6. Accéder à la base de données......................................................................................................................242
19.6.3. Exemple complet de mise à jour et de sélection sur une table..........................................................245
19.7. Obtenir des informations sur la base de données........................................................................................247
19.7.2. La classe DatabaseMetaData............................................................................................................247
19.9. L'utilisation des transactions.......................................................................................................................249
Développons en Java
?624

Table des matières

19.12. JDBC 2.0...................................................................................................................................................250
19.12.7. L'API RowSet.................................................................................................................................254
19.14. MySQL et Java..........................................................................................................................................255
19.14.3. Utilisation de MySQL avec java via ODBC...................................................................................257
19.14.3.1. Déclaration d'une source de données ODBC vers la base de données.................................257
19.14.3.2. Utilisation de la source de données.......................................................................................260
19.14.4. Utilisation de MySQL avec java via un pilote JDBC.....................................................................261

20.1. La classe Class............................................................................................................................................263
20.1.1. Obtenir un objet de la classe Class....................................................................................................264
20.1.1.3. Une troisième façon d'obtenir un objet Class.........................................................................265
20.1.2. Les méthodes de la classe Class........................................................................................................265
20.2. Rechercher des informations sur une classe................................................................................................266
20.2.6. Rechercher les constructeurs de la classe.........................................................................................269
20.2.8. Rechercher toutes les méthodes........................................................................................................271
20.3. Définir dynamiquement des objets..............................................................................................................271
20.3.2. Exécuter dynamiquement une méthode............................................................................................272

21.3. Le développement coté serveur...................................................................................................................274
21.3.3. L'écriture d'une classe pour instancier l'objet et l'enregistrer dans le registre...................................275
21.3.3.4. Lancement dynamique du registre de nom RMI.....................................................................276
21.4. Le développement coté client......................................................................................................................277
21.4.4. L'appel d'une méthode distante dans une applet...............................................................................278
21.6. La mise en oeuvre des objets RMI..............................................................................................................279
21.6.1. Le lancement du registre RMI..........................................................................................................279
Développons en Java
?623

Table des matières

21.6.2. L'instanciation et l'enregistrement de l'objet distant.........................................................................280
21.6.3. Le lancement de l'application cliente................................................................................................280

22.1. Les objets de type Locale............................................................................................................................281
22.1.3. L'utilisation d'un objet Locale...........................................................................................................283
22.2. La classe ResourceBundle...........................................................................................................................283
22.2.2. Les sous classes de ResourceBundle................................................................................................284
22.2.2.1. L'utilisation de PropertyResourceBundle...............................................................................284
22.2.2.2. L'utilisation de ListResourceBundle.......................................................................................284
22.2.3. Obtenir un texte d'un objet ResourceBundle.....................................................................................285
22.3. Chemins guidés pour réaliser la localisation...............................................................................................285
22.3.6. Exemple de classes utilisant une classe fille de ResourceBundle.....................................................291

23.1. Présentations des java beans.......................................................................................................................294
23.2. Les propriétés..............................................................................................................................................295
23.2.4. Les propriétés liées avec contraintes (Constrained properties).........................................................298
23.5. L'introspection.............................................................................................................................................300
23.5.2. La classe BeanInfo............................................................................................................................301
23.9. Le B.D.K.....................................................................................................................................................304

24.1. Log4j...........................................................................................................................................................305
24.1.1. Les catégories....................................................................................................................................305
24.1.1.2. Les priorités............................................................................................................................307
24.1.4. La configuration................................................................................................................................309
24.2. L'API logging..............................................................................................................................................311
24.2.2. La classe Logger...............................................................................................................................312
24.2.9. Exemples d'utilisation.......................................................................................................................313
24.3. D'autres API de logging..............................................................................................................................313
Développons en Java
?622

Table des matières

25.2. La sécurité dans les spécifications du langage............................................................................................315
25.2.1. Les contrôles lors de la compilation.................................................................................................315
25.2.2. Les contrôles lors de l'exécution.......................................................................................................316
25.3. Le contrôle des droits d’une application.....................................................................................................316
25.3.3. Le modèle Java 1.2............................................................................................................................316
25.4. JCE (Java Cryptography Extension)...........................................................................................................317
25.4.1. La classe Cipher................................................................................................................................317
25.5. JSSE (Java Secure Sockets Extension).......................................................................................................317
25.6. JAAS (Java Authentication and Authorization Service).............................................................................317


26.1. Les API de J2EE.........................................................................................................................................320
26.2. L'environnement d'éxécution des applications J2EE..................................................................................321
26.2.4. Les services proposés par la plateforme J2EE..................................................................................322
26.3. L'assemblage et le déploiement d'applications J2EE..................................................................................322
26.3.3. Les limitations des fichiers EAR......................................................................................................323

27.1. Présentation des servlets..............................................................................................................................324
27.1.2. Les outils nécessaires pour développer des servlets.........................................................................325
27.1.4. Les différences entre les servlets et les CGI.....................................................................................326
27.2. L'API servlet................................................................................................................................................326
27.2.3. Un exemple de servlet.......................................................................................................................328
27.4. Les servlets http...........................................................................................................................................330
27.4.6. Un exemple de servlet HTTP très simple.........................................................................................334
27.5. Les informations sur l'environnement d'execution des servlets..................................................................335
27.5.3. Les informations contenues dans la requète.....................................................................................337
27.6. La mise en oeuvre des servlets avec Tomcat..............................................................................................339
27.6.1. Installation de tomcat........................................................................................................................339
27.6.1.2. L'installation de tomcat 4.0 sur Windows 98..........................................................................340
27.6.2. L'utilisation avec Jbuilder 3.0...........................................................................................................343
27.6.2.4. Le test de la servlet.................................................................................................................352
Développons en Java
?621

Table des matières

27.7. L'utilisation des cookies..............................................................................................................................353
27.7.1. La classe Cookie...............................................................................................................................353
27.7.2. L'enregistrement et la lecture d'un cookie.........................................................................................353
27.9. Packager une application web.....................................................................................................................354
27.9.3. Le déploiement d'une application web..............................................................................................357

28.1. Présentation des JSP....................................................................................................................................358
28.1.2. JSP et les technologies concurrentes.................................................................................................359
28.2. Les outils nécessaires..................................................................................................................................359
28.2.2. Tomcat..............................................................................................................................................361
28.4. Les Tags JSP...............................................................................................................................................361
28.4.1. Les tags de directives <%@ ... %>...................................................................................................362
28.4.1.3. La directive taglib...................................................................................................................364
28.4.2. Les tags de scripting..........................................................................................................................365
28.4.2.4. Le tag des scriptlets <% ... %>...............................................................................................367
28.4.3. Les tags de commentaires.................................................................................................................368
28.4.3.2. Les commentaires cachés <%?? ... ??%>.............................................................................369
28.4.4. Les tags d'actions..............................................................................................................................369
28.4.4.6. Le tag <jsp:plugin>.................................................................................................................375
28.6. La gestion des erreurs..................................................................................................................................376
28.6.1. La définition d'une page d'erreur.......................................................................................................376
28.7. Les bibliothèques de tag personnalisées (custom taglibs)...........................................................................377
28.7.5. Les deux types de handlers...............................................................................................................380
28.7.5.2. Les handlers de tags avec corps..............................................................................................380
28.7.8. Utilisation d'une bibliothèque de tags...............................................................................................383
28.7.8.2. Déploiement d'une bibliothèque.............................................................................................384
28.7.9. Déploiement et tests dans Tomcat....................................................................................................385
28.7.9.3. Test..........................................................................................................................................385
28.7.10. Les bibliothèques de tags existantes...............................................................................................385
Développons en Java
?620

Table des matières

28.7.10.3. JSP Standard Tag Library (JSTL).........................................................................................386

29.4. La bibliothèque Core...................................................................................................................................391
29.4.10. Le tag redirect.................................................................................................................................400
29.4.11. Le tag url.........................................................................................................................................401
29.5. La bibliothèque XML..................................................................................................................................401
29.5.7. Le tag transform................................................................................................................................405
29.6. La bibliothèque I18n...................................................................................................................................406
29.6.7. Le tag formatDate.............................................................................................................................410
29.6.10. Le tag timeZone..............................................................................................................................411
29.7. La bibliothèque Database............................................................................................................................412
29.7.4. Le tag update.....................................................................................................................................415

30.1. Présentation et utilité...................................................................................................................................417
30.1.2. Le modèle MVC2..............................................................................................................................418
30.2. Struts............................................................................................................................................................418
 30.3.2. Le développement des vues.............................................................................................................419
 30.3.4. Le développement de la partie contrôleur........................................................................................420
30.6. Turbine........................................................................................................................................................421
Développons en Java
?619

Table des matières

30.10. Velocity.....................................................................................................................................................421

31.5. L'utilisation de SAX....................................................................................................................................424
31.5.2. L'utilisation de SAX de type 2..........................................................................................................431
31.6. DOM............................................................................................................................................................432
31.6.1. Les interfaces du DOM.....................................................................................................................433
31.6.1.2. L'interface NodeList...............................................................................................................434
31.6.1.8. L'interface Text.......................................................................................................................436
31.6.3. Parcours d'un arbre DOM.................................................................................................................437
31.6.3.1. Les interfaces Traversal..........................................................................................................437
31.6.4. Modifier un arbre DOM....................................................................................................................438
31.6.4.2. L'ajout d'un élément................................................................................................................438
31.6.5. Envoyer un arbre DOM dans un flux................................................................................................440
31.6.5.1. Exemple avec Xerces..............................................................................................................440
31.8. JAXP : Java API for XML Parsing.............................................................................................................442
31.8.2. L'utilisation de JAXP avec un parseur de type SAX........................................................................443
31.9. XSLT (Extensible Stylesheet Language Transformations).........................................................................443
31.9.2. La syntaxe de XSLT.........................................................................................................................444
31.9.4. Exemple avec Xalan 2.......................................................................................................................445
31.11. JDOM........................................................................................................................................................447
31.11.8. La sortie de document.....................................................................................................................452
31.12. dom4j.........................................................................................................................................................453
31.12.6. Exporter le document......................................................................................................................456
31.13. Jaxen..........................................................................................................................................................458
Développons en Java
?618

Table des matières

31.14. JAXB.........................................................................................................................................................458
31.14.5. La génération d'un document XML................................................................................................463

32.1. Les concepts de base...................................................................................................................................466
32.1.1. La définition d'un annuaire...............................................................................................................466
32.1.2. Le protocole LDAP...........................................................................................................................466
32.3. Utilisation de JNDI avec un serveur LDAP................................................................................................466

33.3. Le package ..................................................................................................................................468
33.3.4. Les messages.....................................................................................................................................470
33.3.4.3. Le corps du message...............................................................................................................471
33.3.6. La réception de messages..................................................................................................................472
33.4. L'utilisation du mode point à point (queue)................................................................................................472
33.4.3. La session : l'interface QueueSession...............................................................................................473
33.4.7. La réception de messages : l'interface QueueReceiver.....................................................................474
33.4.7.3. La sélection de messages........................................................................................................475
33.5. L'utilisation du mode publication/abonnement (publish/souscribe)............................................................476
33.5.7. La réception de messages : l'interface TopicSubscriber...................................................................477
33.6. Les exceptions de JMS................................................................................................................................478

34.2. Les principaux protocoles...........................................................................................................................480
34.2.2. POP...................................................................................................................................................480
34.2.4. NNTP................................................................................................................................................480
34.3. Les principales classes et interfaces de l'API JavaMail..............................................................................480
34.3.2. Les classes Address, InternetAddress et NewsAddress....................................................................481
Développons en Java
?617

Table des matières

34.3.6. La classe Transport...........................................................................................................................485
34.3.10. La classe Authenticator...................................................................................................................486
34.6. Les fichiers de configuration.......................................................................................................................488
34.6.2. Les fichiers  et .................................................489

35.3. Un exemple avec lido..................................................................................................................................491
35.3.4. La définition d'un fichier metadata...................................................................................................493
35.3.7. L'exécution de l'exemple...................................................................................................................495
...............................................................................................................................497
36.1. Présentation des EJB...................................................................................................................................497
36.1.3. L'interface remote.............................................................................................................................499
36.1.4. L'interface home................................................................................................................................500
36.2. Les EJB session...........................................................................................................................................501
36.2.2. Les EJB session avec état..................................................................................................................503
36.4. Les outils pour développer et mettre oeuvre des EJB.................................................................................504
36.4.2. Les serveurs d'EJB............................................................................................................................504
36.4.2.1. Jboss........................................................................................................................................504
36.5. Le déploiement des EJB..............................................................................................................................504
36.5.2. Le mise en package des beans...........................................................................................................505
36.6. L'appel d'un EJB par un client.....................................................................................................................505
36.6.1. Exemple d'appel d'un EJB session....................................................................................................505
36.7. Les EJB orientés messages..........................................................................................................................506

37.2. Les technologies utilisées............................................................................................................................507
37.2.2. WSDL...............................................................................................................................................509
37.2.3. UDDI.................................................................................................................................................509
37.3. Les API Java liées à XML pour les services web.......................................................................................509
37.3.4. JAXR.................................................................................................................................................511
Développons en Java
?616

Table des matières

37.4. Mise en oeuvre avec JWSDP......................................................................................................................511
37.4.4. L'utilisation du JWSDP Registry Server...........................................................................................515
37.5. Mise en oeuvre avec Axis...........................................................................................................................516
37.5.3. L'utilisation d'un service web par un client.......................................................................................519


38.1. Le compilateur javac...................................................................................................................................522
38.1.2. Les options de javac..........................................................................................................................523
38.2. L'interpréteur java/javaw.............................................................................................................................523
38.2.2. Les options de l'outil java..................................................................................................................524
38.3. L'outil JAR..................................................................................................................................................524
38.3.5. L'extraction du contenu d'une archive jar.........................................................................................527
38.3.8. La signature d'une archive jar...........................................................................................................528
38.5. Pour générer la documentation : l'outil javadoc..........................................................................................530
38.5.2. Les options de javadoc......................................................................................................................530

39.1. Les environnements de développements intégrés (IDE).............................................................................531
39.1.7. Le projet Eclipse...............................................................................................................................533
39.1.9. Omnicore CodeGuide.......................................................................................................................534
39.1.10. IntelliJ IDEA...................................................................................................................................534
39.2. Les serveurs d'application...........................................................................................................................534
39.2.6. Oracle 9i Application Server.............................................................................................................535
39.3. Les conteneurs web.....................................................................................................................................535
39.3.3. Enhydra.............................................................................................................................................536
39.4. Les conteneurs d'EJB..................................................................................................................................536
39.4.1. JBoss.................................................................................................................................................536
Développons en Java
?615

Table des matières

39.4.3. OpenEJB...........................................................................................................................................537
39.5. Les outils divers..........................................................................................................................................537
39.5.5. Artistic Style.....................................................................................................................................538
39.5.9. Junit...................................................................................................................................................539
39.6. Les MOM....................................................................................................................................................539
39.6.3. OSMQ...............................................................................................................................................539

40.3. Les tags définis par javadoc........................................................................................................................542
40.3.9. Le tag @version................................................................................................................................545
40.4. Les fichiers pour enrichir la documentation des packages..........................................................................546

41.11. Le diagramme de déploiement..................................................................................................................553

42.2. Les fichiers..................................................................................................................................................554
42.2.6. La déclaration des classes et des interfaces......................................................................................556
42.3. La documentation du code..........................................................................................................................556
42.3.1. Les commentaires de documentation................................................................................................556
42.3.1.2. Les commentaires pour une classe ou une interface...............................................................557
Développons en Java
?614

Table des matières

42.3.1.4. Les commentaires pour une méthode.....................................................................................557
42.3.2. Les commentaires de traitements......................................................................................................558
42.3.2.4. Les commentaires de fin de ligne...........................................................................................559
42.4. Les déclarations...........................................................................................................................................560
42.4.4. Les conventions de nommage des entités.........................................................................................562
42.5. Les séparateurs............................................................................................................................................563
42.5.2. Les lignes blanches...........................................................................................................................564
42.5.4. La coupure de lignes.........................................................................................................................565
42.6. Les traitements............................................................................................................................................565
42.6.8. Les instructions try?catch.................................................................................................................567
42.7. Les règles de programmation......................................................................................................................567
42.7.8. La déclaration d'un tableau...............................................................................................................569

43.2. Les modèles de création..............................................................................................................................570
43.2.5. Singleton (Singleton)........................................................................................................................571
43.4. Les modèles de comportement....................................................................................................................573

44.1. Installation...................................................................................................................................................575
44.1.2. Installation sous Linux......................................................................................................................576
44.3. Le fichier .....................................................................................................................................576
44.3.5. Les chemins.......................................................................................................................................578
Développons en Java
?613

Table des matières

44.3.7. Les taches..........................................................................................................................................579

45.1. JUnit............................................................................................................................................................580
45.1.2. Exécution des tests avec JUnit..........................................................................................................582
45.1.2.2. Exécution des tests dans une application graphique...............................................................583
45.1.3. Ecriture des cas de tests JUnit...........................................................................................................585
 45.1.3.3. La création et la destruction d'objets......................................................................................588
45.1.6. Les extensions de JUnit.....................................................................................................................590
45.2. Cactus..........................................................................................................................................................590


46.4. J2ME wireless toolkit..................................................................................................................................594
46.4.2. Première exécution............................................................................................................................595

47.5. Le package ...............................................................................................................601

48.3. L'interface utilisateur...................................................................................................................................603
48.3.6. La classe Alert...................................................................................................................................607
 48.5. Le Stockage et la gestion des données.......................................................................................................609
 48.5.1. La classe RecordStore......................................................................................................................609
 48.6. MIDP for Palm O.S....................................................................................................................................611
 48.6.3. Installation et exécution d'une application.......................................................................................614


50.2. Personal Basis Profile (PBP).......................................................................................................................616
Développons en Java
?612

Table des matières

50.3. Personal Profile (PP)...................................................................................................................................617

51.7. Waba, Super Waba, Visual Waba...............................................................................................................620

 Annexe B : Glossaire...........................................................................................................................................625
Développons en Java
?611

Développons en Java
Version 0.70
 du 05/07/2003
 par Jean Michel DOUDOUX
Développons en Java
1

Préambule
A propos de ce document
L'idée de départ de ce document était de prendre des notes relatives à mes premiers essais en Java. Ces notes ont
tellement grossies que j'ai décidé de les formaliser un peu plus et de les diffuser sur internet sous la forme d'un
didacticiel.
Celui?ci est composé de six grandes parties :
les bases du langage java
1. 
développement des interfaces graphiques
2. 
les API avancées
3. 
développement d'applications d'entreprises
4. 
les outils de développement
5. 
développement d'application mobiles
6. 
Chacune de ces parties est composées de plusieurs chapitres.
Je souhaiterais le développer pour qu'il couvre un maximum de sujets autour du développement en Java. Ce souhait est
ambitieux car l'API de Java est très riche et ne cesse de s'enrichir au fil des versions.
Dans chaque partie, les membres des classes décrites ne le sont que partiellement : pour une description complète de
chaque classe, il faut consulter la documentation fournie par Sun au format HTML.
Je suis ouvert à toutes réactions ou suggestions concernant ce document notamment  le signalement des erreurs, les
points à éclaircir, les sujets à ajouter, etc. ... N'hésitez pas à me contacter : jean?
Ce document est disponible aux formats HTML et PDF à l'adresse suivante :
Ce manuel est fourni en l'état, sans aucune garantie. L'auteur ne peut être tenu pour responsable des éventuels dommages
causés par l'utilisation des informations fournies dans ce document.
La version pdf de ce document est réalisée grâce à l'outils HTMLDOC 1.8.14 de la société Easy Software Products. Cet
excellent outil freeware peut être téléchargé à l'adresse :
Notes de licence
Copyright (C) 1999?2003 DOUDOUX Jean Michel
Vous pouvez copier, redistribuer et/ou modifier ce document selon les termes de la Licence de Documentation Libre
GNU, Version 1.1 ou toute autre version ultérieure publiée par la Free Software Foundation; les Sections Invariantes
étant constitués des chapitres :
Développons en Java
• 
Presentation de java
• 
Technique de base de la programmation java
• 
La syntaxe et les éléments de bases de java
• 
POO avec java
• 
Bibliotheque de classes java
• 
Les fonctions mathématiques
• 
La gestion des exceptions
• 
Le multitâche
• 
Le graphisme en java
• 
Les éléments d'interface graphique de l'AWT
• 
La création d'interface graphique avec AWT
• 
Développons en Java
2

L'interception des actions de l'utilisateur
• 
Le développement d'interface graphique avec SWING
• 
Les applets en java
• 
Les collections
• 
Les flux
• 
La sérialisation
• 
L'interaction avec le réseau
• 
L'accès aux bases de données : JDBC
• 
La gestion dynamique des objets et l'introspection
• 
L'appel de méthode distantes : RMI
• 
L'internationalisation
• 
Les composants java beans
• 
Logging
• 
La sécurité
• 
Java 2 Entreprise Edition
• 
Les servlets
• 
Les JSP (Java Servers Pages)
• 
JSTL (Java server page Standard Tag Library)
• 
Les frameworks pour les applications web
• 
Java et XML
• 
JNDI (Java Naming and Directory Interface)
• 
JMS (Java Messaging Service)
• 
JavaMail
• 
JDO (Java Data Object)
• 
Les EJB (Entreprise Java Bean)
• 
Les services web
• 
Les outils du J.D.K.
• 
Les outils libres et commerciaux
• 
JavaDoc
• 
Java et UML
• 
Des normes de développement
• 
Les motifs de conception (design patterns)
• 
Ant
• 
Les frameworks de tests
• 
J2ME
• 
CLDC
• 
MIDP
• 
CDC
• 
Personal Profile
• 
Les autres technologies
• 
Annexes
• 
aucun Texte de Première de Couverture, et aucun Texte de Quatrième de Couverture. Une copie de la licence est incluse
dans la section GNU FreeDocumentation Licence.
La version la plus récente de cette licence est disponible à l'adresse : GNU Free Documentation Licence.
Marques déposées
Sun, Sun Microsystems, le logo Sun et Java sont des marques déposées de Sun Microsystems Inc.
Les autres marques et les noms de produits cités dans ce document sont la propriété de leur éditeur respectif.
Historique des versions
Version Date
Evolutions
Développons en Java
3

0.10
15/01/2001 brouillon : 1ere version diffusée sur le web.
ajout des chapitres JSP et serialization, des informations sur le JDK et son installation,
0.20
11/03/2001 corrections diverses.
0.30
10/05/2001 ajout des chapitres flux, beans et outils du JDK, corrections diverses.
réorganisation des chapitres et remise en page du document au format HTML (1 page par
chapitre) pour faciliter la maintenance
0.40
10/11/2001 ajout des chapitres : collections, XML, JMS, début des chapitres Swing et EJB
séparation du chapitre AWT en trois chapitres.
séparation du document en trois parties
ajout de chapitres : logging, JNDI, java mail, services web, outils du JDK, outils lires et
0.50
31/04/2002 commerciaux, java et UML, motifs de conception
compléments ajoutés aux chapitres : JDBC, javadoc, intéraction avec le réseau, java et xml,
bibliothèques de classes
ajout des chapitres : JSTL, JDO, Ant, les frameworks
0.60
23/12/2002 ajout des sections : java et MySQL, les classes internes, les expressions régulières, dom4j
compléments ajoutés aux chapitres : JNDI, design patterns, J2EE, EJB
ajout d'un index sous la forme d'un arbre hiérarchique affiché dans un frame de la version
HTML
0.65
05/04/2003 ajout des sections : DOM, JAXB, bibliothèques de tags personnalisés, package .war
compléments ajoutés aux chapitres : EJB, réseau, services web
ajout de la partie sur le développement d'applications mobiles contenant les chapitres : J2ME,
CLDC, MIDP, CDC, Personal Profile, les autres technologies
ajout des chapitres : le multitache, les frameworks de tests, la sécurité, les frameworks pour les
app web
0.70
05/07/2003
compléments ajoutés aux chapitres : JDBC, JSP, servlets, intéraction avec le réseau
application d'une feuille de styles CSS pour la version HTML
corrections et ajouts divers
Développons en Java
4

Partie 1 : les bases du langage Java
Cette première partie est chargée de présenter les bases du langage java.
Elle comporte les chapitres suivants :
présentation de java : introduit le langage java en présentant les différentes éditions et versions du JDK, les
• 
caractéristiques du langage et décrit l'installation du JDK
les techniques de base de programmation : présente rapidement comment compiler et executer une application
• 
la syntaxe et les éléments de bases de java : explore les éléments du langage d'un point de vue syntaxique
• 
la programmation orientée objet : explore comment java d'utiliser son orientation objet
• 
la bibliothèque de classes java : propose un présentation rapide des principales API fournies avec le JDK
• 
les fonctions mathématiques : indique comment utiliser les fonctions mathématiques
• 
la gestion des exceptions : traite de la faculté de java de traiter les anomalies qui surviennent lors de l'éxécution
• 
du code
le multitâche :
• 
Développons en Java
5

1. Présentation
Java est un langage de programmation à usage général, évolué et orienté objet dont la syntaxe est proche du C. Il existe 2
types de programmes en Java : les applets et les applications. Une application autonome (stand alone program) est une
application qui s'exécute sous le contrôle direct du système d'exploitation. Une applet est une application qui est chargée
par un navigateur et qui est exécutée sous le contrôle de celui ci.
Ce chapitre contient plusieurs sections :
Les caractéristiques le langage
• 
Bref historique de Java
• 
Les différentes éditions de Java
• 
Un rapide tour d'horizon des API et de quelques outils
• 
Les différences entre Java et JavaScript
• 
L'installation du JDK
• 
1.1. Les caractéristiques
Java possède un certain nombre de caractéristiques qui ont largement contribué à son énorme succès :
le source est compilé en pseudo code ou yte code puis exécuté par un interpréteur Java :
la Java Virtual Machine (JVM). Ce concept est à la base du slogan de Sun pour Java :
Java est interprété
WORA (Write Once, Run Anywhere : écrire une fois, exécuté partout). En effet, le byte
code, s'il ne contient pas de code spécifique à une plate?forme particulière peut être
exécuté et obtenir les même résutlats sut toutes les machines disposant d'une JVM.
il n'y a pas de compilation spécifique pour chaque plate forme. Le code reste
indépendant de la machine sur laquelle il  s'exécute. Il est possible d'exécuter des 
Java est indépendant de
programmes Java sur tous les environnements qui possèdent une Java Virtual Machine.
toute plate?forme
Cette indépendance est assurée au niveau du code source grâce à Unicode et au niveau
du byte code.
comme la plupart des langages récent, java est orienté objet. Chauqe fichier source
contient la définition d'une ou plusieurs classes qui sont utilisées les unes avec les autres
Java est orienté objet.
pour former une application. Java n'est complètement objet par il définit des types
primitifs (entier, caractère, flottant, booléen,...).
le choix de ses auteurs a été d'abandonner des éléments mal compris ou mal exploités des
Java est simple
autres langages tels que la notion de pointeurs (pour éviter les incidents en manipulant
directement la mémoire), 'héritage multiple et la surcharge des opérateurs, ...
Java est fortement typé
toutes les variables sont typées et il n'existe pas de conversion automatique qui risquerait
Développons en Java
6

une perte de données. Si une tel conversion doit être réalisée, le développeur doit
obligatoirement utilisé un cast ou une méthode statique pour la réaliser.
l'allocation de la mémoire pour un objet est automatique à sa création et Java récupère
Java assure la gestion de la
automatiquement la mémoire inutilisée grâce au garbage collector qui restitue les zones
mémoire
de mémoire laissées libres suite à la destruction des objets.
la sécurité fait partie intégrante du système d'exécution et du compilateur. Un
programme Java planté ne menace pas le système d'exploitation. Il ne peut pas y avoir
d'accès direct à la mémoire. L'accès au disque dur est réglementé dans une applet.
Les applets fonctionnant sur le Web sous soumis aux restrictions suivantes dans la
version 1.0 de Java :
aucun programme ne peut ouvrir, lire, écrire ou effacer un fichier sur le système
• 
Java est sûr
de l'utilisateur
aucun programme ne peut lancer un autre programme sur le système de
• 
l'utilisateur
toute fenêtre créée par le programme est clairement identifiée comme étant une
• 
fenêtre Java, ce qui interdit par exemple la création d'une fausse fenêtre
demandant un mot de passe
les programmes ne peuvent pas se connecter à d'autres sites Web que celui dont
• 
ils proviennent.
le pseudo code a une taille relativement petite car les bibliothèques de classes requises ne
Java est économe
sont liées qu'à l'exécution.
il permet l'utilisation de threads qui sont des unités d'exécution isolées. La JVM elle
Java est multitâche
même utilise plusieurs threads.
Les programmes Java exécutés localement sont des applications, ceux qui tournent sur des pages Web sont des applets.
Les différences entre une applet et une application sont :
les applets n'ont pas de bloc main() : la méthode main() est appelée par la machine virtuelle pour exécuter une
• 
application.
les applets ne peuvent pas être testées avec l'interpréteur mais doivent être intégrées à une page HTML, elle
• 
même visualisée avec un navigateur sachant gérer les applets Java, ou testées avec l'applet viewer.
1.2. Bref historique de Java
Année
Evénements
1995
mai : premier lancement commercial
1996
janvier : JDK 1.0
1996
septembre : lancement du JDC
1997
février : JDK 1.1
1998
décembre : lancement de J2SE et du JCP
1999
décembre : lancement J2EE
2000
mai : J2SE 1.3
2002
J2SE 1.4
Développons en Java
7

1.3. Les différentes éditions de Java
Sun fourni gratuitement un ensemble d'outils et d'API pour permettre le développement de programmes avec Java. Ce

Le JRE contient uniquement l'environnement d'exécution de programmes Java. Le JDK contient lui même le JRE. Le
JRE seul doit être installé sur les machines ou des applications java doivent être exécutées.
Depuis sa version 1.2, Java a été renommé Java 2. Les numéros de versions 1.2 et 2 désignent donc la même version.
Le JDK a été renommé J2SDK (Java 2 Software Development Kit) mais la dénomination JDK reste encore largement
utilisée.
Le JRE a été renommé J2RE (Java 2 Runtime Edition).
Trois éditions de Java existent :
J2ME : Java 2 Micro Edition
• 
J2SE : Java 2 Standard Edition
• 
J2EE : Java 2 Entreprise Edition
• 
Sun fourni le JDK, à partir de la version 1.2, sous les plate?formes Windows, Solaris et Linux.
La version 1.3 de Java est désignée sous le nom Java 2 version 1.3.
La documentation au format HTML des API de java est fournie séparément. Malgré sa taille imposante, cette
documentation est indispensable pour obtenir des informations complètes sur les classes fournies. Le tableau ci dessous
résume la taille des différents composants selon leur version pour la plateforme Windows.
Version 1.0
Version 1.1
Version 1.2
Version 1.3
Version 1.4
JDK compressé
8,6 Mo
20 Mo
30 Mo
47 Mo 
JDK installé
53 Mo
59 Mo
JRE compressé
12 Mo
7 Mo
JRE installé
 35 Mo
40 Mo
Documentation
16 Mo
21 Mo
 30 Mo
compressée
Documentation
83 Mo
106 Mo
 144 Mo
décompressée
1.3.1. Java 1.0
Cette première version est lancée officiellement en mai 1995.
1.3.2. Java 1.1
Cette version du JDK est annoncée officiellement en mars 1997. Elle apporte de nombreuses améliorations et
d'importantes fonctionnalités nouvelles dont :
les java beans
• 
les fichiers JAR
• 
Développons en Java
8

RMI pour les objets distribués
• 
la sérialisation
• 
l'introspection
• 
JDBC pour l'accès aux données
• 
les classes internes
• 
l'internationalisation
• 
un nouveau modèle de sécurité permettant notamment de signer les applets
• 
JNI pour l'appele de méthodes natives
• 
...
• 
1.3.3. Java 1.2
Cette version du JDK est lancée fin 1998. Elle apporte de nombreuses améliorations et d'importantes fonctionnalités
nouvelles dont :
un nouveau modèle de sécurité basé sur les policy
• 
les JFC sont incluses dans le JDK (Swing, Java2D, accessibility, drag & drop ...)
• 
JDBC 2.0
• 
les collections
• 
support de CORBA
• 
un compilateur JIT est inclus dans le JDK
• 
de nouveaux format audio sont supportés
• 
...
• 
Java 2 se décline en 3 éditions différentes qui regroupent des APIs par domaine d'applications :
Java 2 Micro Edition (J2ME) : contient le nécessaire pour développer des applications capable de fonctionner
• 
dans des environnements limités tels que les assistants personnels (PDA), les téléphones portables ou les
systèmes de navigation embarqués
Java 2 Standard Edition (J2SE) : contient le nécessaire pour développer des applications et des applets. Cette
• 
édition reprend le JDK 1.0 et 1.1.
Java 2 Enterprise Edition (J2EE) : contient en plus un ensemble de plusieurs API permettant le développement
• 
d'applications destinées aux entreprises tel que JDBC pour l'accès aux bases de données, EJB pour développer
des composants orientés métiers, Servlet / JSP pour générer des pages HTML dynamiques, ...
Le but de ces trois éditions est de proposer une solution à base java quelque soit le type de développement à réaliser.
1.3.4. Java 1.3
Cette version du JDK apporte de nombreuses améliorations notamment sur les performances et des fonctionnalités
nouvelles dont :
JNDI est inclus dans le JDK
• 
hotspot est inclus dans la JVM
• 
...
• 
La rapidité d'exécution a été grandement améliorée dans cette version.
1.3.5. Java 1.4 (nom de code Merlin)
Cette version du JDK, lancée début 2002, apporte de nombreuses améliorations notamment sur les performances et des
fonctionnalités nouvelles dont :
JAXP est inclus dans le JDK pour le support de XML
• 
JDBC version 3.0
• 
Développons en Java
9

new I/O API pour compléter la gestion des entrée/sortie
• 
logging API pour la gestion des logs applicatives
• 
une API pour utiliser les expressions régulières
• 
une api pour gérer les préférences utilisateurs
• 
JAAS est inclus dans le JDK pour l'authentification
• 
un ensemble d'API pour utiliser la cryptographie
• 
l'outils java WebStart
• 
...
• 
Cette version ajoute un nouveau mot clé au langage pour utiliser les assertion : assert.
1.3.6. Java 1.5 (nom de code Tiger)
Cette prochaine version du J2SE est en cours de spécification par le JCP sous la JSR 176. Elle devrait intégrer un certain
nombre de JSR dans le but de simplifier les développements en Java.
1.3.7. Le résumé des différentes versions
Au fur et à mesure des nouvelles versions de Java , le nombre de packages et de classes s'accroît :
Java 1.0
Java 1.1
Java 1.2
Java 1.3
Java 1.4
Nombre de de packages
8
23
59
76
135
Nombre de classes
201
503
1520
1840
2990
1.3.8. Les extensions du JDK
Sun fourni un certains nombres d'API supplémentaires qui ne sont pas initialement fournies en standard dans le JDK. Ces
API sont intégrées au fur et à mesure de l'évolution de Java.
Extension
Description
Java Naming and directory interface Cet API permet d'unifier l'accès à des ressources. Elle est
JNDI
intégré a java 1.3
Java mail
Cet API permet de gérer des emails. Elle est intégré a la plateforme J2EE.
Java 3D
Cet API permet de mettre en oeuvre des graphismes en 3 dimensions
Java Media
Cet API permet d'utiliser des composants multimédia
Cet API permet de créer des servlets (composants serveurs). Elle est intégré a la plateforme
Java Servlets
J2EE.
Java Help
Cet API permet de créer des aide en ligne pour les applications
Jini
Cet API permet d'utiliser java avec des appareils qui ne sont pas des ordinateurs
JAXP
Cet API permet le parsing et le traitement de document XML. Elle est intégré a java 1.4
Cette liste n'est pas exhaustive.
Développons en Java
10

1.4. Un rapide tour d'horizon des API et de quelques outils
La communauté Java est très productive car elle regroupe :
Sun, le fondateur de Java
• 
le JCP (Java Community Process) : processus de traitement des évolutions de Java dirigé par Sun. Chaque
• 
évolution est traitée dans une JSR (Java Specification Request) par un groupe de travail constitué de différents
acteurs du monde Java
des acteurs commerciaux dont tous les plus grands acteurs du monde informatique excepté Microsoft
• 
la communauté libre qui produit un très grand nombre d'API et d'outils pour Java
• 
Ainsi l'ensemble des API et des outils utilisables est énorme et évolue très rapidement. Les tableaux ci dessous tentent de
recencer les principaux par thème.
J2SE 1.4
Java Bean
RMI
IO
Applet
Reflexion
Collection
Logging
AWT
Net (réseau)
Preferences
Security
JFC
Internationalisation
Exp régulière
Swing
Les outils de Sun
Jar
Javadoc
Java Web Start
JWSDK
Les outils libres (les plus connus)
Jakarta Tomcat
Jakarta Ant
JBoss
Apache Axis
JUnit
Eclipse
Les autres API
Données
Web
Entreprise
XML
Divers
JDBC
Servlets
Java Mail
JAXP
JAI
JDO
JSP
JNDI
SAX
JAAS
JSTL
EJB
DOM
JCA
Jave Server Faces
JMS
JAXM
JCE
JMX
JAXR
Java Help
JTA
JAX?RPC
JMF
RMI?IIOP
SAAJ
JSSE
Java IDL
JAXB
Java speech
JINI
Java 3D
Développons en Java
11

JXTA
Les API de la communauté open source
Données
Web
Entreprise
XML
Divers
OJB
Jakarta Struts
Apache Xerces
Jakarta Log4j
Cator
Webmacro
Apache Xalan
Jakarta regexp
Hybernate
Expresso
Apache Axis
Barracuda
JDOM
Turbine
DOM4J
1.5. Les différences entre Java et JavaScript
Il ne faut pas confondre Java et JavaScript. JavaScript est un langage développé par Netscape Communications.
La syntaxe des deux langages est proche car elles dérivent toutes les deux du C++.
Il existe de nombreuses differences entre les deux langages :
Java
Javascript
Auteur
Développé par Sun Microsystems
Développé par Netscape Communications
Format
Compilé sous forme de byte?code
Interprété
Applet téléchargé comme un élément de la page
Stockage
Source inséré dans la page web
web
Utilisable pour développer tous les types
Utilisable uniquement pour "dynamiser" les
Utilisation
d'applications
pages web
Execution
Executé dans la JVM du navigateur
Executé par le navigateur
Manipule des objets mais ne permet pas d'en
POO
Orienté objets
définir
Typage
Fortement typé
Pas de contrôle de type
Compléxité du
Code relativement complexe
Code simple
code
1.6. L'installation du JDK
Le JDK et la documentation sont librement téléchargeable sur le site web de Sun :
1.6.1. L'installation de la version 1.3 DU JDK de Sun sous Windows 9x
Pour installer le JDK 1.3 sous Windows 9x, il suffit d'exécuter le programme : j2sdk1_3_0?
Le programme commence par désarchiver les composants.
Développons en Java
12

Le programme utilise InstallShield pour réaliser l'installation
L'installation vous souhaite la bienvenue et vous donne quelques informations d'usage.
L'installation vous demande ensuite de lire et d'approuver les termes de la licence d'utilisation.
Développons en Java
13

L'installation vous demande le répertoire dans lequel le JDK va être installé. Le répertoire proposé par défaut est
pertinent car il est simple.
L'installation vous demande les composants à installer :
Program Files est obligatoire pour une première installation
• 
Les interfaces natives ne sont utiles que pour réaliser des appels de code natif dans les programmes java
• 
Les démos sont utiles car ils fournissent quelques exemples
• 
les sources contiennent les sources de la plupart des classes java écrite en java. Attention à l'espace disque
• 
nécessaire à cet élément
Développons en Java
14

L'installation se poursuit par la copie des fichiers et la configuration du JRE
1.6.2. L'installation de la documentation de java 1.3 sous Windows
L'archive contient la documentation sous forme d'arborescence dont la racine est jdk1.3\docs.
Si le répertoire par défaut a été utilisé lors de l'installation, il suffit de décompresser l'archive à la racine du disque C:\.
Développons en Java
15

Il peut être pratique de désarchiver le fichier dans dans un sous répertoire, ce permet de reunir plusieurs versions de la
documentation.
1.6.3. La configuration des variables système sous Windows
Pour un bon fonctionnement du JDK, il faut paramétrer correctement deux variables systèmes : la variable PATH qui
définie les chemins de recherche des exécutables et la variable CLASSPATH qui définies les chemins de rechercher des
classes java.
Pour configurer la variable PATH, il suffit d'ajouter à la fin du fichier :
Exemple :
SET PATH=%PATH%;C:\JDK1.3\BIN
Attention : si une version antérieure du JDK était déjà présente, la variable PATH doit déjà contient un chemin vers les
utilitaires du JDK. Il faut alors modifier ce chemin sinon c'est l'ancienne version qui sera utilisée. Pour vérifier la version
du JDK utilisé, il suffit de saisir la commande java ?version dans une fenêtre DOS.
La variable CLASSPATH est aussi définie dans le fichier . Il suffit d'ajouter ligne ou de modifier la ligne
existante définissant cette variable.
Exemple :
SET CLASSPATH=.;
Il est intéressant d'ajouter le . qui désigne le répertoire courant dans le CLASSPATH.
Il faudra ajouter par la suite les chemins d'accès aux différent packages requis par les développements.
Pour que ces modifications prennent effet dans le système, il faut redemarrer Windows ou executer ces deux instructions
sur une ligne de commande dos.
1.6.4. Les éléments du JDK 1.3 sous Windows
Le répertoire dans lequel a été installé le JDK contient plusieurs répertoires. Les répertoires données ci après sont ceux
utilisés en ayant gardé le répertoire défaut lors de l'installation.
Développons en Java
16

Répertoire
Contenu
Le répertoire d'installation contient deux fichiers intéressants : le fichier
qui fourni quelques information et des liens web et le fichier
C:\jdk1.3
qui contient le source java de nombreuses classes. Ce dernier fichier n'est présent
que si l'option correspondante a été cochée lors de l'installation.
Ce répertoire contient les exécutables : le compilateur javac, l'interpréteur java, le
C:\jdk1.3\bin
débuggeur jdb et d'une façon générale tous les outils du JDK.
Ce répertoire n'est présent que si l'option nécessaire a été cochée lors de
C:\jdk1.3\demo
l'installation. Il contient des applications et des applets avec leur code source.
C:\jdk1.3\docs
Ce répertoire n'est présent que si la documentation a été décompressée.
Ces répertoires ne sont présent que si les options nécessaires ont été cochées lors
C:\jdk1.3\include et
de l'installation. Il contient des fichiers d'en?tête C (fichier avec l'extension .H)
C:\jdk1.3\include?old
qui permettent d'inclure du code C dans le source java.
Ce répertoire contient le JRE : il regroupe le nécessaire à l'exécution des
applications notamment le fichier qui regroupe les API. Depuis la version
1.3, le JRE contient deux machines virtuelles : la JVM classique et la JVM
utilisant la technologie Hot spot. Cette dernière est bien plus rapide et celle qui est
C:\jdk1.3\jre
utilisée par défaut.
Les éléments qui composent le JRE sont séparés dans les répertoires bin et lib
selon leur nature.
Ce répertoire ne contient plus que quelques bibliothèques notamment le fichier
C:\jdk1.3\lib
. Avec le JDK 1.1 ce répertoire contenait le fichier de la bibliothèque
standard. Ce fichier est maintenant dans le répertoire JRE.
Développons en Java
17

2. Les techniques de base de programmation en Java
N'importe quel éditeur de texte peut être utilisé pour éditer un fichier source Java.
Il est nécessaire de compiler le source pour le transformer en J?code ou byte?code Java qui sera lui exécuté par la
machine virtuelle.
Il est préférable de définir une classe par fichier. Le nom de la classe publique et le fichier qui la contient doivent être
identiques.
Pour être compilé, le programme doit être enregistré au format de caractères Unicode : une conversion automatique est
faite par le JDK si nécessaire.
Ce chapitre contient plusieurs sections :
La compilation d'un code source :
• 
Cette section présente la compilation d'un fichier source.
L'exécution d'un programme et d'une applet :
• 
Cette section présente l'éxécution d'un programme et d'une applet.
2.1. La compilation d'un code source
Pour compiler un fichier source il suffit d'invoquer la commande javac avec le nom du fichier source avec son extension
.java
javac
Le nom du fichier doit correspondre au nom de la classe principale en respectant la casse même si le système
d'exploitation n'y est pas sensible
Suite à la compilation, le pseudo code Java est enregistré sous le nom NomFichier.class
2.2. L'exécution d'un programme et d'une applet
2.2.1. L'exécution d'un programme
Une classe ne peut être éxécutée que si elle contient une méthode main() correctement définie.
Développons en Java
18

Pour exécuter un fichier contenant du byte?code il suffit d'invoquer la commande java avec le nom du fichier source sans
son extension .class
java NomFichier
2.2.2. L'exécution d'une applet
Il suffit de créer une page HTML pouvant être très simple :
Exemple
<HTML>
<TITLE> test applet Java </TITLE>
<BODY>
<APPLET code=« NomFichier.class » width=270 height=200>
</APPLET>
</BODY>
</HTML>
Il faut ensuite visualiser la page créée dans l'appletviewer ou dans un navigateur 32 bits compatible avec la version de
Java dans laquelle l'applet est écrite.
Développons en Java
19

3. La syntaxe et les éléments de bases de java
Ce chapitre ce compose de plusieurs sections :
Les règles de bases
• 
Cette section présente les règles syntaxiques de base de java.
Les identificateurs
• 
Cette section présente les règles de composition des identificateurs.
Les commentaires
• 
Cette section présente les différentes formes de commentaires de java.
La déclaration et l'utilisation de variables
• 
Cette section présente la déclaration des variables, les types élémentaires, les formats des type élémentaires,
l'initialisation des variables, l'affectation et les comparaisons.
Les opérations arithmétiques
• 
Cette section présente les opérateurs arithmétique sur les entiers et les flottants et les opérateurs
d'incrémentation et de décrémentation.
La priorité des opérateurs
• 
Cette section présente la priorité des opérateurs.
Les structures de contrôles
• 
Cette section présente les instructions permettant la réalisation de boucles, de branchements conditionnels et de
débranchements.
Les tableaux
• 
Cette section présente la déclaration, l'initialisation explicite et le parcours d'un tableau
Les conversions de types
• 
Cette section présente la conversion de types élémentaires.
La manipulation des chaines de caractères
• 
Cette section présente la définition et la manipulation de chaine de caractères (addition, comparaison,
changement de la casse ... ).
3.1. Les règles de base
Java est sensible à la casse.
Les blocs de code sont encadrés par des accolades. Chaque instruction se termine par un caractère ';' (point virgule).
Une instruction peut tenir sur plusieurs lignes
Exemple :
char 
code
=
'D'; 
L'indentation est ignorée du compilateur mais elle permet une meilleure compréhension du code par le programmeur.
Développons en Java
20

3.2. Les identificateurs
Chaque objet, classe, programme ou variable est associer à un nom : l'identificateur qui peut se composer de tous les
caractères alphanumériques et des caractères _ et $. Le premier caractère doit être une lettre, le caractère de soulignement
ou le signe dollars.
Rappel : Java est sensible à la casse.
3.3. Les commentaires
Ils ne sont pas pris en compte par le compilateur donc ils ne sont pas inclus dans le pseudo code. Ils ne se terminent pas
par un ;.
Il existe trois type de commentaire en Java :
Type de commentaires
Exemple
// commentaire sur une seule ligne
commentaire abrégé
int N=1; // déclaration du compteur
/* commentaires ligne 1
commentaire multiligne
commentaires ligne 2 */
commentaire de documentation automatique
/** commentaire */
3.4. La déclaration et l'utilisation de variables
3.4.1. La déclaration de variables
Une variable possède un nom, un type et une valeur. La déclaration d'une variable doit donc contenir deux choses : un
nom et le type de données qu'elle peut contenir. Une variable est utilisable dans le bloc ou elle est définie.
La déclaration d'une variable permet de réserver la mémoire pour en stocker la valeur.
Le type d'une variable peut être un type élémentaire ou un objet :
type_élémentaire variable;
classe variable ;
Exemple :
long nombre;
Rappel : les noms de variables en Java peuvent commencer par un lettre, par le caractère de soulignement ou par le signe
dollars. Le reste du nom peut comporter des lettres ou des nombres mais jamais d'espaces.
Il est possible de définir plusieurs variables de même type en séparant chacune d'elles par une virgule.
Exemple :
Développons en Java
21

int jour, mois, annee ;
Java est un langage à typage rigoureux qui ne possède pas de transtypage automatique lorsque ce transtypage risque de
conduire à une perte d'information.
Pour les objets, il est nécessaire en plus de la déclaration de la variable de créer un objet avant de pouvoir l'utiliser. Il faut
réserver de la mémoire pour la création d'un objet ( remarque : un tableau est un objet en java ) avec l'instruction new. La
libération de la mémoire se fait automatiquement grâce au garbage collector.
Exemple :
MaClasse instance; // déclaration de l'objet
instance = new maClasse(); // création de l'objet
OU MaClasse instance = new MaClasse(); // déclaration et création de l'objet
Exemple :
int[] nombre = new int[10];
Il est possible en une seule instruction de faire la déclaration et l'affectation d'une valeur à une variable ou plusieurs
variables.
Exemple :
int i=3 , j=4 ;
3.4.2. Les types élémentaires
Les types élémentaires ont une taille identique quelque soit la plate?forme d'exécution : c'est un des éléments qui permet
à java d'être indépendant de la plate?forme sur lequel le code s'exécute.
Type
Désignation
Longueur
Valeurs
Commentaires
pas de conversion possible vers un autre
boolean valeur logique : true ou false
8 bits
True ou false
type
byte
octet signé
8 bits
?128 à 127
short
entier court signé
16 bits
?32768 à 32767
entouré de cotes simples dans un
char
caractère Unicode
16 bits
\u0000 à \uFFFF
programme Java
?2147483648 à
int
entier signé
32 bits
2147483647
virgule flottante simple
1.401e?045 à
float
32 bits
précision (IEEE754)
3.40282e+038
virgule flottante double
2.22507e?308 à
double
64 bits
précision (IEEE754)
1.79769e+308
?9223372036854775808
long
entier long
64 bits
à
9223372036854775807
Développons en Java
22

Les types élémentaires commencent tous par une minuscule.
3.4.3. Le format des types élémentaires
Le format des nombres entiers :
Les types byte, short, int et long peuvent être codés en décimal, hexadécimal ou octal. Pour un nombre hexadécimal, il
suffit de préfixer sa valeur par 0x. Pour un nombre octal, le nombre doit commencer par un zéro. Le suffixe l ou L
permet de spécifier que c'est un entier long.
Le format des nombres décimaux :
Les types float et double stockent des nombres flottants : pour être reconnus comme tel ils doivent posséder soit un point,
un exposant ou l'un des suffixes f, F, d, D. Il est possible de préciser des nombres qui n'ont pas le partie entière ou
décimale.
Exemple :
float pi = 3.141f;
double v = 3d
float f = +.1f , d = 1e10f; 
Par défaut un littéral est de type double : pour définir un float il faut le suffixer par la lettre f ou F.
Exemple :
double w = 1.1; 
Attention : float pi = 3.141; // erreur à la compilation
Le format des caractères :
Un caractère est codé sur 16 bis car il est conforme à la norme Unicode. Il doit être entouré par des apostrophes. Une
valeur de type char peut être considérée comme un entier non négatif de 0 à 65535. Cependant la conversion implicite
par affectation n'est pas possible.
Exemple :
/* test sur les caractères */
class test1 {
    public static void main (String args[]) {
        char code = 'D';
        int index = code ? 'A';
        .println("index = " + index);
    } 
}
Développons en Java
23

3.4.4. L'initialisation des variables
Exemple :
int nombre; // déclaration
nombre = 100; //initialisation
OU int nombre = 100; //déclaration et initialisation
En java, toute variable appartenant à un objet (définie comme étant un attribut de l'objet) est initialisée avec une valeur
par défaut en accord avec son type au moment de la creation. Cette initialisation ne s'applique pas aux variables locales
des méthodes de la classe.
Les valeurs par défaut lors de l'initialisation automatique des variables d'instances sont :
Type
Valeur par défaut
boolean
false
byte, short, int, long
0
float, double
0.0
char
\u000
Remarque : Dans une applet, il est préférable de faire les déclarations et initialisation dans la méthode init().
3.4.5. L'affectation
le signe = est l'opérateur d'affectation et s'utilise avec une expression de la forme variable = expression. L'opération
d'affectation est associatif de droite à gauche : il renvoie la valeur affectée ce qui permet d'écrire :
x = y = z = 0;
Il existe des opérateurs qui permettent de simplifier l'écritures d'une opération d'affectation associée à un opérateur
mathématique :
Opérateur
Exemple
Signification
=
a=10
équivalent à : a = 10
+=
A+=10
équivalent à : a = a + 10
?=
a?=
équivalent à : a = a ? 10
*=
A*=
équivalent à : a = a * 10
/=
a/=10
équivalent à : a = a / 10
%=
A%=10
reste de la division
^=
a^=10
équivalent à : a = a ^ 10
<<=
A<<=10
équivalent à : a = a << 10 a est complété par des zéros à droite
>>=
a>>=10
équivalent à : a = a >> 10 a est complété par des zéros à gauche
>>>=
a>>>=10
équivalent à : a = a >>> 10 décalage à gauche non signé
Attention : Lors d'une opération sur des opérandes de type différents, le compilateur détermine le type du
résultat en prenant le type le plus précis des opérandes. Par exemple, une multiplication d'une variable de
type float avec une variable de type double donne un résultat de type double. Lors d'une opération entre un
opérande entier et un flottant, le résultat est du type de l'opérande flottant.
Développons en Java
24

3.4.6. Les comparaisons
Java propose des opérateurs pour toutes les comparaisons :
Opérateur
Exemple
Signification
>
a > 10
strictement supérieur
<
a < 10
strictement inférieur
>=
a >= 10
supérieur ou égal
<=
a <= 10
inférieur ou égal
==
a == 10
Egalité
!=
a != 10
diffèrent de
&
a & b
ET binaire
^
a ^ b
OU exclusif binaire
|
a | b
OU binaire
ET logique (pour expressions booléennes) : l'évaluation de l'expression
&&
a && b
cesse dès qu'elle devient fausse
OU logique (pour expressions booléennes) : l'évaluation de
||
a || b
l'expression cesse dès qu'elle devient vraie
opérateur conditionnel : renvoie la valeur b ou c selon l'évaluation de
? :
a ? b : c
l'expression a (si a alors b sinon c) : b et c doivent retourner le même
type
Les opérateurs sont exécutés dans l'ordre suivant à l'intérieure d'une expression qui est analysée de gauche à droite:
incréments et décréments
• 
multiplication, division et reste de division (modulo)
• 
addition et soustraction
• 
comparaison
• 
le signe = d'affectation d'une valeur à une variable
• 
L'usage des parenthèse permet de modifier cet ordre de priorité.
3.5. Les opérations arithmétiques
Les opérateurs arithmétiques se notent + (addition), ? (soustraction), * (multiplication), / (division) et % (reste de la
division). Ils peuvent se combiner à l'opérateur d'affectation
Exemple :
nombre += 10;
3.5.1. L'arithmétique entière
Pour les types numériques entiers, Java met en oeuvre une sorte de mécanisme de conversion implicite vers le type int
appelée promotion entière. Ce mécanisme fait partie des règles mise en place pour renforcer la sécurité du code.
Développons en Java
25

Exemple :
short x= 5 , y = 15;
x = x + y ; //erreur à la compilation
Incompatible type for =. Explicit cast needed to convert int to short.
x = x + y ; //erreur à la compilation
^
1 error
Les opérandes et le résultat de l'opération sont convertis en type int. Le résultat est affecté dans un type short : il y a donc
risque de perte d'informations et donc erreur à la compilation est émise. Cette promotion évite un débordement de
capacité sans que le programmeur soit pleinement conscient du risque : il est nécessaire, pour régler le problème,
d'utiliser une conversion explicite ou cast
Exemple :
x = (short) ( x + y );
Il est nécessaire de mettre l'opération entre parenthèse pour que ce soit son résultat qui soit converti car le cast a une
priorité plus forte que les opérateurs arithmétiques.
La division par zéro pour les types entiers lève l'exception ArithmeticException
Exemple :
/* test sur la division par zero de nombres entiers */ 
class test3 {
    public static void main (String args[]) {
        int valeur=10;
        double résultat = valeur / 0;
        .println("index = " + résultat);
    }
}
3.5.2. L'arithmétique en virgule flottante
Avec des valeurs float ou double, la division par zéro ne produit pas d'exception mais le résultat est indiqué par une
valeur spéciale qui peut prendre trois états :
indéfini : ou (not a number)
• 
indéfini positif : Float.POSITIVE_INFINITY ou Double.POSITIVE_INFINITY, + 
• 
?
indéfini négatif : Float.NEGATIVE_INFINITY ou Double.NEGATIVE_INFINITY, + 
• 
?
Conformément à la norme IEEE754, ces valeurs spéciales représentent le résultat d'une expression invalide NaN, une
valeur supérieure au plafond du type pour infini positif ou négatif.
X
Y
X / Y
X % Y
valeur finie
0
+ ?
NaN
valeur finie
+/? ?
0
x
0
0
NaN
NaN
+/? ?
valeur finie
+/? ?
NaN
+/? ?
+/? ?
NaN
NaN
Développons en Java
26

Exemple :
/* test sur la division par zero de nombres flottants */ 
class test2 {
    public static void main (String args[]) {
        float valeur=10f; 
        double résultat = valeur / 0;
        .println("index = " + résultat);
    }
}
3.5.3. L'incrémentation et la décrémentation
Les opérateurs d'incrémentation et de décrémentation sont : n++ ++n n?? ??n
Si l'opérateur est placé avant la variable (préfixé), la modification de la valeur est immédiate sinon la modification n'a
lieu qu'à l'issu de l'exécution de la ligne d'instruction (postfixé)
L'opérateur ++ renvoie la valeur avant incrémentation s'il est postfixé, après incrémentation s'il est préfixé.
Exemple :
.println(x++); // est équivalent à
.println(x); x = x + 1;
.println(++x); // est équivalent à
x = x + 1; .println(x);
Exemple :
/* test sur les incrementations prefixees et postfixees */
class test4 {
    public static void main (String args[]) {
        int n1=0;
        int n2=0;
        .println("n1 = " + n1 + " n2 = " + n2);
        n1=n2++;         
        .println("n1 = " + n1 + " n2 = " + n2);
        n1=++n2;        
        .println("n1 = " + n1 + " n2 = " + n2);
        n1=n1++;        //attention
        .println("n1 = " + n1 + " n2 = " + n2);
    }
}
Résultat :
int n1=0;
int n2=0; // n1=0 n2=0
n1=n2++; // n1=0 n2=1
n1=++n2; // n1=2 n2=2
n1=n1++; // attention : n1 ne change pas de valeur
Développons en Java
27

3.6. La priorité des opérateurs
Java définit les priorités dans les opérateurs comme suit ( du plus prioriotaire au moins prioritaire )
les parenthèses
( )
++
les opérateurs d'incrémentation
??
*
les opérateurs de multiplication, division, et modulo
/
%
+
les opérateurs d'addition et soustraction
?
<<
les opérateurs de décalage
>>
<
>
les opérateurs de comparaison
<=
>=
==
les opérateurs d'égalité
!=
l'opérateur OU exclusif
^
l'opérateur ET
&
l'opérateur OU
|
l'opérateur ET logique
&&
l'opérateur OU logique
||
=
les opérateurs d'assignement
+=
?=
Les parenthèses ayant une forte priorité, l'ordre d'interprétation des opérateurs peut être modifié par des parenthèses.
3.7. Les structures de contrôles
Comme quasi totalité des langages de développement orienté objets, Java propose un ensemble d'instructions qui
permettent de d'organiser et de structurer les traitements. L'usage de ces instructions est similaire à celui rencontré dans
leur équivalent dans d'autres langage.
3.7.1. Les boucles
while ( boolean )
{
    ... // code a éxécuter dans la boucle
}
Le code est exécuté tant que le booléen est vrai. Si avant l'instruction while, le booléen est faux, alors le code de la
Développons en Java
28

boucle ne sera jamais exécuté
Ne pas mettre de ; après la condition sinon le corps de la boucle ne sera jamais exécuté
do {
   ...
while ( boolean )
Cette boucle est au moins exécuté une fois quelque soit la valeur du booléen;
for ( initialisation; condition; modification) {
    ...
}
Exemple :
for (i = 0 ; i < 10; i++ ) { ....}
for (int i = 0 ; i < 10; i++ ) { ....}
for ( ; ; ) { ... } // boucle infinie
L'initialisation, la condition et la modification de l'index sont optionels.
Dans l'initialisation, on peut déclarer une variable qui servira d'index et qui sera dans ce cas locale à la boucle.
Il est possible d'inclure plusieurs traitements dans l'initialisation et la modification de la boucle : chacun des traitements
doit etre séparé par une virgule.
Exemple :
for (i = 0 , j = 0 ; i * j < 1000;i++ , j+= 2) { ....}
La condition peut ne pas porter sur l'index de la boucle :
Exemple :
boolean trouve = false;
for (int i = 0 ; !trouve ; i++ ) { 
    if ( tableau[i] == 1 )
    trouve = true;
    ... //gestion de la fin du parcours du tableau
}
Il est possible de nommer une boucle pour permettre de l'interrompre même si cela est peu recommendé :
Exemple :
int compteur = 0;
boucle:
while (compteur < 100) {
    for(int compte = 0 ; compte < 10 ; compte ++) {
        compteur += compte;
        .println("compteur = "+compteur);
        if (compteur> 40) break boucle;
    }
}
Développons en Java
29

3.7.2. Les branchements conditionnels
if (boolean) {
    ...
else if (boolean) {
    ...
else {
    ...
}
swith (expression) {
case constante1 :
        instr11;
        instr12;
break;
case constante2 :
        ...
default :
        ...
}
On ne peut utiliser switch qu'avec des types primitifs d'une taille maximum de 32 bits (byte, short, int, char).
Si une instruction case ne contient pas de break alors les traitements associés au case suivant sont éxécutés.
Il est possible d'imbriquer des switch
L'opérateur ternaire : ( condition ) ? valeur?vrai : valeur?faux
Exemple :
if (niveau == 5) // equivalent à total = (niveau ==5) ? 10 : 5;
total = 10;
else total = 5 ; 
.println((sexe == « H ») ? « Mr » : « Mme »);
3.7.3. Les débranchements
break : permet de quitter immédiatement une boucle ou un branchement. Utilisable dans tous les controles de flot
continue : s'utilise dans une boucle pour passer directement à l'itération suivante
break et continue peuvent s'excuter avec des blocs nommés. Il est possible de préciser une étiquette pour indiquer le point
de retour lors de la fin du traitement déclenché par le break.
Une étiquette est un nom suivi d'un deux points qui définit le début d'une instruction.
3.8. Les tableaux
Ils sont dérivés de la classe Object : il faut utiliser des méthodes pour y accéder dont font parti des messages de Object tel
que equals() ou getClass(). Le premier élément possède l'indice 0.
Développons en Java
30

3.8.1. La déclaration des tableaux
Java permet de placer les crochets après ou avant le nom du tableau dans la déclaration.
Exemple :
int tableau[] = new int[50]; // déclaration et allocation
OU int[] tableau = new int[50];
OU int tab[]; // déclaration
tab = new int[50]; //allocation
Java ne supporte pas directement les tableaux à plusieurs dimensions : il faut déclarer un tableau de tableau.
Exemple :
float tableau[][] = new float[10][10];
La taille des tableaux de la seconde dimension peut ne pas être identiques pour chaque occurrences.
Exemple :
int dim1[][] = new int[3][];
dim1[0] = new int[4];
dim1[1] = new int[9];
dim1[2] = new int[2];
Chaque élément du tableau est initialisé selon son type par l'instruction new : 0 pour les numériques, '\0' pour les
caractères, false pour les booléens et nil pour les chaines de caractères et les autres objets.
3.8.2. L'initialisation explicite d'un tableau
Exemple :
int tableau[5] = {10,20,30,40,50};
int tableau[3][2] = {{5,1},{6,2},{7,3}};
La taille du tableau n'est pas obligatoire si le tableau est initialisé à sa création.
Exemple :
int tableau[] = {10,20,30,40,50};
Le nombre d'élément de chaque lignes peut ne pas être identique :
Exemple :
int[][] tabEntiers = {{1,2,3,4,5,6},
                     {1,2,3,4},
                     {1,2,3,4,5,6,7,8,9}};
Développons en Java
31

3.8.3. Le parcours d'un tableau
Exemple :
for (int i = 0; i < tableau.length ; i ++) { ... }
La variable length retourne le nombre d'éléments du tableau.
Pour passer un tableau à une méthode, il suffit de déclarer les paramètres dans l'en tête de la méthode
Exemple :
public void printArray(String texte[]){ ... 
}
Les tableaux sont toujours transmis par référence puisque se sont des objets.
U n   a c c è s   a   u n   é l é m e n t   d ' u n   t a b l e a u   q u i   d é p a s s e   s a   c a p a c i t é ,   l è v e   u n e   e x c e p t i o n   d u   t y p e
.arrayIndexOutOfBoundsException.
3.9. Les conversions de types
Lors de la déclaration, il est possible d'utiliser un cast :
Exemple :
int entier = 5;
float flottant = (float) entier;
La conversion peut entrainer une perte d'informations.
Il n'existe pas en java de fonction pour convertir : les conversions de type ce font par des méthodes. La bibliothèque de
classes API fournit une série de classes qui contiennent des méthodes de manipulation et de conversion de types
élémentaires.
Classe
Role
String
pour les chaines de caractères Unicode
Integer
pour les valeurs entières (integer)
Long
pour les entiers long signés (long)
Float
pour les nombres à virgules flottante (float)
Double
pour les nombres à virgule flottante en double précision (double)
Les classes portent le même nom que le type élémentaires sur lequel elles reposent avec la première lettre en majuscule.
Ces classes contiennent généralement plusieurs constructeurs. Pour y accéder, il faut les instancier puisque de sont des
objets.
Développons en Java
32

Exemple :
String montexte;
 montexte = new String(«test»);
L'objet montexte permet d'accéder aux méthodes de la classe .String
3.9.1. La conversion d'un entier int en chaine de caractère String
Exemple :
int i = 10;
String montexte = new String();
montexte =montexte.valueOf(i);
valueOf est également définie pour des arguments de type boolean, long, float, double et char
3.9.2. La conversion d'une chaine de caractères String en entier int
Exemple :
String montexte = new String(« 10 »);
Integer nomnombre=new Integer(montexte);
int i = monnombre.intValue(); //convertion d'Integer en int
3.9.3. La conversion d'un entier int en entier long
Exemple :
int i=10;
Integer monnombre=new Integer(i);
long j=monnombre.longValue();
3.10. La manipulation des chaines de caractères
La définition d'un caractère :
Exemple :
char touche = '%';
La définition d'une chaine :
Exemple :
String texte = « bonjour »;
Les variables de type String sont des objets. Partout ou des constantes chaines figurent entre guillemets, le compilateur
Java génère un objet de type String avec le contenu spécifié. Il est donc possible d'ecrire :
Développons en Java
33

String texte = « Java Java Java ».replace('a','o');
Les chaines ne sont pas des tableaux : il faut utiliser les méthodes de la classes String d'un objet instancié pour effectuer
des manipulations.
Il est impossible de modifier le contenu d'un objet String contruit à partir d'une constante. Cependant, il est possible
d'utiliser les méthodes qui renvoient une chaine pour modifier le contenu de la chaine
Exemple :
String texte = « Java Java Java »;
texte = texte.replace('a','o');
Java ne fonctionne pas avec le jeu de caractères ASCII ou ANSI, mais avec Unicode (Universal Code). Ceci concerne les
types char et les chaines de caractères. Le jeu de caractères Unicode code un caractère sur 2 octets. Les caractères 0 à 255
correspondent exactement au jeu de caractères ASCII
3.10.1. Les caractères spéciaux dans les chaines
Caractères spéciaux
Affichage
\'
Apostrophe
\ »
Guillemet
\\
anti slash
\t
Tabulation
\b
retour arrière (backspace)
\r
retour chariot
\f
saut de page (form feed)
\n
saut de ligne (newline)
\0ddd
caractère ASCII ddd (octal)
\xdd
caractère ASCII dd (hexadécimal)
\udddd
caractère Unicode dddd (hexadécimal)
3.10.2. L'addition de chaines
Java admet l'opérateur + comme opérateur de concaténation de chaines de caractères.
L'opérateur + permet de concatener plusieurs chaines. Il est possible d'utiliser l'opérateur +=
Exemple :
String texte = « »;
texte += « Hello »;
texte += « World3 »;
Cet opérateur sert aussi à concatener des chaines avec tous les types de bases. La variable ou constante est alors convertie
en chaine et ajoutée à la précédente. La condition préalable est d'avoir au moins une chaine dans l'expression sinon le
sinon '+' est évalué comme opérateur mathématique.
Développons en Java
34

Exemple :
.println(« La valeur de Pi est : »);
int duree = 121;
.println(« durée = » +duree); 
3.10.3. La comparaison de deux chaines
Il faut utiliser la méthode equals()
Exemple :
String texte1 = « texte 1 »;
String texte2 = « texte 2 »;
if ( texte1.equals(texte2) )... 
3.10.4. La détermination de la longueur d'une chaine
La méthode length() permet de déterminer la longueur d'une chaine.
Exemple :
String texte = « texte »;
int longueur = texte.length();
3.10.5. La modification de la casse d'une chaine
Les méthodes Java toUpperCase() et toLowerCase() permettent respectivement d'obtenir une chaine tout en majuscule ou
tout en minuscule.
Exemple :
String texte = « texte »;
String textemaj = texte.toUpperCase();
Développons en Java
35

4. La programmation orientée objet
L'idée de base de la programmation orientée objet est de rassembler dans une même entité appelée objet les données et
les traitements qui s'y appliquent.
Ce chapitre ce compose de plusieurs sections :
Le concept de classe
• 
Cette section présente le concept et la syntaxe de la déclaration d'une classe
Les objets
• 
Cette section présente la création d'un objet, sa durée de vie, le clonage d'objets, les références et la comparaison
d'objets, l'objet null, les variables de classes, la variable this et l'opérateur instanceof.
Les modificateurs d'accès
• 
Cette section présente les modificateurs d'accès des entités classes, méthodes et attributs ainsi que les mots clés
qui permettent de qualifier ces entités
Les propriétés ou attributs
• 
Cette section présente les données d'une classe : les propriétés ou attributs
Les méthodes
• 
Cette section présente la déclaration d'une méthode, la transmissions de paramètres, l'emmission de messages, la
surcharge, la signature d'une méthode et le polymorphisme et des méthodes particulières : les constructeurs, le
destructeur et les accesseurs
L'héritage
• 
Cette section présente l'héritage : son principe, sa mise en oeuvre, ces conséquences. Il présente aussi la
redéfinition d'une méthode héritée et les interfaces
Les packages
• 
Cette section présente la définition et l'utilisation des packages
Les classes internes
• 
Cette section présente une extension du langage java qui permet de definir une classe dans une autre.
La gestion dynamique des objets
• 
Cette section présente rapidement la gestion dynamique des objets grace à l'introspection
4.1. Le concept de classe
Une classe est le support de l 'encapsulation : c'est un ensemble de données et de fonctions regroupées dans une même
entité. Une classe est une description abstraite d'un objet. Les fonctions qui opèrent sur les données sont appelées des
méthodes. Instancier une classe consiste à créer un objet sur son modèle. Entre classe et objet il y a, en quelque sorte, le
même rapport qu'entre type et variable.
java est un langage orienté objet : tout appartient à une classe sauf les variables de type primitives.
Pour accéder à une classe il faut en déclarer une instance de classe ou objet.
Une classe comporte sa déclaration, des variables et la définition de ses méthodes.
Une classe se compose en deux parties : un en?tête et un corps. Le corps peut être divisé en 2 sections : la déclaration des
données et des constantes et la définition des méthodes. Les méthodes et les données sont pourvues d'attributs de
visibilité qui gère leur accessibilité par les composants hors de la classe.
Développons en Java
36

4.1.1. La syntaxe de déclaration d'une classe
modificateurs nom_de_classe [extends classe_mere] [implements interface] { ... }
ClassModifiers class ClassName [extends SuperClass] [implemenents Interfaces]
{
   // insérer ici les champs et les méthodes
}
Les modificateurs de classe (ClassModifiers) sont :
Modificateur
Role
la classe contient une ou des méthodes abstraites, qui n'ont pas de définition explicite. Une classe
abstract
déclarée abstract ne peut pas être instanciée : il faut définir une classe qui hérite de cette classe et
qui implémente les méthodes nécessaires pour ne plus être abstraite.
la classe ne peut pas être modifiée, sa redéfinition grace à l'héritage est interdite. Les classes
final
déclarées final ne peuvent donc pas avoir de classes filles.
private
la classe n'est accessible qu'à partir du fichier où elle est définie
public
La classe est accessible partout
Les modificateurs abstract et final ainsi que public et private sont mutuellement exclusifs.
Le mot clé extends permet de spécifier une superclasse éventuelle : ce mot clé permet de préciser la classe mère dans une
relation d'héritage.
Le mot clé implements permet de spécifier une ou des interfaces que la classe implémente. Cela permet de récupérer
quelques avantages de l'héritage multiple.
L'ordre des méthodes dans une classe n'a pas d'importance. Si dans une classe, on rencontre d'abord la méthode A puis la
méthode B, B peut être appelée sans problème dans A.
4.2. Les objets
Les objets contiennent des attributs et des méthodes. Les attributs sont des variables ou des objets nécessaires au
fonctionnement de l'objet. En java, une application est un objet. La classe est la description d'un objet. Un objet est une
instance d'une classe. Pour chaque instance d'une classe, le code est le même, seul les données sont différentes à chaque
objet.
4.2.1. La création d'un objet : instancier une classe
Il est nécessaire de définir la déclaration d'une variable ayant le type de l'objet désiré. La déclaration est de la forme
classe nom_de_variable
Exemple :
MaClasse m;
Développons en Java
37

L'opérateur new se charge de créer une instance de la classe et de l'associer à la variable
Exemple :
m = new MaClasse();
Il est possible de tout reunir en une seule déclaration
Exemple :
MaClasse m = new MaClasse();
Chaque instance d'une classe nécessite sa propre variable. Plusieurs variables peuvent désigner un même objet.
En Java, tous les objets sont instanciés par allocation dynamique. Dans l'exemple, la variable m contient une référence
sur l'objet instancié ( contient l'adresse de l'objet qu'elle désigne : attention toutefois, il n'est pas possible de manipuler ou
d'effectuer des opérations directement sur cette adresse comme en C).
Si m2 désigne un objet de type MaClasse, l'instruction m2 = m ne définit pas un nouvel objet mais m et m2 désignent
tous les deux le même objet.
L'opérateur new est un opérateur de haute priorité qui permet d'instancier des objets et d'appeler une méthode particulière
de cet objet : le contructeur. Il fait appel à la machine virtuelle pour obtenir l'espace mémoire nécessaire à la
représentation de l'objet puis appelle le constructeur pour initialiser l'objet dans l'emplacement obtenu. Il renvoie une
valeur qui référence l'objet instancié.
Si l'opérateur new n'obtient pas l'allocation mémoire nécessaire il lève l'exception OutOfMemoryError.
Remarque sur les objets de type String : Un objet String est automatiquement créer lors de l'utilisation d'une
constante chaine de caractères sauf si celle ci est déjà utilisée dans la classe. Ceci permet une simplification
dans l'écriture des programmes.
Exemple :
String chaine = « bonjour » 
et String chaine = new String(« bonjour ») 
sont équivalents.
4.2.2. La durée de vie d'un objet
Les objets ne sont pas des éléments statiques et leur durée de vie ne correspond pas forcément à la durée d'exécution du
programme.
La durée de vie d'un objet passe par trois étapes :
la déclaration de l'objet et l'instanciation grace à l'opérateur new
• 
Exemple :
nom_de_classe nom_d_objet = new nom_de_classe( ... );
l'utilisation de l'objet en appelant ces méthodes
• 
la suppression de l'objet : elle est automatique en java grace à la machine virtuelle. La restitution de la mémoire
• 
Développons en Java
38

inutilisée est prise en charge par le récupérateur de mémoire (garbage collector). Il n'existe pas d'instruction
delete comme en C++.
4.2.3. La création d'objets identiques
Exemple :
MaClasse m1 = new MaClasse();
MaClasse m2 = m1;
m1 et m2 contiennent la même référence et pointent donc tous les deux sur le même objet : les modifications faites à
partir d'une des variables modifient l'objet.
Pour créer une copie d'un objet, il faut utiliser la méthode clone() : cette méthode permet de créer un deuxième objet
indépendant mais identique à l'original. Cette méthode est héritée de la classe Object qui est la classe mère de toute les
classes en Java.
Exemple :
MaClasse m1 = new MaClasse();
MaClasse m2 = m1.clone();
m1 et m2 ne contiennent plus la même référence et pointent donc sur des objets différents.
4.2.4. Les références et la comparaison d'objets
Les variables de type objet que l'on déclare ne contiennent pas un objet mais une référence vers cette objet. Lorque l'on
écrit c1 = c2 (c1 et c2 sont des objets), on copie la référence de l'objet c2 dans c1 : c1 et c2 réfèrent au même objet (ils
pointent sur le même objet). L'opérateur == compare ces références. Deux objets avec des propriétés identiques sont
deux objets distincts :
Exemple :
Rectangle r1 = new Rectangle(100,50);
Rectangle r2 = new Rectangle(100,50);
if (r1 == r1) { ... } // vrai
if (r1 == r2) { ... } // faux
Pour comparer l'égalité des variables de deux instances, il faut munir la classe d'un méthode à cette effet : la méthode
equals héritée de Object.
Pour s'assurer que deux objets sont de la même classe, il faut utiliser la méthode getClass() de la classe Object dont
toutes les classes héritent.
Exemple :
(obj1.getClass().equals(obj2.getClass())
4.2.5. L'objet null
L'objet null est utilisable partout. Il n'appartient pas à une classe mais il peut être utilisé à la place d'un objet de n'importe
quelle classe ou comme paramètre. null ne peut pas etre utilisé comme un objet normal : il n'y a pas d'appel de méthodes
et aucunes classes ne peut en hériter.
Développons en Java
39

Le fait d'initialiser un variable référent un objet à null permet au ramasse miette de libérer la mémoire allouée à l'objet.
4.2.6. Les variables de classes
Elles ne sont définies qu'une seule fois quelque soit le nombre d'objets instanciés de la classe. Leur déclaration est
accompagnée du mot clé static
Exemple :
public class MaClasse() { 
    static int compteur = 0;
}
L'appartenance des variables de classe à une classe entière et non à un objet spécifique permet de remplacer le nom de la
variable par le nom de la classe.
Exemple :
MaClasse m = new MaClasse();
int c1 = m.compteur;
int c2 = MaClasse.compteur;
c1 et c2 possèdent la même valeur.
Ce type de variable est utile pour par exemple compter le nombre d'instanciation de la classe qui est faite.
4.2.7. La variable this
Cette variable sert à référencer dans une méthode l'instance de l'objet en cours d'utilisation. this est un objet qui est égale
à l'instance de l'objet dans lequel il est utilisé.
Exemple :
private int nombre;
public maclasse(int nombre) {
   nombre = nombre; // variable de classe = variable en paramètre du constructeur
}
Il est préférable d'écrire
this.nombre = nombre;
Cette référence est habituellement implicite :
Exemple :
class MaClasse() {
  String chaine = « test » ;
  Public String getChaine() { return chaine) ; 
  // est équivalent à public String getChaine (this.chaine);
}
Développons en Java
40

This est aussi utilisé quand l'objet doit appeler une méthode en se passant lui même en paramètre de l'appel.
4.2.8. L'opérateur instanceof
L'opérateur instanceof permet de déterminer la classe de l'objet qui lui est passé en paramètre. La syntaxe est objet
instanceof classe
Exemple :
void testClasse(Object o) {
   if (o instanceof MaClasse )
      .println(« o est une instance de la classe MaClasse »);
   else .println(« o n'est pas un objet de la classe MaClasse »);
}
Il n'est toutefois pas possible d'appeler une méthode de l'objet car il est passé en paramètre avec un type Object
Exemple :
void afficheChaine(Object o) {
    if (o instanceof MaClasse)
        .println(o.getChaine());
        // erreur à la compil car la méthode getChaine()
        //n'est pas définie dans la classe Object
}
Pour résoudre le problème, il faut utiliser la technique du casting (conversion).
Exemple :
void afficheChaine(Object o) {
   if (o instanceof MaClasse)
   {
      MaClasse m = (MaClasse) o;
      .println(m.getChaine());
      // OU .println( ((MaClasse) o).getChaine() );
   }
}
4.3. Les modificateurs d'accès
Ils se placent avant ou après le type de l'objet mais la convention veut qu'ils soient placés avant.
Ils s'appliquent aux classes et/ou aux méthodes et/ou aux attributs.
Ils ne peuvent pas être utilisés pour qualifier des variables locales : seules les variables d'instances et de classes peuvent
en profiter.
Ils assurent le contrôle des conditions d'héritage, d'accès aux éléments et de modification de données par les autres objets.
4.3.1. Les mots clés qui gèrent la visibilité des entités
De nombreux langages orientés objet introduisent des attributs de visibilité pour reglémenter l'accès aux classes et aux
objets, aux méthodes et aux données.
Développons en Java
41

Il existe 3 modificateurs qui peuvent être utilisés pour définir les attributs de visibilité des entités (classes, méthodes ou
attributs) : public, private et protected. Leur utilisation permet de définir des niveaux de protection différents (présenté
dans un ordre croissant de niveau de protection offert):
Modificateur
Role
Une variable, méthode ou classe déclarée public est visible par tout les autres objets. Dans la version
1.0, une seule classe public est permise par fichier et son nom doit correspondre à celui du fichier.
public
Dans la philosophie orientée objet aucune donnée d'une classe ne devraient être déclarée publique : il
est préférable d'écrire des méthodes pour la consulter et la modifier
Il n'existe pas de mot clé pour définir ce niveau, qui est le niveau par défaut lorsqu'aucun
par défaut :
modificateur n'est précisé. Cette déclaration permet à une entité (classe, méthode ou variable) d'être
package friendly visible par toutes les classes se trouvant dans le même package.
Si une classe, une méthode ou une variable est déclarée protected , seules les méthodes présentes
protected
dans le même package que cette classe ou ses sous classes pourront y acceder. On ne peut pas
qualifier une classe avec protected.
C'est le niveau de protection le plus fort. Les composants ne sont visibles qu'à l'intérieur de la classe :
ils ne peuvent être modifiés que par des méthodes définies dans la classe prévues à cet effet. Les
private
méthodes déclarée private ne peuvent pas être en même temps déclarée abstract car elles ne peuvent
pas être redéfinies dans les classes filles.
Ces modificateurs d'accès sont mutuellement exclusifs.
4.3.2. Le mot clé static
Le mot clé static s'applique aux variables et aux méthodes.
Les variables d'instance sont des variables propres à un objet. Il est possible de définir une variable de classe qui est
partagée entre toutes les instances d'une même classe : elle n'existe donc qu'une seule fois. Une telle variable permet de
stocker une constante ou une valeur modifiée tour à tour par les instances de la classe. Elle se définit avec le mot clé
static.
Exemple :
public class Cercle {
    static float pi = 3.1416f; 
    float rayon;
    public Cercle(float rayon) { this.rayon = rayon; }
    public float surface() { return rayon * rayon * pi;}
}
Il est aussi possible par exemple de mémoriser les valeurs min et max d'un ensemble d'objet de même classe.
Une méthode static est une méthode qui n'agit pas sur des variables d'instance mais uniquement sur des variables de
classe. Les méthodes ainsi définies peuvent être appelée avec la notation classe.méthode au lieu de objet.méthode. Ces
méthodes peuvent être utilisées sans instancier un objet de la classe.
Il n'est pas possible d'appeler une méthode d'instance ou d'accéder à une variable d'instance à partir d'une méthode de
classe statique
Développons en Java
42

4.3.3. Le mot clé final
Le mot cle final s'applique aux variables, aux méthodes et aux classes.
Une variable qualifiée de final signifie que la variable est constante. Le compilateur ne contrôle ni n'empéche la
modification. On ne peut déclarer de variables final locale à une méthode. Les constantes sont qualifiées de final et static
Exemple :
public static final float PI = 3.141f;
Une méthode final ne peut pas être redéfinie dans une sous classe. Une méthode possédant le modificateur final pourra
être optimisée par le compilateur car il est garanti qu'elle ne sera pas sous classée.
Lorsque le modificateur final est ajouté à une classe, il est interdit de créer un classe qui en hérite.
Pour une méthode ou une classe, on renonce à l'héritage mais ceci peut s'avérer nécessaire pour des questions de sécurité
ou de performance. Le test de validité de l'appel d'une méthode est bien souvent repoussé à l'éxécution, en fonction du
type de l'objet appelé (c'est le polymorphisme). Ces tests ont un coup en terme de performance.
4.3.4. Le mot clé abstract
Le mot cle abstract s'applique aux méthodes et aux classes.
Abstract indique que la classe ne pourra être instanciée telle quelle. De plus, toutes les méthodes de cette classe abstract
ne sont pas implémentées et devront être redéfinies par des méthodes complètes dans ses sous classes.
Abstract permet de créer une classe qui sera une sorte de moule. Toutes les classes dérivées pouront profiter des
méthodes héritées et n'auront à implémenter que les méthodes déclarées abstract.
Exemple :
abstract class ClasseAbstraite {
    ClasseBastraite() { ... //code du constructeur }
    void méthode() { ... // code partagé par tous les descendants}
    abstract void méthodeAbstraite();
}
class ClasseComplete extends ClasseAbstraite {
    ClasseComplete() { super(); ... }
    void méthodeAbstraite() { ... // code de la méthode }
    // void méthode est héritée
}
Une méthode abstraite est une méthode déclarée avec le modificateur abstract et sans corps. Elle correspond à une
méthode dont on veut forcer l'implémentation dans une sous classe. L'abstraction permet une validation du codage : une
sous classe sans le modificateur abstract et sans définition explicite d'une ou des méthodes abstraites génère une erreur de
compilation.
Une classe est automatiquement abstraite dès qu'une de ses méthodes est déclarée abstraite. Il est possible de définir une
classe abstraite sans méthodes abstraites.
Développons en Java
43

4.3.5. Le mot clé synchronized
Permet de gérer l'accès concurrent aux variables et méthodes lors de traitement de thread (exécution « simultanée » de
plusieurs petites parties de code du programme)
4.3.6. Le mot clé volatile
Le mot cle volatile s'applique aux variables.
Précise que la variable peut être changée par un périphérique ou de manière asynchrone. Cela indique au compilateur de
ne pas stocker cette variable dans des registres. A chaque utilisation, on lit la valeur et on réécrit immédiatement le
résultat s'il a changé.
4.3.7. Le mot clé native
Une méthode native est une méthode qui est implémentée dans un autre langage. L'utilisation de ce type de méthode
limite la portabilité du code mais permet une vitesse exécution plus rapide.
4.4. Les propriétés ou attributs
Les données d'une classe sont contenues dans les propriétés ou attributs. Ce sont des variables qui peuvent être des
variables d'instances, des variables de classes ou des constantes.
4.4.1. Les variables d'instances
Une variable d'instance nécessite simplement une déclaration de la variable dans le corps de la classe.
Exemple :
public class MaClasse {
   public int valeur1 ;
   int valeur2 ;
   protected int valeur3 ;
   private int valeur4 ;
}
Chaque instance de la classe a accès à sa propre occurrence de la variable.
4.4.2. Les variables de classes
Les variables de classes sont définies avec le mot clé static
Exemple ( code java 1.1 ) :
public class MaClasse {
   static int compteur ;
}
Développons en Java
44

Chaque instance de la classe partage la même variable.
4.4.3. Les constantes
Les constantes sont définies avec le mot clé final : leur valeur ne peut pas être modifiée.
Exemple ( code java 1.1 ) :
public class MaClasse {
   final double pi=3.14 ;
}
4.5. Les méthodes
Les méthodes sont des fonctions qui implémentent les traitements de la classe.
4.5.1. La syntaxe de la déclaration
La syntaxe de la déclaration d'une méthode est :
modificateurs type_retourné nom_méthode ( arg1, ... ) {... }
    // définition des variables locales et du bloc d'instructions
}
Le type retourné peut être élémentaire ou correspondre à un objet. Si la méthode ne retourne rien, alors on utilise void
Le type est le nombre d'arguments déclarés doivent correspondrent au type et au nombre d'arguments transmis. Il n'est
pas possible d'indiquer des valeurs par défaut dans les paramètres. Les arguments sont passés par valeur : la méthode fait
une copie de la variable qui lui est locale. Lorsqu'un objet est transmis comme argument à une méthode, cette dernière
reçoit une référence qui désigne son emplacement mémoire d'origine et qui est une copie de la variable . Il est possible de
modifier l'objet grace à ces méthodes mais il n'est pas possible de remplacer la référence contenue dans la variable passée
en paramètre : ce changement n'aura lieu que localement à la méthode.
Les modificateurs de méthodes sont :
Modificateur
Role
public
la méthode est accéssible aux méthodes des autres classes
private
l'usage de la méthode est réservée aux autres méthodes de la même classe
la méthode ne peut être invoquée que par des méthodes de la classe ou de ses sous
protected
classes
final
la méthode ne peut être modifiée (redifinition lors de l'héritage interdite)
la méthode appartient simultanément à tous les objets de la classe (comme une
constante déclarée à l'intérieur de la classe). Il est inutile d'instancier la classe pour
static
appeler la méthode mais la méthode ne peut pas manipuler de variable d'instance.
Elle ne peut utiliser que des variables de classes.
la méthode fait partie d'un thread. Lorsqu'elle est appelée, elle barre l'accès à son
synchronized
instance. L'instance est à nouveau libérée à la fin de son éxécution.
native
le code source de la méthode est écrit dans un autre langage
Développons en Java
45

Sans modificateur, la méthode peut être appelée par toutes autres méthodes des classes du package auquel appartient la
classe.
La valeur de retour de la méthode doit être transmise par l'instruction return. Elle indique la valeur que prend la méthode
et termine celle ci : toutes les instructions qui suivent return sont donc ignorées.
Exemple :
int add(int a, int b) {
   return a + b; 
}
Il est possible d'inclure une instruction return dans une méthode de type void : cela permet de quitter la méthode.
La méthode main() de la classe principale d'une application doit être déclarée de la façon suivante :
Déclaration d'une méthode main() :
public static void main (String args[]) { ... }
Si la méthode retourne un tableau alors les [] peuvent être préciser après le type de retour ou après la liste des paramètres
:
Exemple :
int[] valeurs() { ... }
int valeurs()[] { ... }
4.5.2. La transmission de paramètres
Lorsqu'un objet est passé en paramètre, ce n'est pas l'objet lui même qui est passé mais une référence sur l'objet. La
référence est bien transmise par valeur et ne peut pas être modifiée mais l'objet peut être modifié via un message (appel
d'une méthode).
Pour transmettre des arguments par référence à une méthode, il faut les encapsuler dans un objet qui prévoit les méthodes
nécessaires pour les mises à jour.
Si un objet o transmet sa variable d'instance v en paramètre à une méthode m, deux situations sont possibles :
si v est une variable primitive alors elle est passée par valeur : il est impossible de la modifier dans m pour que v
• 
en retour contiennent cette nouvelle valeur.
si v est un objet alors m pourra modifier l'objet en utilisant une méthode de l'objet passé en paramètre.
• 
4.5.3. L'emmission de messages
Un message est émis lorsqu'on demande à un objet d'exécuter l'une de ses méthodes.
La syntaxe d'appelle d'une méthode est : nom_objet.nom_méthode(parametre, ... ) ;
Si la méthode appelée ne contient aucun paramètre, il faut laisser les parenthèses vides.
Développons en Java
46

4.5.4. L'enchainement de références à des variables et à des méthodes
Exemple :
.Println("bonjour");
Deux classes sont impliqués dans l'instruction : System et PrintStream. La classe System possède une variable nommée
out qui est un objet de type PrintStream. Println() est une méthode de la classe PrintStream. L'instruction signifie : «
utilise la méthode Println() de la variable out de la classe System ».
4.5.5. La surcharge de méthodes
La surcharge d'une méthode permet de définir plusieurs fois une même méthode avec des arguments différents. Le
compilateur choisi la méthode qui doit être appellée en fonction du nombre et du type des arguments. Ceci permet de
simplifier l'interface des classes vis à vis des autres classes.
Une méthode est surchargée lorqu'elle exécute des actions différentes selon le type et le nombre de paramètres transmis.
Exemple :
class affiche{
    public void afficheValeur(int i) {
        .pintln(« nombre entier = » + i);
    }
    public void afficheValeur(float f) {
        .println(« nombre flottant = » + f);
    }
}
Il n'est pas possible d'avoir deux méthodes de même nom dont tous les paramètres sont identiques et dont seul le type
retourné diffère.
Exemple :
class Affiche{
    public float convert(int i){
         return((float) i);
    }
    public double convert(int i){
        return((double) i);
    }
}
Résultat à la compilation :
C:\>javac
:5: Methods can't be redefined with a different return type: double
convert(int) was float convert(int)
public double convert(int i){
       ^
1 error
Développons en Java
47

4.5.6. La signature des méthodes et le polymorphisme
Il est possible de donner le même nom à deux méthodes différentes à condition que les signatures de ces deux méthodes
soient différentes. La signature d'une méthode comprend le nom de la classe, le nom de la méthode et les types des
paramètres. Cette facilité permet de mettre en oeuvre la polymorphisme.
Le polymorphisme est la capacité, pour un même message de correspondre à plusieurs formes de traitements selon l'objet
auquel ce message est adressé. La gestion du polymorphisme est assurée par la machine virtuelle dynamiquement à
l'exécution
4.5.7. Les constructeurs
La déclaration d'un objet est suivie d'une sorte d'initialisation par le moyen d'une méthode particulière appelée
constructeur pour que les variables aient une valeur de départ. Elle n'est systématiquement invoquée que lors de la
création d'un objet.
Le constucteur suit la définition des autres méthodes excepté que son nom doit obligatoirement correspondre à celui de la
classe et qu'il n'est pas typé, pas même void, donc il ne peut pas y avoir d'instruction return dans un constructeur. On peut
surcharger un constructeur.
La définition d'un constructeur est facultative. Si elle n'est pas définie, la machine virtuelle appelle un constructeur par
défaut vide créé automatiquement. Dès qu'un constructeur est explicitement défini, Java considère que le programmeur
prend en charge la création des constructeurs et que le mécanisme par défaut, qui correspond à un constructeur sans
paramètres, est supprimé. Si on souhaite maintenir ce mécanisme, il faut définir explicitement un constructeur sans
paramètres.
Il existe plusieurs manière de définir un constructeur :
le constructeur simple : ce type de constructeur ne nécessite pas de définition explicite : son existence découle
1. 
automatiquement de la définition de la classe.
Exemple :
public MaClasse() {}
le constructeur avec initialisation fixe : il permet de créer un constructeur par défaut
2. 
Exemple :
public MaClasse() {
    nombre = 5;
}
le constructeur avec initialisation des variables : pour spécifier les valeurs de données à initialiser on peut les
3. 
passer en paramètres au constructeur
Exemple :
public MaClasse(int valeur) {
     nombre = valeur;
}
Développons en Java
48

4.5.8. Le destructeur
Un destructeur permet d'éxécuter du code lors de la libération de la place mémoire occupée par l'objet. En java, les
destructeurs appellés finaliseurs (finalizers), sont automatiquement appellés par le garbage collector.
Pour créer un finaliseur, il faut redéfinir la méthode finalize() héritée de la classe Object.
4.5.9. Les accesseurs
L'encapsulation permet de sécuriser l'accès aux données d'une classe. Ainsi, les données déclarées private à l'intérieur
d'une classe ne peuvent être accédées et modifiées que par des méthodes définies dans la même classe. Si une autre classe
veut accéder aux données de la classe, l'opération n'est possible que par l'intermédiaire d'une méthode de la classe prévue
à cet effet. Ces appels de méthodes sont appelés « échanges de message ».
Un accesseur est une méthode publique qui donne l'accès à une variable d'instance privée. Pour une variable d'instance, il
peut ne pas y avoir d'accesseur, un seul accesseur en lecture ou un accesseur en lecture et un en écriture. Par convention,
les accesseurs en lecture commencent par get et les accesseurs en écriture commencent par set.
Exemple :
private int valeur = 13;
public int getValeur(){
    return(valeur);
}
public void setValeur(int val) {    
    valeur = val;
}
4.6. L'héritage
4.6.1. Le principe de l'héritage
L'héritage est un mécanisme qui facilite la réutilisation du code et la gestion de son évolution.
Grace à l'heritage, les objets d'une classe ont accès aux données et aux méthodes de la classe parent et peuvent les
étendre. Les sous classes peuvent redéfinir les variables et les méthodes héritées. Pour les variables, il suffit de les
redéclarer sous le même nom avec un type différent. Les méthodes sont redéfinies avec le même nom, les mêmes types et
le même nombre d'arguments, sinon il s'agit d'une surcharge.
L'héritage successif de classes permet de définir une hiérarchie de classe qui ce compose de super classes et de sous
classes. Une classe qui hérite d'une autre est une sous classe et celle dont elle hérite est une super classe. Une classe peut
avoir plusieurs sous classes. Une classe ne peut avoir qu'une seule classe mère : il n'y a pas d'héritage multiple en java.
Object est la classe parente de toutes les classes en java. Toutes les variables et méthodes contenues dans Object sont
accessibles à partir de n'importe quelle classe car par héritage succéssif toutes les classes héritent d'Object.
4.6.2. La mise en oeuvre de l'héritage
On utilise le mot clé extends pour indiquer qu'une classe hérite d'une autre. En l'absence de ce mot réservé associé à une
classe, le compilateur considère la classe Object comme classe parent.
Développons en Java
49

Exemple :
class Fille extends Mere { ... }
Pour invoquer une méthode d'une classe parent, il suffit d'indiquer la méthode préfixée par super. Pour appeler le
constructeur de la classe parent il suffit d'écrire super(paramètres) avec les paramètres adéquats.
Le lien entre une classe fille et une classe parent est géré par le langage : une évolution des règles de gestion de la classe
parent conduit à modifier automatiquement la classe fille dès que cette dernière est recompilée.
En java, il est obligatoire dans un constructeur d'une classe fille de faire appel explicitement ou implicitement au
constructeur de la classe mère.
4.6.3. L'accès aux propriétés héritées
Les variables et méthodes définies avec le modificateur d'accès public restent publiques à travers l'héritage et toutes les
autres classes.
Une variable d'instance définie avec le modificateur private est bien héritée mais elle n'est pas accessible directement
mais via les méthodes héritées.
Si l'on veut conserver pour une variable d'instance une protection semblable à celle assurée par le modificateur private, il
faut utiliser le modificateur protected. La variable ainsi définie sera hérité dans toutes les classes descendantes qui
pourront y accéder librement mais ne sera pas accessible hors de ces classes directement.
4.6.4. Le transtypage induit par l'héritage facilitent le polymorphisme
L'héritage définit un cast implicite de la classe fille vers la classe mere : on peut affecter à une référence d'une classe
n'importe quel objet d'une de ses sous classes.
Exemple : la classe Employe hérite de la classe Personne
   Personne p = new Personne («Dupond», «Jean»);
    Employe e = new Employe(«Durand», «Julien», 10000);
    p = e ; // ok : Employe est une sous classe de Personne
    Objet obj;
    obj = e ; // ok : Employe herite de Personne qui elle même hérite de Object
Il est possible d'écrire le code suivant si Employe hérite de Personne
Exemple :
   Personne[] tab = new Personne[10];
    tab[0]:= new Personne( «Dupond»,«Jean»);
    tab[1]:= new Employe(«Durand», «Julien», 10000);
Il est possible de surcharger une méthode héritée : la forme de la méthode à éxécuter est choisie en fonction des
paramètres associés à l'appel.
Compte tenu du principe de l'héritage, le temps d'exécution du programme et la taille du code source et de l'éxécutable
augmentent.
Développons en Java
50

4.6.5. La redéfinition d'une méthode héritée
La redéfinition d'une méthode héritée doit impérativement conserver la déclaration de la méthode parent (type et nombre
de paramètres, la valeur de retour et les exceptions propagées doivent être identique).
Si la signature de la méthode change, ce n'est plus une redéfinition mais une surcharge. Cette nouvelle méthode n'est pas
héritée : la classe mere ne possède pas de méthode possédant cette signature.
4.6.6. Les interfaces et l'héritage multiple
Avec l'héritage multiple, une classe peut hériter en même temps de plusieurs super classes. Ce mécanisme n'existe pas en
java. Les interfaces permettent de mettre en oeuvre un mécanisme de remplacement.
Une interface est un ensemble de constantes et de déclarations de méthodes correspondant un peu à une classe abstraite.
C'est une sorte de standard auquel une classe peut répondre. Tous les objets qui se conforment à cette interface (qui
implémentent cette interface) possèdent les méthodes et les constantes déclarée dans celle?ci. Plusieurs interfaces
peuvent être implémentées dans une même classe.
Les interfaces se déclarent avec le mot cle interface et sont intégrées aux autres classes avec le mot clé implements. Une
interface est implicitement déclarée avec le modificateur abstract.
Déclaration d'une interface :
[public] interface nomInterface [extends nomInterface1, nomInterface2 ... ] {
    // insérer ici des méthodes ou des champs static
}
Implémentation d'une interface :
Modificateurs class nomClasse [extends superClasse] 
   [implements nomInterface1, nomInterface 2, ...] {
    //insérer ici des méthodes et des champs
}
Exemple :
interface AfficheType {
    void AfficheType();
}
class Personne implements AfficheType {
    public void afficheType() {
        .println(« Je suis une personne »);
    }
}
class Voiture implements AfficheType {
    public void afficheType() {
        .println(« Je suis une voiture »);
    }

Développons en Java
51

Exemple : déclaration d'un interface à laquelle doit se conformer tout individus
interface Individu {
    String getNom();
    String getPrenom();
    Date getDateNaiss();
}
Toutes les méthodes d'une interface sont publiques et abstraites : elles sont implicitement déclarées comme telles.
Une interface peut être d'accès public ou package. Si elle est publique, toutes ses méthodes sont publiques même si elles
ne sont pas déclarées avec le modificateur public. Si elle est d'accès package, il s'agit d'une interface d'implémentation
pour les autres classes du package et ses méthodes ont le même accès package : elles sont accessible à toutes les classes
du packages.
Les seules variables que l'on peut définir dans une interface sont des variables de classe qui doivent être constantes : elles
sont donc implicitement déclarées avec le modificateur static et final même si elles sont définies avec d'autres
modificateurs.
Toute classe qui implémente cette interface doit au moins posséder les méthodes qui sont déclarées dans l'interface.
L'interface ne fait que donner une liste de méthodes qui seront à définir dans les classes qui implémentent l'interface.
Les méthodes déclarées dans une interface publique sont implicitement publiques et elles sont héritées par toutes les
classes qui implémentent cette interface. Une tel classe doit, pour être instanciable, définir toutes les méthodes héritées
de l'interface.
Une classe peut implémenter une ou plusieurs interfaces tout en héritant de sa classe mère.
L'implémentation d'une interface définit un cast : l'implémentation d'une interface est une forme d'héritage. Comme pour
l'héritage d'une classe, l'héritage d'une classe qui implémente une interface définit un cast implicite de la classe fille vers
cette interface. Il est important de noter que dans ce cas il n'est possible de faire des appels qu'à des méthodes de
l'interface. Pour utiliser des méthodes de l'objet, il faut définir un cast explicite : il est préférable de controler la classe de
l'objet pour éviter une exception ClassCastException à l'éxecution
4.6.7. Des conseils sur l'héritage
Lors de la création d'une classe « mère » il faut tenir compte des points suivants :
la définition des accès aux variables d'instances, très souvent privées, doit être réfléchie entre protected et
• 
private
pour empecher la redéfinition d'une méthode (surcharge) il faut la déclarer avec le modificateur final
• 
Lors de la création d'une classe fille, pour chaque méthode héritée qui n'est pas final, il faut envisager les cas suivant :
la méthode héritée convient à la classe fille : on ne doit pas la redéfinir
• 
la méthode héritée convient mais partiellement du fait de la spécialisation apportée par la classe fille : il faut la
• 
redéfinir voir la surcharger. La plupart du temps une redéfinition commencera par appeler la méthode héritée
(via super) pour garantir l 'évolution du code
la méthode héritée ne convient pas : il faut redéfinir ou surcharger la méthode sans appeler la méthode héritée
• 
lors de la redéfinition.
4.7. Les packages
Développons en Java
52

4.7.1. La définition d'un package
En java, il existe un moyen de regrouper des classe voisines ou qui couvrent un même domaine : ce sont les packages.
Pour réaliser un package, on écrit un nombre quelconque de classes dans plusieurs fichiers d'un même repertoire et au
début de chaque fichier on met la directive ci dessous ou nom?du?package doit être identique au nom du répertoire :
package nomPackage;
La hiérarchie d'un package se retrouve dans l'arborescence du disque dur puisque chaque package est dans un répertoire
nommé du nom du package.
Remarque : Il est préférable de laisser les fichiers source .java avec les fichiers compilés .class
D'une façon générale, l'instruction package associe toutes les classes qui sont définies dans un fichier source à un même
package.
Le mot clé package doit être la première instruction dans un fichier source et il ne doit être présent qu'une seule fois dans
le fichier source (une classe ne peut pas appartenir à plusieurs packages).
4.7.2. L'utilisation d'un package
Pour utiliser ensuite le package ainsi créé, on l'importe dans le fichier :
import nomPackage.*;
Pour importer un package, il y a trois méthodes si le chemin de recherche est correctement renseigné :
Exemple
Role
les classes ne peuvent pas être simplement désignées par leur nom et il
import nomPackage;
faut aussi préciser le nom du package
import nomPackage.*;
toutes les classes du package sont importées
appel à une seule classe : l'avantage de cette notation est de réduire le
import nomPackage.nomClasse;
temps de compilation
Attention : l'astérisque n'importe pas les sous paquetages. Par exemple, il n'est pas possible d'écrire import
java.*.
Il est possible d'appeler une méthode d'un package sans inclure ce dernier dans l'application en precisant son nom
complet :
éthode(arg1, arg2 ... )
Il existe plusieurs types de packages : le package par défaut (identifié par le point qui représente le répertoire courant et
permet de localiser les classes qui ne sont pas associées à un package particulier), les packages standards qui sont
empaquetés dans le fichier et les packages personnels
Le compilateur implémente automatiquement une commande import lors de la compilation d'un programme Java même
si elle ne figure pas explicitement au début du programme : import .*; Ce package contient entre autre les
classes de base de tous les objets java dont la classe Object.
Développons en Java
53

Un package par défaut est systématiquement attribué par le compilateur aux classes qui sont définies sans déclarer
explicitement une appartenance à un package. Ce package par défaut correspond au répertoire courant qui est le
répertoire de travail.
4.7.3. La collision de classes.
Deux classes entre en collision lorsqu'elles portent le même nom mais qu'elles sont définies dans des packages différents.
Dans ce cas, il faut qualifier explicitement le nom de la classe avec le nom complet du package.
4.7.4. Les packages et l'environnement système
Les classes Java sont importées par le compilateur (au moment de la compilation) et par la machine virtuelle (au moment
de l'éxécution). Les techniques de chargement des classes varient en fonction de l'implémentation de la machine virtuelle.
Dans la plupart des cas, une variable d'environnement CLASSPATH référence tous les répertoires qui hébergent des
packages succeptibles d'être importés.
Exemple sous Windows :
CLASSPATH = .;C:\Java\JDK\Lib\; C:\rea_java\package
L'importation des packages ne fonctionne que si le chemin de recherche spécifié dans une variable particulière pointe sur
les packages, sinon le nom du package devra refléter la structure du répertoire ou il se trouve. Pour déterminer l'endroit
où se trouvent les fichiers .class à importer, le compilateur utilise une variable d'environnement dénommée
CLASSPATH. Le compilateur peut lire les fichiers .class comme des fichiers indépendants ou comme des fichiers ZIP
dans lesquels les classes sont reunies et compressées.
4.8. Les classes internes
Les classes internes (inner classes) sont une extension du langage java introduite dans la version 1.1 du JDK. Ce sont des
classes qui sont définies dans une autre classe. Les difficultés dans leur utilisation concerne leur visibilité et leur accès
aux membres de la classe dans laquelle elles sont définies.
Exemple très simple :
public class ClassePrincipale1 {
  class ClasseInterne {
  }
}
Les classes internes sont particulièrement utiles pour :
permettre de définir une classe à l'endroit ou une seule autre en a besoin
• 
définir des classes de type adapter (essentiellement à partir du JDK 1.1 pour traiter des évenements émis par les
• 
interfaces graphiques)
définir des méthodes de type callback d'une façon générale
• 
Pour permettre de garder une compatibilité avec la version précédente de la JVM, seul le compilateur a été modifié. Le
compilateur interprète la syntaxe des classes internes pour modifier le code source et générer du byte code compatible
avec la première JVM.
Il est possible d'imbriquer plusieurs classes internes. Java ne possèdent pas de restrictions sur le nombre de classes qu'il
est ainsi possible d'imbriquer. En revanche une limitation peut intervenir au niveau du système d'exploitation en ce qui
concerne la longueur du nom du fichier .class généré pour les différentes classes internes.
Développons en Java
54

Si plusieurs classes internes sont imbriquées, il n'est pas possible d'utiliser un nom pour la classe qui soit déjà attribuée à
une de ces classes englobantes. Le compilateur génèrera une erreur à la compilation.
Exemple :
public class ClassePrincipale6 {
  class ClasseInterne1 {
    class ClasseInterne2 {
      class ClasseInterne3 {
      }
    }
  }
}
Le nom de la classe interne utilise la notation qualifié avec le point préfixé par le nom de la classe principale. Ainsi, pour
utiliser ou accéder à une classe interne dans le code, il faut la préfixer par le nom de la classe principale suivi d'un point.
Cependant cette notation ne représente pas physiquement le nom du fichier qui contient le byte code. Le nom du fichier
qui contient le byte code de la classe interne est modifié par le compilateur pour éviter des conflits avec d'autres nom
d'entité : à partir de la classe principale, les points de séparation entre chaque classe interne sont remplacé par un
caractère $ (dollard).
Par exemple, la compilation du code de l'exemple précédent génère quatres fichiers contenant le byte code :
ClassePrincipale6$ClasseInterne1$ClasseInterne2ClasseInterne3.class
ClassePrincipale6$ClasseInterne1$ClasseInterne2.class
ClassePrincipale6$ClasseInterne1.class
ClassePrincipale6.class
L'utilisation du signe $ entre la classe principale et la classe interne permet d'éviter des confusions de nom entre le nom
d'une classe appartenant à un package et le nom d'une classe interne.
L'avantage de cette notation est de créer un nouvel espace de nommage qui dépend de la classe et pas d'un package. Ceci
renforce le lien entre la classe interne et sa classe englobante.
C'est le nom du fichier qu'il faut préciser lorsque l'on tente de charger la classe avec la méthode forName() de la classe
Class. C'est aussi sous cette forme qu'est restitué le résultat d'un appel aux méthodes getClass().getName() sur un objet
qui est une classe interne.
Exemple :
public class ClassePrincipale8 {
  public class ClasseInterne {
  }
  public static void main(String[] args) {
    ClassePrincipale8 cp = new ClassePrincipale8();
    ClassePrincipale8.ClasseInterne ci = cp. new ClasseInterne() ;
    .println(ci.getClass().getName());                
  }
}
Resultat :
java ClassePrincipale8
ClassePrincipale8$ClasseInterne
L'accessibilité à la classe interne respecte les règles de visibilité du langage. Il est même possible de définir une classe
interne private pour limiter son accès à sa seule classe principale.
Développons en Java
55

Exemple :
public class ClassePrincipale7 {
        private class ClasseInterne {
        }
}
Il n'est pas possible de déclarer des membres statiques dans une classe interne :
Exemple :
public class ClassePrincipale10 {
        public class ClasseInterne {
                static int var = 3;
        }
}
Resultat :
javac
:3: Variable var can't be static in inner class ClassePri
ncipale10. ClasseInterne.  Only members of interfaces and top?level classes can
be static.
                static int var = 3;
                               ^
1 error
Pour pouvoir utiliser une variable de classe dans une classe interne, il faut la déclarer dans sa classe englobante.
Il existe quatres types de classes internes :
les classes internes non statiques : elles sont membres à part entière de la classe qui les englogent et peuvent
• 
accéder à tous les membres de cette dernière
les classes internes locales : elles sont définies dans un block de code. Elles peuvent être static ou non.
• 
les classes internes anonymes : elles sont définies et instanciées à la volée sans posséder de nom
• 
les classe internes statiques : elles sont membres à part entière de la classe qui les englogent et peuvent accéder
• 
uniquement aux membres statiques de cette dernière
4.8.1. Les classes internes non statiques
Les classes internes non statiques (member inner?classes) sont définies dans une classe dite " principale " (top?level
class) en tant que membre de cette classe. Leur avantage est de pouvoir accéder aux autres membres de la classe
principale même ceux déclarés avec le modificateur private.
Exemple :
public class ClassePrincipale20 {
        private int valeur = 1;
        class ClasseInterne {
                public void afficherValeur() {
                        .println("valeur = "+valeur); 
                }
        }
        public static void main(String[] args) {
                ClassePrincipale20 cp = new ClassePrincipale20();
                ClasseInterne ci = cp. new ClasseInterne();
                ci.afficherValeur();
Développons en Java
56

        }       
}
Resultat :
C:\testinterne>javac
C:\testinterne>java ClassePrincipale20
valeur = 1
Le mot clé this fait toujours référence à l'instance en cours. Ainsi fait référence à la variable var de l'instance
courante. L'utilisation du mot clé this dans une classe interne fait donc référence à l'instance courante de cette classe
interne.
Exemple :
public class ClassePrincipale16 {
        class ClasseInterne {
                int var = 3;
                public void affiche() {
                        .println("var      = "+var);  
                        .println(" = ");     
                }
        }
        ClasseInterne ci = this. new ClasseInterne();
        public static void main(String[] args) {
                ClassePrincipale16 cp = new ClassePrincipale16();
                ClasseInterne ci = cp. new ClasseInterne();             
                ci.affiche();
        }
}
Resultat :
C:\>java ClassePrincipale16
var      = 3
= 3
Une classe interne a accès à tous les membres de sa classe principale. Dans le code, pour pouvoir faire référence à un
membre de la classe principale, il suffit simplement d'utiliser son nom de variable.
Exemple :
public class ClassePrincipale17 {
        int valeur = 5;
        class ClasseInterne {
                int var = 3;
                public void affiche() {
                        .println("var      = "+var);  
                        .println(" = ");     
                        .println("valeur   = "+valeur);       
                }
        }
        ClasseInterne ci = this. new ClasseInterne();
        public static void main(String[] args) {
Développons en Java
57

                ClassePrincipale17 cp = new ClassePrincipale17();
                ClasseInterne ci = cp. new ClasseInterne();     
                ci.affiche();
        }
}
Resultat :
C:\testinterne>java ClassePrincipale17
var      = 3
= 3
valeur   = 5
La situation se complique un peu plus, si la classe principale et la classe interne possède tous les deux un membre de
même nom. Dans ce cas, il faut utiliser la version qualifée du mot clé this pour accéder au membre de la classe
principale. La qualification se fait avec le nom de la classe principale ou plus généralement avec le nom qualifié d'une
des classes englobantes.
Exemple :
public class ClassePrincipale18 {
        int var = 5;
        class ClasseInterne {
                int var = 3;
                public void affiche() {
                        .println("var                          = "+var);      
                        .println("                     = "); 
                        .println("  = "
                          );        
                }
        }
        ClasseInterne ci = this. new ClasseInterne();
        public static void main(String[] args) {
                ClassePrincipale18 cp = new ClassePrincipale18();
                ClasseInterne ci = cp. new ClasseInterne();     
                ci.affiche();
        }
}
Resultat :
C:\>java ClassePrincipale18
var                          = 3
                    = 3
 = 5
Comme une classe interne ne peut être nommée du même nom que l'une de ces classes englobantes, ce nom qualifié est
unique et il ne risque pas d'y avoir de confusion.
Le nom qualifié d'une classe interne est nom_classe_principale.nom_classe_interne. C'est donc le même principe que
celui utilisé pour qualifié une classe contenue dans un package. La notation avec le point est donc légèrement étendue.
L'accès au membre de la classe principale est possible car le compilateur modifie le code de la classe principale et celui
de la classe interne pour fournir à la classe interne une référence sur la classe principale.
Le code de la classe interne est modifié pour :
Développons en Java
58

ajouter une variable privée finale du type de la classe principale nommée this$0
• 
ajouter un paramètre supplémentaire dans le constructeur qui sera la classe principale et qui va initialiser la
• 
variable this$0
utiliser cette variable pour préfixer les attributs de la classe principale utilisés dans la classe interne.
• 
La code de la classe principale est modifié pour :
ajouter une méthode static pour chaque champ de la classe principale qui attend en paramètre un objet de la
• 
classe principale. Cette méthode renvoie simplement la valeur du champ. Le nom de cette méthode est de la
forme access$0
modifier le code d'instanciation de la classe interne pour appeler le constructeur modifié
• 
Dans le byte code généré, une variable privée finale contient une référence vers la classe principale. Cette variable est
nommée this$0. Comme elle est générée par le compilateur, cette variable n'est pas utilisable dans le code source. C'est à
partir de cette référence que le compilateur peut modifier le code pour accéder aux membres de la classe principale.
Pour pouvoir avoir acces aux membres de la classe principale, le compilateur génère dans la classe principale des
accesseurs sur ces membres. Ainsi, dans la classe interne, pour accéder à un membre de la classe principale, le
compilateur appelle un de ces accesseurs en utilisant la référence stockée. Ces méthodes ont un nom de la forme
access$numero_unique et sont bien sûre inutilisables dans le code source puisqu'elles sont générées par le compilateur.
En tant que membre de la classe principale, une classe interne peut être déclarée avec le modificateur private ou
protected.
Une classe peut faire référence dans le code source à son unique instance lors de l'éxécution via le mot clé this. Une
classe interne possède au moins deux références :
l'instance de la classe interne elle même
• 
éventuellement les instances des classes internes dans laquelle la classe interne est imbriquée
• 
l'instance de sa classe principale
• 
Dans la classe interne, il est possible pour accéder à une de ces instances d'utiliser le mot clé this préfixé par le nom de la
classe suivi d'un point :


Le mot this seul désigne toujours l'instance de la classe courante dans son code source, donc this seul dans une classe
interne désigne l'instance de cette classe interne.
Une classe interne non statique doit toujours être instanciée relativement à un objet implicite ou explicite du type de la
classe principale. A la compilation, le compilateur ajoute dans la classe interne une référence vers la classe principale
contenu dans une variable privée nommée this$0. Cette référence est initialisée avec un paramètre fourni au constructeur
de la classe interne. Ce mécanisme permet de lier les deux instances.
La création d'une classe interne nécessite donc obligatoirement une instance de sa classe principale. Si cette instance n'est
pas accessible, il faut en créer une et utiliser une notation particulière de l'opérateur new pour pouvoir instancier la classe
interne. Par défaut, lors de l'instanciation d'une classe interne, si aucune instance de la classe principale n'est utilisée, c'est
l'instance courante qui est utilisée (mot clé this).
Exemple :
public class ClassePrincipale14 {
        class ClasseInterne {
        }
        ClasseInterne ci = this. new ClasseInterne();
}
Pour créer une instance d'une classe interne dans une méthode statique de la classe principale, (la méthode main() par
exemple), il faut obligatoirement instancier un objet de la classe principale avant et utiliser cet objet lors de la création de
l'instance de la classe interne. Pour créer l'instance de la classe interne, il faut alors utiliser une syntaxe particulière de
Développons en Java
59

l'opérateur new.
Exemple :
public class ClassePrincipale15 {
        class ClasseInterne {
        }
        ClasseInterne ci = this. new ClasseInterne();
        static void maMethode() {
                ClassePrincipale15 cp = new ClassePrincipale15();
                ClasseInterne ci = cp. new ClasseInterne();
        }
}
Il est possible d'utiliser une syntaxe condensée pour créer les deux instances en une seul et même ligne de code.
Exemple :
public class ClassePrincipale19 {
        class ClasseInterne {
        }
        static void maMethode() {       
                ClasseInterne ci = new ClassePrincipale19(). new ClasseInterne();
        }
}
Une classe peut hériter d'une classe interne. Dans ce cas, il faut obligatoirement fournir aux contructeurs de la classe une
référence sur la classe principale de la classe mère et appeler explicitement dans le constructeur le constructeur de cette
classe principale avec une notation particulière du mot clé super
Exemple :
public class ClassePrincipale9 {
        public class ClasseInterne {
        }
        class ClasseFille extends ClassePrincipale9.ClasseInterne {
                ClasseFille(ClassePrincipale9 cp) {
                        cp. super();
                }
        }
}
Une classe interne peut être déclarée avec les modificateurs final et abstract. Avec le modificateur final, la classe interne
ne pourra être utilisée comme classe mère. Avec le modificateur abstract, la classe interne devra être étendue pour
pouvoir être instanciée.
4.8.2. Les classes internes locales
Ces classes internes locales (local inner?classes) sont définies à l'intérieure d'une méthode ou d'un bloc de code. Ces
classes ne sont utilisables que dans le bloc de code où elles sont définies. Les classes internes locales ont toujours accès
aux membres de la classe englobante.
Exemple :
Développons en Java
60

public class ClassePrincipale21 {
   int varInstance = 1;
   public static void main(String args[]) {
     ClassePrincipale21 cp = new ClassePrincipale21();
     cp.maMethode();
   }
   public void maMethode() {
     class ClasseInterne {
       public void affiche() {
         .println("varInstance = " + varInstance);
       }
     }
     ClasseInterne ci = new ClasseInterne();
     ci.affiche();
   }
 }
Resultat :
C:\testinterne>javac
C:\testinterne>java ClassePrincipale21
varInstance = 1
Leur particularité, en plus d'avoir un accès aux membres de la classe principale, est d'avoir aussi un accès à certaines
variables locales du bloc ou est définie la classe interne.
Ces variables définies dans la méthode (variables ou paramètres de la méthode) sont celles qui le sont avec le mot clé
final. Ces variables doivent être initialisée avant leur utilisation par la classe interne. Celles ci sont utilisables n'importe
ou dans le code de la classe interne.
Le modificateur final désigne une variable dont la valeur ne peut être changée une fois qu'elle a été initialisée.
Exemple :
public class ClassePrincipale12 {
   public static void main(String args[]) {
     ClassePrincipale12 cp = new ClassePrincipale12();
     cp.maMethode();
   }
   public void maMethode() {
        int varLocale = 3;
     class ClasseInterne {
       public void affiche() {
         .println("varLocale = " + varLocale);
       }
     }
     ClasseInterne ci = new ClasseInterne();
     ci.affiche();
   }
 }
Resultat :
Développons en Java
61

javac
:14: Attempt to use a non?final variable varLocale from a
 different method. From enclosing blocks, only final local variables are availab
le.
         .println("varLocale = " + varLocale);
                                             ^
1 error
Cette restriction est imposée par la gestion du cycle de vie d'une variable locale. Une telle variable n'existe que durant
l'éxécution de cette méthode. Une variable finale est une variable dont la valeur ne peut être modifiée après son
initialisation. Ainsi, il est possible sans risque pour le compilateur d'ajouter un membre dans la classe interne et de copier
le contenu de la variable finale dedans.
Exemple :
public class ClassePrincipale13 {
   public static void main(String args[]) {
     ClassePrincipale13 cp = new ClassePrincipale13();
     cp.maMethode();
   }
   public void maMethode() {
        final int varLocale = 3;
     class ClasseInterne {
       public void affiche(final int varParam) {
         .println("varLocale = " + varLocale);
         .println("varParam  = " + varParam);
       }
     }
     ClasseInterne ci = new ClasseInterne();
     ci.affiche(5);
   }
 }
Resultat :
C:\>javac
C:\>java ClassePrincipale13
varLocale = 3
varParam  = 5
Pour permettre à une classe interne locale d'accéder à une variable locale utilisée dans le bloc de code ou est définie la
classe interne, la variable doit être stockée dans un endroit ou la classe interne pourra y accéder. Pour que cela
fonctionne, le compilateur ajoute les variables nécessaires dans le constructeur de la classe interne.
Les variables accédées sont dupliquées dans la classe interne par le compilateur. Il ajoute pour chaque variable un
membre privé dans la classe interne dont le nom est de la forme val$nom_variable. Comme la variable accédée est
déclarée finale, cette copie peut être faite sans risque. La valeur de chacune de ces variables est fournie en paramètre du
constructeur qui a été modifié par le compilateur.
Une classe qui est définie dans un bloc de code n'est pas un membre de la classe englobante : elle n'est donc pas
accessible en dehors du bloc de code ou elle est définie. Ces restrictions sont équivalentes à la déclaration d'une variable
dans un bloc de code.
Les variables ajoutées par le compilateur sont préfixées par this$ et val$. Ces variables et le constructeur modifié par le
compilateur ne sont pas utilisables dans le code source.
Etant visible uniquement dans le bloc de code qui la définie, une classe interne locale ne peut pas utiliser les
Développons en Java
62

modificateurs public, private, protected et static dans sa définition. Leur utilisation provoque une erreur à la compilation.
Exemple :
public class ClassePrincipale11 {
        public void maMethode() {
                public class ClasseInterne {
                }
        }
}
Resultat :
javac
:2: '}' expected.
        public void maMethode() {
                                 ^
:3: Statement expected.
                public class ClasseInterne {
                ^
:7: Class or interface declaration expected.
}
^
3 errors
4.8.3. Les classes internes anonymes
Les classes internes anonymes (anonymous inner?classes) sont des classes internes qui ne possèdent pas de nom. Elles
ne peuvent donc être instanciées qu'à l'endroit ou elles sont définies.
Ce type de classe est très pratique lorsqu'une classe doit être utilisée une seule fois : c'est par exemple le cas d'une classe
qui doit être utilisée comme un callback.
Une syntaxe particulière de l'opérateur new permet de déclarer et instancier une classe interne :
new classe_ou_interface () {
// définition des attributs et des méthodes de la classe interne
}
Cette syntaxe particulière utilise le mot clé new suivi d'un nom de classe ou interface que la classe interne va
respectivement étendre ou implémenter. La définition de la classe suit entre deux accolades. Une classe interne anonyme
peut soit hériter d'une classe soit implémenter une interface mais elle ne peut pas explicitement faire les deux.
Si la classe interne étend une classe, il est possible de fournir des paramètres entre les parenthèses qui suivent le nom de
la classe. Ces arguments éventuels fournis au moment de l'utilisation de l'opérateur new sont passés au constructeur de la
super classe. En effet, comme la classe ne possède pas de nom, elle ne possède pas non plus de constructeur.
Les classes internes anonymes qui implémentent une interface héritent obligatoirement de classe Object. Comme cette
classe ne possèdent qu'un constructeur sans paramètre, il n'est pas possible lors de l'instanciation de la classe interne de
lui fournir des paramètres.
Une classe interne anonyme ne peut pas avoir de constructeur puisqu'elle ne possède pas de nom mais elle peut avoir des
initialisateurs.
Exemple :
public void init() {
   boutonQuitter.addActionListener(
     new ActionListener() {
       public void actionPerformed(ActionEvent e) {
         (0);
Développons en Java
63

       }
     }
   );
 }
Les classes anonymes sont un moyen pratique de déclarer un objet sans avoir a lui trouver un nom. La contre partie est
que cette classe ne pourra être instanciée dans le code qu'à l'endroit ou elle est définie : elle est déclarée et instanciée en
un seul et unique endroit.
Le compilateur génère un fichier ayant pour nom la forme suivante : nom_classe_principale$numéro_unique. En fait, le
compilateur attribut un numéro unique à chaque classe interne anonyme et c'est ce numéro qui est donné au nom du
fichier préfixé par le nom de la classe englobante et d'un signe '$'.
4.8.4. Les classes internes statiques
Les classes internes statiques (static member inner?classes) sont des classes internes qui ne possèdent pas de référence
vers leur classe principale. Elles ne peuvent donc pas accéder aux membres d'instance de leur classe englobante. Elles
peuvent toutefois avoir accès aux variables statiques de la classe englobante.
Pour les déclarer, il suffit d'utiliser en plus le modificateur static dans la déclaration de la classe interne.
Leur utilisation est obligatoire si la classe est utilisée dans une méthode statique qui par définition peut être appelée dans
avoir d'instance de la classe et que l'on ne peut pas avoir une instance de la classe englobante. Dans le cas contraire, le
compilateur indiquera une erreur :
Exemple :
public class ClassePrincipale4 {
        class ClasseInterne {
                public void afficher() {
                        .println("bonjour");  
                }
        }
        public static void main(String[] args) {        
                new ClasseInterne().afficher();
        }
}
Resultat :
javac
:10: No enclosing instance of class ClassePrincipale4 is i
n scope; an explicit one must be provided when creating inner class ClassePrinci
pale4. ClasseInterne, as in "outer. new Inner()" or "outer. super()".
                new ClasseInterne().afficher();
                ^
1 error
En déclarant la classe interne static, le code se compile et peut être exécuté
Exemple :
public class ClassePrincipale4 {
        static class ClasseInterne {
                public void afficher() {
Développons en Java
64

                        .println("bonjour");  
                }
        }
        public static void main(String[] args) {        
                new ClasseInterne().afficher();
        }
}
Resultat :
javac
java ClassePrincipale4
bonjour
Comme elle ne possède pas de référence sur sa classe englobante, une classe interne statique est en fait traduite par le
compilateur comme une classe principale. En fait, il est difficile de les mettre dans une catégorie (classe principale ou
classe interne) car dans le code source c'est une classe interne (classe définie dans une autre) et dans le byte code généré
c'est une classe principale.
Ce type de classe n'est pas très employée.
4.9. La gestion dynamique des objets
Tout objet appartient à une classe et Java sait la reconnaitre dynamiquement.
Java fournit dans son API un ensemble de classes qui permettent d'agir dynamiquement sur des classes. Cette technique
est appellée introspection et permet :
de décrire une classe ou une interface : obtenir son nom, sa classe mère, la liste de ces méthodes, de ses
• 
variables de classe, de ses constructeurs et de ses variables d'instances
d'agir sur une classe en envoyant, à un objet Class des message comme à tout autre objet. Par exemple, créer
• 
dynamiquement à partir d'un objet Class une nouvelle instance de la classe représentée
Voir le chapitre sur l'introspection.
Développons en Java
65

5. La bibliothèque de classes java
Dans la version 1.0, le JDK contient 8 packages chacun étant constitués par un ensemble de classes qui couvrent un
même domaine et apportent de nombreuses fonctionnalités. Les différentes versions du JDK sont constamment enrichis
de packetages :
JDK
JDK
JDK
JDK
JDK
Packages
Role
1.0
1.1
1.2
1.3
1.4
développement des
java.applet
X
X
X
X
X
applets
ttoolkit pour

X
X
X
X
X
interfaces
graphiques
gérer et utiliser les
.color
X
X
X
couleurs
échanger des
.datatransfer
X
X
X
X
données via le
presse?papier
gérer le

X
X
X
cliquer/glisser
gérer les
.event
X
X
X
X
évenements
utilisateurs

X
X
X
utiliser les fontes
dessiner des formes

X
X
X
géométiques

X
X

X
X
.image
X
X
X
X
afficher des images
modifier le rendu
.image.renderable 
X
X
X
des images
réaliser des
.print
X
X
X
impressions
développer des
java.beans
X
X
X
X
composants
réutilisables
java.beans.beancontext
X
X
X

X
X
X
X
X
gérer les flux

X
X
X
X
X
Développons en Java
66

classes de base du
langage

X
X
X
utiliser la réflexion
.reflect
X
X
X
X
(introspection)
utiliser des

X
X
X
X
opérations
mathématiques
utiliser les

X
X
X
X
X
fonctionnalités
réseaux

X
.channels
X

X
.charset
X

X
développement

X
X
X
X
d'objets distribués
.activation 
X
X
X

X
X
X
X
.registry
X
X
X
X
gérer les objets
.server
X
X
X
X
serveurs de RMI
gérer la signature et
java.security
X
X
X
X
la certification

X
X
X
X

X
X
X
X
java.security.interfaces
X
X
X
X

X
X
X
JDBC pour l'accès

X
X
X
X
aux bases de
données
formatter des objets

X
X
X
X
en texte

X
X
X
X
X
utilitaires divers

X
X
X
gérer les fichiers jar
.logging
X
utiliser des logs
gerer des
.prefs
X
préférences
utiliser les
.regex
X
expressions
régulières

X
X
X
X
gérer les fichiers zip
javax.accessibility
X
X
X
Développons en Java
67

utiliser le cryptage
javax.crypto
X
des données
javax.crypto.interfaces
X

X
javax.imageio
X
javax.imageio.event
X
javax.imageio.metadata
X

X

X
javax.imageio.stream
X
javax.naming
X
X
javax.naming.directory
X
X
javax.naming.event
X
X

X
X

X
X

X
utiliser une

X
connexion reseau
securisé avec SSL
javax.print
X
javax.print.attribute
X
javax.print.attribute.standard
X
javax.print.event
X

X
X
.CORBA
X
X
API JAAS pour

X
l'authentification et
l'autorisation
.callback
X
.kerberos
X
.login
X

X
.x500
X

X

X
X

X
X
javax.sound.sampled
X
X

X
X

X
javax.swing
X
X
X
Swing pour
développer des
Développons en Java
68

interfaces
graphiques
gérer les bordures
javax.swing.border
X
X
X
des composants
Swing
composant pour
javax.swing.colorchooser
X
X
X
sélectionner une
couleur
gérer des
évenements
javax.swing.event 
X
X
X
utilisateur des
composants Swing
composant pour
javax.swing.filechooser 
X
X
X
sélectionner un
fichier
gérer l'aspect des

X
X
X
composants Swing
.basic
X
X
X
gérer l'aspect metal
.metal
X
X
X
des composants
Swing
.multi
X
X
X
javax.swing.table 
X
X
X

X
X
X

X
X
X
.parser
X
X
X

X
X
X
gérer un composant

X
X
X
JTree
gérer les
annulations

X
X
X
d'opérations
d'édition
javax.transaction
X
X

X
API JAXP pout
.parsers
X
utiliser XML
transformer un
.transform
X
document XML
avec XSLT

X

X
.transform.stream
X

X
.CORBA
X
X
X
.CORBA_2_3
X
X
Développons en Java
69

.CORBA_2_3.portable
X
X
.CORBA.DynAnyPackage
X
X
X
.CORBA.ORBPackage
X
X
X
.CORBA.portable
X
X
X
.CORBA.TypeCodePackage
X
X
X
.CosNaming
X
X
X
.CosNaming.NamingContextExtPackage
X
X
X
.CosNaming.NamingContextPackage
X
.Dynamic
X
.DynamicAny
X
.DynamicAny.DynAnyFactoryPackage
X
.DynamicAny.DynAnyPackage
X

X
.CodecFactoryPackage
X
.CodecPackage
X
.Messaging
X
.PortableInterceptor
X
.PortableInterceptor.ORBInitInfoPackage
X
.PortableServer
X
.PortableServer.CurrentPackage
X
.PortableServer.POAPackage
X
.PortableServer.ServantLocatorPackage
X
.PortableServer.portable
X
.SendingContext
X
X

X
X
utiliser DOM pour

X
un document XML
utiliser SAX pour

X
un document XML

X
.helpers
X
Ce chapitre contient les sections suivantes :
Présentation du package
• 
La classe Object

Présentation de la classe Object qui est la classe mère de toutes les classes en java.
La classe String

Présentation de la classe String qui représente les chaines de caractères non modifiables
La classe StringBuffer

Présentation de la classe StringBuffer qui représente les chaines de caractères modifiables
Les wrappers

Présentation des wrappers qui sont des classes qui encapsulent des types primitifs et permettent de faire
Développons en Java
70

des conversions.
Présentation rapide du package awt
• 
Présentation rapide du package
• 
Le package
• 
La classe StringTokenizer

Présentation de la classe StringTokenizer qui permet de découper une chaine selon des séparateurs.
La classe Random

Présentation de la classe Random qui permet de générer des nombres aléatoires.
Les classes Date et Calendar

Présentation des classes qui permettent selon de la version du JDK de gerer les dates.
La classe Vector

Présentation de la classe Vector qui définit une sorte de tableau dynamique.
La classe Hashtable

Présentation de la classe Hastable qui définit une sorte de dictionnaire.
L'interface Enumeration

Présentation de cette interface qui définit des méthodes pour le parcours séquentiel de collections.
Les expressions régulières

Le JDK 1.4 propose une api pour l'utilisation des expressions régulières avec java.
Présentation rapide du package
• 
Présentation rapide du package java.applet
• 
5.1. Présentation du package
Ce package de base contient les classes fondamentales tel que Object, Class, Math, System, String, StringBuffer, Thread,
les wrapper etc ...
La classe Math est détaillée dans le chapitre "les fonctions mathématiques".
La classe Class est détaillée dans le chapitre "la gestion dynamique des objets et l'introspection".
La classe Thread est détaillée dans le chapitre "le multitache".
Il contient également plusieurs classes qui permettent de demander des actions au système d'exploitation sur laquelle la
machine virtuelle tourne, par exemple ClassLoader, Runtime, SecurityManager.
Ce package est implicitement importé dans tous les fichiers sources par le compilateur.
5.1.1. La classe Object
C'est la super classe de toutes les classes Java : toutes ces méthodes sont donc héritées par toutes les classes.
5.1.1.1. La méthode getClass()
La méthode getClass() renvoie un objet de la classe Class qui représente la classe de l'objet.
Le code suivant permet de connaitre le nom de la classe de l'objet
Exemple :
String nomClasse = monObject.getClass().getName();
Développons en Java
71

5.1.1.2. La méthode toString()
La méthode toString() de la classe Object renvoie le nom de la classe , suivi du séparateur @, lui même suivi par la
valeur de hachage de l'objet.
5.1.1.3. La méthode equals()
La méthode equals() implémente une comparaison par défaut. Sa définition dans Object compare les références : donc
obj1.equals(obj2) ne renverra true que si obj1 et obj2 désignent le même objet. Dans une sous classe de Object, pour
laquelle on a besoin de pouvoir dire que deux objets distincts peuvent être égaux, il faut redéfinir la méthode equals
héritée de Object.
5.1.1.4. La méthode finalize()
A l'inverse de nombreux langage orienté objet tel que le C++ ou Delphi, le programmeur Java n'a pas à se préoccuper de
la destruction des objets qu'il instancie. Ceux?ci sont détruits et leur emplacement mémoire est récupéré par le ramasse
miette de la machine virtuelle dès qu'il n'y a plus de référence sur l'objet.
La machine virtuelle garantit que toutes les ressources Java sont correctement libérées mais, quand un objet encapsule
une ressource indépendante de Java (comme un fichier par exemple), il peut être préférable de s'assurer que la ressource
sera libérée quand l'objet sera détruit. Pour cela, la classe Object définit la méthode protected finalize, qui est appelée
quand le ramasse miettes doit récupérer l'emplacement de l'objet ou quand la machine virtuelle termine son exécution
Exemple :
import .*;
public class AccesFichier {
   private FileWriter fichier;
   public AccesFichier(String s) {
      try {
      fichier = new FileWriter(s);
      }
      catch (IOException e) {
         .println("Impossible d'ouvrir le fichier
5.1.1.5. La méthode clone()
Si x désigne un objet obj1, l'exécution de x.clone() renvoie un second objet obj2, qui est une copie de obj1 : si obj1 est
ensuite modifié, obj2 n'est pas affecté par ce changement.
Par défaut, la méthode clone(), héritée de Object fait une copie variable par variable : elle offre donc un comportement
acceptable pour de très nombreuses sous classe de Object. Cependant comme le processus de duplication peut être délicat
à gérer pour certaines classes (par exemple des objets de la classe Container), l'héritage de clone ne suffit pas pour qu'une
classe supporte le clonage.
Pour permettre le clonage d'une classe, il faut implémenter dans la classe l'interface Cloneable.
La première chose que fait la méthode clone() de la classe Object, quand elle est appelée, est de tester si la classe
implémente Cloneable. Si ce n'est pas le cas, elle lève l'exception CloneNotSupportedException.
Développons en Java
72

5.1.2. La classe String
Une chaine de caractères est contenue dans un objet de la classe String
On peut initialiser une variable String sans appeler explicitement un contructeur : le compilateur se charge de créer un
objet.
Exemple : deux déclarations de chaines identiques.
String uneChaine = «bonjour»;
String uneChaine = new String(«bonjour»);
Les objets de cette classe ont la particularité d'être constants. Chaque traitement qui vise à transformer un objet de la
classe est implémenté par une méthode qui laisse l'objet d'origine inchangé et renvoie un nouvel objet String contenant
les modifications.
Exemple :
private String uneChaine;
void miseEnMajuscule(String chaine) {
    uneChaine = chaine.toUpperCase()
}
Il est ainsi possible d'enchainer plusieurs méthodes :
Exemple :
uneChaine = chaine.toUpperCase().trim();
L'opérateur + permet la concatenation de chaines de caractères.
La comparaison de deux chaine doit se faire via la méthode equals() qui compare les objets eux même et non l'opérateur
== qui compare les réferences de ces objets :
Exemple :
String nom1 = new String("Bonjour");
String nom2 = new String("Bonjour");
.println(nom1 == nom2); // affiche false
.println( nom1.equals(nom2)); // affiche true
Cependant dans un soucis d'efficacité, le compilateur ne duplique pas 2 constantes chaines de caractères : il optimise
l'espace mémoire utilisé en utilisant le même objet. Cependant, l'appel explicite du constructeur ordonne au compilateur
de créer un nouvel objet.
Exemple :
String nom1 = «Bonjour»;
String nom2 = «Bonjour»;
String nom3 = new String(«Bonjour»);
.println(nom1 == nom2); // affiche true
.println(nom1 == nom3); // affiche false
Développons en Java
73

La classe String possède de nombreuses méthodes dont voici les principales :
Méthodes la classe String
Role
charAt(int)
renvoie le nieme caractère de la chaine
compareTo(String)
compare la chaine avec l'argument
concat(String)
ajoute l'argument à la chaine et renvoie la nouvelle chaine
endsWith(String)
vérifie si la chaine se termine par l'argument
equalsIgnoreCase(String)
compare la chaine sans tenir compte de la casse
indexOf(String)
renvoie la position de début à laquelle l'argument est contenu dans la chaine
lastIndexOf(String)
renvoie la dernière position à laquelle l'argument est contenu dans la chaine
lenght()
renvoie la longueur de la chaine
replace(char,char)
renvoie la chaine dont les occurences d'un caractère ont remplacées
startsWidt(String int)
Vérifie si la chaine commence par la sous chaine
substring(int,int)
renvoie une partie de la chaine
toLowCase()
renvoie la chaine en minuscule
toUpperCase()
renvoie la chaine en majuscule
trim()
enlève les caractères non significatifs de la chaine
5.1.3. La classe StringBuffer
Les objets de cette classe contiennent des chaines de caractères variables, ce qui permet de les agrandir ou de les réduire.
Cette objet peut être utilisé pour construire ou modifier une chaine de caractères chaque fois que l'utilisation de la classe
String nécessiterait de nombreuses instanciations d'objets temporaires.
Par exemple, si str est un objet de type String, le compilateur utilisera la classe StringBuffer pour traiter la concaténation
de « abcde »+str+« z » en générant le code suivant : new StringBuffer().append(« abcde ».append(str).append(« z
»).toString();
Ce traitement aurait pu être réalisé avec trois appels à la méthode concat() de la classe String mais chacun des appels
aurait instancié un objet StringBuffer pour réaliser la concaténation, ce qui est couteux en temps exécution
La classe StringBuffer dispose de nombreuses méthodes qui permettent de modifier le contenu de la chaine de caractère
Exemple ( code java 1.1 ) : une méthode uniquement pédagogique
public class MettreMaj {
   static final String lMaj = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   static final String lMin = "abcdefghijklmnopqrstuvwxyz";
   public static void main(.String[] args) {
      .println(MetMaj("chaine avec MAJ et des min"));
   }
   public static String MetMaj(String s) {
      StringBuffer sb = new StringBuffer(s);
      for ( int i = 0; i <sb.length(); i++) {
          int index = lMin.indexOf(sb.charAt(i));
          if (index >=0 ) sb.setCharAt(i,lMaj.charAt(index));
      }
      return sb.toString();
   }
}
Développons en Java
74

Résultat :
CHAINE AVEC MAJ ET DES MIN
5.1.4. Les wrappers
Les objet de type wrappers (enveloppeurs) représentent des objets qui encapsulent une données de type primitif et qui
fournissent un ensemble de méthodes qui permettent notamment de faire de conversions.
Ces classes offrent toutes les services suivants :
un constructeur qui permet une instanciation à partir du type primitif et un constructeur qui permet une
• 
instanciation à partir d'un objet String
une méthode pour fournir la valeur primitive représentée par l'objet
• 
une méthode equals() pour la comparaison.
• 
Les méthodes de conversion opèrent sur des instances, mais il est possible d'utiliser des méthodes statiques.
Exemple :
int valeur =
Integer.valueOf("999").intValue();
Ces classes ne sont pas interchangeable avec les types primitif d'origine car il s'agit d'objet.
Exemple :
Float objetpi = new Float(«3.1415»);
.println(5*objetpi); // erreur à la compil
Pour obtenir la valeur contenue dans l'objet, il faut utiliser la méthode typeValue() ou type est le nom du type standard
Exemple :
Integer Entier = new Integer(«10»);
int entier = Entier.intValue();
Les classes Integer, Long, Float et Double définissent toutes les constantes MAX_VALUE et MIN_VALUE qui
représentent leurs valeurs minimales et maximales.
Lorsque l'on effectue certaines opérations mathématiques sur des nombres à virgules flottantes (float ou double), le
résultat peut prendre l'une des valeurs suivantes :
NEGATIVE_INFINITY : infini négatif causé par la division d'un nombre négatif par 0.0
• 
POSITIVE_INFINITY : infini positif causé par la division d'un nombre positif par 0.0
• 
NaN: n'est pas un nombre (Not a Number) causé par la division de 0.0 par 0.0
• 
Il existe des méthodes pour tester le résultat :
Float.isNaN(float); //idem avec double
Développons en Java
75

Double.isInfinite(double); // idem avec float
Exemple :
float res = 5.0f / 0.0f;
if (Float.isInfinite(res)) { ... };
La constante n'est ni égale à un nombre dont la valeur est NaN ni à elle même. ==
retourne False
Lors de la division par zéro d'un nombre entier, une exception est levée.
Exemple :
.println(10/0);
Exception in thread "main" .ArithmeticException: / by zero
at (:6)
5.1.5. La classe System
Cette classe possède de nombreuses fonctionnalités pour utiliser des services du système d'exploitation.
5.1.5.1. L'utilisation des flux d'entrée/sortie standard
La classe System défini trois variables statiques qui permettent d'utiliser les flux d'entrée/sortie standards du système
d'exploitation.
Variable
Type
Rôle
in
PrintStream
Entrée standard du système. Par défaut, c'est le clavier.
out
InputStream
Sortie standard du système. Par défaut, c'est le moniteur.
err
PrintStream
Sortie standard des erreurs du système. Par défaut, c'est le moniteur.
Exemple :
.println("bonjour");
La classe système possède trois méthodes qui permettent de rediriger ces flux.
5.1.5.2. Les variables d'environnement et les propriétés du système
JDK 1.0 propose la méthode statique getEnv() qui renvoie la valeur de la propriété système dont le nom est fourni en
paramètre.
Depuis le JDK 1.1, cette méthode est deprecated car elle n'est pas multi?système. Elle est remplacée par un autre
mécanisme qui n'interroge pas directement le système mais qui recherche les valeurs dans un ensemble de propriétés. Cet
ensemble est consituté de propriétés standard fournies par l'environnement java et par des propriétés ajoutés par
Développons en Java
76

l'utilisateur.
Voici une liste non exhaustive des propriétés fournies par l'environnement java :
Nom de la propriété
Rôle
java.version
Version du JRE
java.vendor
Auteur du JRE

URL de l'auteur

Répertoire d'installation de java
.version
Version de l'implémentation la JVM
.vendor
Auteur de l'implémentation de la JVM

Nom de l'implémentation de la JVM
java.specification.version
Version des spécifications de la JVM
java.specification.vendor
Auteur des spécifications de la JVM

Nom des spécifications de la JVM

Chemin du ou des répertoires d'extension

Nom du système d'exploitation

Architecture du système d'exploitation
os.version
Version du système d'exploitation
file.separator
Séparateur de fichiers (exemple : "/" sous Unix, "\" sous Windows)
path.separator
Séparateur de chemin (exemple : ":" sous Unix, ";" sous Windows)
line.separator
Séparateur de ligne

Nom du user courant

Répertoire d'accueil du user courant

Répertoire courant au moment de l'initialisation de la propriété
Pour définir ces propres propriétés, il faut utiliser l'option ?D de l'interpreteur java en utilisant la ligne de commande.
La méthode statique getProperty() permet d'obtenir la valeur de la propriété dont le nom est fourni en paramètre. Une
version surchargée de cette méthode permet de préciser un second paramètre qui contiendra la valeur par défaut, si la
propriété n'est pas définie.
Exemple :
public class TestProperty {
  public static void main(String[] args) {
    .println("java.version                  ="+System.getProperty("java.version"));
    .println("java.vendor                   ="+System.getProperty("java.vendor"));
    .println("               ="+System.getProperty(""));
    .println("                     ="+System.getProperty(""));
    .println(".specification.version ="
      +System.getProperty(".specification.version"));
    .println(".specification.vendor  ="
      +System.getProperty(".specification.vendor"));
    .println("    ="
      +System.getProperty(""));
    .println(".version               ="+System.getProperty(".version"));
    .println(".vendor                ="+System.getProperty(".vendor"));
    .println("                  ="+System.getProperty(""));
Développons en Java
77

    .println("java.specification.version    ="
      +System.getProperty("java.specification.version"));
    .println("java.specification.vendor     ="
      +System.getProperty("java.specification.vendor"));
    .println("       ="
      +System.getProperty(""));
    .println("java.class.version            ="
      +System.getProperty("java.class.version"));
    .println("               ="
      +System.getProperty(""));
    .println("                 ="+System.getProperty(""));
    .println("                       ="+System.getProperty(""));
    .println("                       ="+System.getProperty(""));
    .println("os.version                    ="+System.getProperty("os.version"));
    .println("file.separator                ="+System.getProperty("file.separator"));
    .println("path.separator                ="+System.getProperty("path.separator"));
    .println("line.separator                ="+System.getProperty("line.separator"));
    .println("                     ="+System.getProperty(""));
    .println("                     ="+System.getProperty(""));
    .println("                      ="+System.getProperty(""));
  }
}
Par défaut, l'accès aux propriétés système est restreint par le SecurityManager pour les applets.
5.1.6. La classe Runtime
La classe Runtime permet d'intéragir avec le système dans lequel l'application s'éxécute : obtenir des informations sur le
système, arrêt de la machine virtuelle, éxecution d'un programme externe
Cette classe ne peut pas être instanciée mais il est possible d'obtenir une instance en appelant la méthode statique
getRuntime().
La méthode exec() permet d'éxécuter des commandes du système d'exploitation ou s'éxécute la JVM. Elle lance la
commande de manière asynchrone et renvoie un objet de type Process pour obtenir des informations sur le processus
lancé.
L'inconvénient d'utiliser cette méthode est que la commande executée est dépendante du système d'exploitation.
La suite de cette section sera développée dans une version future de ce document
5.2. Présentation rapide du package awt java
AWT est une collection de classes pour la réalisation d'applications graphique ou GUI (Graphic User Interface)
Les composants qui sont utilisés par les classes définies dans ce package sont des composants dit "lourds" : ils dépendent
entièrement du système d'explotation. D'ailleurs leur nombre est limité car ils sont communs à plusieurs systèmes
d'exploitation pour assurer la portabilité. Cependant, la représentation d'une interface graphique avec awt sur plusieurs
systèmes peut ne pas être identique.
La chapitre "Création d'interface graphique avec AWT" détaille l'utilisation de ce package,
Développons en Java
78

5.2.1. Le package java.image
Ce package permet la gestion des images
5.2.2. Le package
Ce package contient des classes qui réalise l'interface avec le système d'exploitation.
5.3. Présentation rapide du package
Ce package définit un ensemble de classes pour la gestion des flux d'entrées?sorties
Le chapitre les flux détaille l'utilisation de ce package
5.4. Le package
Ce package contient un ensemble de classes utilitaires : la gestion des dates (Date et Calendar), la génération de nombres
aléatoires (Random), la gestion des collections ordonnées ou non tel que la tablea de hachage (HashTable), le vecteur
(Vector), la pile (Stack) ..., la gestion des propriétés (Properties), des classes dédiées à l'internationalisation
(ResourceBundle, PropertyResourceBundle, ListResourceBundle) etc ...
Certaines de ces classes sont présentées plus en détail dans les sections suivantes.
5.4.1. La classe StringTokenizer
Cette classe permet de découper une chaine de caractères (objet de type String) en fonction de séparateurs. Le
constructeur de la classe accepte 2 paramètres : la chaine à décomposer et une chaine contenant les séparateurs
Exemple ( code java 1.1 ) :
import .*;
class test9 {
   public static void main(String args[]) {
      StringTokenizer st = new StringTokenizer("chaine1,chaine2,chaine3,chaine4",",");
      while (st.hasMoreTokens()) {
         .println((st.nextToken()).toString());
      }
   }
}
C:\java>java test9
chaine1
chaine2
chaine3
chaine4
La méthode hasMoreTokens() fournit un contrôle d'itération sur la collection en renvoyant un booleen indiquant si il
reste encore des éléments.
La méthode getNextTokens() renvoie le prochain élément sous la forme d'un objet String
Développons en Java
79

5.4.2. La classe Random
La classe Random permet de générer des nombres pseudo?aléatoires. Après l'appel au constructeur, il suffit d'appeler la
méthode correspondant au type désiré : nextInt(), nextLong(), nextFloat() ou nextDouble()
Méthodes
valeur de retour
nextInt
entre Integer.MIN_VALUE et Interger.MAX_VALUE
nextLong
entre long.MIN_VALUE et long.MAX_VALUE
nextFloat ou nextDouble
entre 0.0 et 1.0
Exemple ( code java 1.1 ) :
import .*;
class test9 {
   public static void main (String args[]) {
      Random r = new Random();
      int a = r.nextInt() %10; //entier entre ?9 et 9
      .println("a = "+a);
   }
}
5.4.3. Les classes Date et Calendar
En java 1.0, la classe Date permet de manipuler les dates.
Exemple ( code java 1.0 ) :
import .*;
...
    Date maintenant = new Date();
    if (maintenant.getDay() == 1)
       .println(" lundi ");
Le constructeur d'un objet Date l'initialise avec la date et l'heure courante du système.
Exemple ( code java 1.0 ) : recherche et affichage de l'heure
import .*;
import .*;
public class TestHeure {
   public static void main(.String[] args) {
      Date date = new Date();
      .println(DateFormat.getTimeInstance().format(date));
   }
}
Résultat :
22:05:21
Développons en Java
80

La méthode getTime() permet de calculer le nombre de millisecondes écoulées entre la date qui est encapsulée dans
l'objet qui reçoit le message getTime et le premier janvier 1970 à minuit GMT.
En java 1.1, de nombreuses méthodes et constructeurs de la classe Date sont deprecated, notamment celles
qui permettent de manipuler les éléments qui composent la date et leur formattage : il faut utiliser la classe
Calendar.
Exemple ( code java 1.1 ) :
import .*;
public class TestCalendar {
   public static void main(.String[] args) {
      Calendar c = Calendar.getInstance();
      if (c.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY)
          .println(" nous sommes lundi ");
      if (c.get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY)
          .println(" nous sommes mardi ");
      if (c.get(Calendar.DAY_OF_WEEK) == Calendar.WEDNESDAY)
          .println(" nous sommes mercredi ");
      if (c.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY)
          .println(" nous sommes jeudi ");
      if (c.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY)
          .println(" nous sommes vendrei ");
      if (c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY)
          .println(" nous sommes samedi ");
      if (c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
          .println(" nous sommes dimanche ");
   }
}
Résultat :
nous sommes lundi 
5.4.4. La classe Vector
Un objet de la classe Vector peut être considéré comme une tableau évolué qui peut contenir un nombre indéterminé
d'objets.
Les méthodes principales sont les suivantes :
Méthode
Rôle
void addElement(Object)
ajouter un objet dans le vecteur
boolean contains(Object)
retourne true si l'objet est dans le vecteur
Object elementAt(int)
retourne l'objet à l'index indiqué
Enumeration elements()
retourne une enumeration contenant tous les éléments du vecteur
retourne le premier élément du vecteur (celui dont l'index est égal à
Object firstElement()
zéro)
int indexOf(Object)
renvoie le rang de l'élément ou ?1
void insertElementAt(Object, int)
insérer un objet à l'index indiqué
Développons en Java
81

boolean isEmpty()
retourne un booléen si le vecteur est vide
Objet lastElement()
retourne le dernier élément du vecteur
void removeAllElements()
vider le vecteur
void removeElement(Object)
supprime l'objet du vecteur
void removeElementAt(int)
supprime l'objet à l'index indiqué
void setElementAt(object, int)
remplacer l'élément à l'index par l'objet
int size()
nombre d'objet du vecteur
On peut stocker des objets de classes différentes dans un vecteur mais les éléments stockés doivent obligatoirement être
des objets (pour le type primitif il faut utiliser les wrappers tel que Integer ou Float mais pas int ou float).
Exemple ( code java 1.1 ) :
Vector v = new Vector();
v.addElement(new Integer(10));
v.addElement(new Float(3.1416));
v.insertElementAt("chaine ",1);
.println(" le vecteur contient "()+ " elements ");
String retrouve = (String) v.elementAt(1);
.println(" le 1er element = "+retrouve);
C:\$user\java>java test9
le vecteur contient 3 elements
le 1er element = chaine
Exemple ( code java 1.1 ) : le parcours d'un vecteur
  Vector v = new Vector();
   ... 
   for (int i = 0; i < v.size() ; i ++) {
      .println(v.elementAt(i));
   }
Pour un parcours en utilisant l'interface Enumeration, voir le chapitre correspondant.
5.4.5. La classe Hashtable
Les informations d'une Hastable sont stockées sous la forme clé ? données. Cet objet peut être considéré comme un
dictionnaire.
Exemple ( code java 1.1 ) :
Hashtable dico = new Hashtable();
(«livre1», « titre du livre 1 »);
(«livre2», «titre du livre 2 »);
Il est possible d'utiliser n'importe quel objet comme clé et comme donnée
Exemple ( code java 1.1 ) :
Développons en Java
82

(«jour», new Date());
(new Integer(1),«premier»);
(new Integer(2),«deuxième»);
Pour lire dans la table, on utilise get(object) en donnant la clé en paramètre.
Exemple ( code java 1.1 ) :
.println(« nous sommes le » («jour»));
La méthode remove(Object) permet de supprimer une entrée du dictionnaire correspondant à la clé passée en paramètre.
La méthode size() permet de connaitre le nombre d'association du dictionnaire.
5.4.6. L'interface Enumeration
L'interface Enumeration est utilisée pour permettre le parcours séquentiel de collections.
Enumeration est une interface qui définit 2 méthodes :
Méthodes
Rôle
boolean hasMoreElements()
retourne true si l'énumeration contient encore un ou plusieurs elements
retourne l'objet suivant de l'énumération
Object nextElement()
Elle leve une Exception NoSuchElementException si la fin de la
collection est atteinte.
Exemple ( code java 1.1 ) : contenu d'un vecteur et liste des clés d'une Hastable
import .*;
class test9 {
   public static void main (String args[]) {
      Hashtable h = new Hashtable();
      Vector v = new Vector();
      v.add("chaine 1");
      v.add("chaine 2");
      v.add("chaine 3");
      h.put("jour", new Date());
      h.put(new Integer(1),"premier");
      h.put(new Integer(2),"deuxième");
      .println("Contenu du vector");
      for (Enumeration e = v.elements() ; e.hasMoreElements() ; ) {
         .println(e.nextElement());
      }
      .println("\nContenu de la hashtable");
      for (Enumeration e = h.keys() ; e.hasMoreElements() ; ) {
         .println(e.nextElement());
      }
Développons en Java
83

   }
}
C:\$user\java>java test9
Contenu du vector
chaine 1
chaine 2
chaine 3
Contenu de la hashtable
jour
2
1
5.4.7. Les expressions régulières
Le JDK 1.4 propose une api en standard pour utiliser les expressions régulières. Les expressions régulières permettent de
comparer une chaine de caractères àun motif pour vérifier qu'il y a concordance.
La package .regexp contient deux classes et une exception pour gérer les expressions régulières :
Classe
Rôle
Matcher
comparer une chaine de caractère avec un motif
Pattern
encapsule une version compilée d'un motif
PatternSyntaxException
exception levée lorsque le motif contient une erreur de syntaxe
5.4.7.1. Les motifs
Les expressions régulières utilisent un motif. Ce motif est une chaine de caractères qui contient des caractères et des
métacaractères. Les métacaractères ont une signification particulière et sont interprétés.
Il est possible de déspécialiser un métacaractère (lui enlever sa signification particulière à en le faisant précédé d'un
caractère backslash. Ainsi pour utiliser le caractère backslash, il faut le doubler.
Les métacaractères reconnus par l'api sont :
métacaractères
rôle
()
[]
définir un ensemble de caractères
{}
définir une répétition du motif précédent
\
déspécalisation du caractère qui suit
^
debut de la ligne
$
fin de la ligne
|
le motif precedent ou le motif suivant
?
motif precédent répété zero ou une fois
*
motif précédent repété zéro ou plusieurs fois
+
motif précédent répété une ou plusieurs fois
.
un caractère quelconque
Développons en Java
84

Certains caractères spéciaux ont une notation particulière :
Notation
Rôle
\t
tabulation
\n
nouvelle ligne (ligne feed)
\\
backslash
Il est possible de définir des ensembles de caractères à l'aide des caractères [ et ]. Il suffit d'indiquer les caractères de
l'ensemble entre ces deux caractères
Exemple : toutes les voyelles
[aeiouy]
Il est possible d'utiliser une plage de caractères consécutifs en séparant le caractère de début de la plage et le caractère de
fin de la plage avec un caractère ?
Exemple : toutes les lettres minuscules
[a?z]
L'ensemble peut être l'union de plusieurs plages.
Exemple : toutes les lettres
[a?zA?Z]
Par défaut l'ensemble [] désigne tous les caractères. Il est possible de définir un ensemble de la forme tous sauf ceux
précisés en utilisant le caractère ^ suivi des caractères à enlever de l'ensemble
Exemple : tous les caractères sauf les lettres
[^a?zA?Z]
Il existe plusieurs ensembles de caractères prédéfinis :
Notation
Contenu de l'ensemble
\d
un chiffre
\D
tous sauf un chiffre
\w
une lettre ou un underscore
\W
tous sauf une lettre ou un underscore
\s
un séparateur (espace, tabulation, retour chariot, ...)
\S
tous sauf un séparateur
Développons en Java
85

Plusieurs métacaractères permettent de préciser un critère de répétition d'un motif
métacaractères
rôle
{n}
répétition du motif précédent n fois
{n,m}
répétition du motif précédent entre n et m fois
{n,}
répétition du motif précédent
?
motif precédent répété zero ou une fois
*
motif précédent repété zéro ou plusieurs fois
+
motif précédent répété une ou plusieurs fois
Exemple : la chaine AAAAA
A{5}
5.4.7.2. La classe Pattern
Cette classe encapsule une representation compilée d'un motif d'une expression régulière.
La classe Pattern ne possède pas de constructeur public mais propose une méthode statique compile().
Exemple :
      private static Pattern motif = null;
      ...
      motif = Pattern.compile("liste[0?9]");
Une version surchargée de la méthode compile() permet de préciser certaines options dont la plus interressante permet de
rendre insensible à la casse les traitements en utilisant le flag CASE_INSENSITIVE.
Exemple :
      private static Pattern motif = null;
      ...
      motif = Pattern.compile("liste[0?9]",Pattern.CASE_INSENSITIVE);
Cette méthode compile() renvoie une instance de la classe Pattern si le motif est syntaxiquement correcte sinon elle lève
une exception de type PatternSyntaxException.
La méthode matches(String, String) permet de rapidement et facilement utiliser les expressions régulières avec un seul
appel de méthode en fournissant le motif est la chaine à traiter.
Exemple :
      if (Pattern.matches("liste[0?9]","liste2")) {
            .println("liste2 ok");
Développons en Java
86

      } else {
            .println("liste2 ko");
      }
5.4.7.3. La classe Matcher
La classe Matcher est utilisée pour effectuer la comparaison entre une chaine de caractères et un motif encapsulé dans un
objet de type Pattern.
Cette classe ne possède aucun constructeur public. Pour obtenir une instance de cette classe, il faut utiliser la méthode
matcher() d'une instance d'un objet Pattern en lui fournissant la chaine à traiter en paramètre.
Exemple :
      motif = Pattern.compile("liste[0?9]");
      matcher = motif.matcher("liste1");
La méthodes matches() tente de comparer toute la chaine avec le motif et renvoie le résultat de cette comparaison.
Exemple :
      motif = Pattern.compile("liste[0?9]");
      matcher = motif.matcher("liste1");
      if (matcher.matches()) {
            .println("liste1 ok");
      } else {
            .println("liste1 ko");
      }
      matcher = motif.matcher("liste10");
      if (matcher.matches()) {
            .println("liste10 ok");
      } else {
            .println("liste10 ko");
      }
Résultat :
liste1 ok
liste10 ko
La méthode lookingAt() tente de recherche le motif dans la chaine à traiter
Exemple :
            motif = Pattern.compile("liste[0?9]");
            matcher = motif.matcher("liste1");
            if (matcher.lookingAt()) {
                  .println("liste1 ok");
            } else {
                  .println("liste1 ko");
            }
            matcher = motif.matcher("liste10");
            if (matcher.lookingAt()) {
                  .println("liste10 ok");
            } else {
                  .println("liste10 ko");
            }
Développons en Java
87

Résultat :
liste1 ok
 liste10 ok
La méthode find() permet d'obtenir des informations sur chaque occurrence ou le motif est trouvé dans la chaine à traiter.
Exemple :
      matcher = motif.matcher("zzliste1zz");
      if (()) {
            .println("zzliste1zz ok");
      } else {
           .println("zzliste1zz ko");
      }
Résultat :
zzliste1zz ok
Il est possible d'appeler successivement cette méthode pour obtenir chacune des occurrences.
Exemple :
       int i = 0;
        motif = Pattern.compile("liste[0?9]");
        matcher = motif.matcher("liste1liste2liste3");
        while (()) {
              i++;
        }
        .println("nb occurences = " + i);
Les méthodes start() et end() permettent de connaitre la position de début et de fin dans la chaine dans l'occurrence en
cours de traitement.
Exemple :
       int i = 0;
        motif = Pattern.compile("liste[0?9]");
        matcher = motif.matcher("liste1liste2liste3");
        while (()) {
              i++;
        }
        .println("nb occurences = " + i);
Résultat :
 pos debut : 0 pos fin : 6
  pos debut : 6 pos fin : 12
  pos debut : 12 pos fin : 18
  nb occurences = 3
La classe Matcher propose aussi les méthodes replaceFirst() et replaceAll() pour facilement remplacer la première ou
toutes les occurrences du motif trouvées par une chaine de caractères.
Développons en Java
88

Exemple : remplacement de la première occurrence
       motif = Pattern.compile("liste[0?9]");
        matcher = motif.matcher("zz liste1 zz liste2 zz");
        .println(matcher.replaceFirst("chaine"));
Résultat :
zz chaine zz liste2 zz
Exemple : remplacement de toutes les occurrences
      motif = Pattern.compile("liste[0?9]");
      matcher = motif.matcher("zz liste1 zz liste2 zz");
      .println(matcher.replaceAll("chaine"));
Résultat :
zz chaine zz chaine zz
5.5. Présentation rapide du package
Ce package contient un ensemble de classes pour permettre une interaction avec le réseau
Le chapitre l'interaction avec le reseau détaille l'utilisation de ce package
5.6. Présentation rapide du package java.applet
Ce package contient des classes à importer obligatoirement pour développer des applets
Le développement des applets est détaillé dans le chapitre les applets
Développons en Java
89

6. Les fonctions mathématiques
La classe contient une série de méthodes et variables mathématiques. Comme la classe Math fait partie du
package , elle est automatiquement importée. Il n'est pas nécessaire de déclarer un objet de type Math car les
méthodes sont toutes static
Exemple ( code java 1.1 ) : Calculer et afficher la racine carrée de 3
public class Math1 {
   public static void main(.String[] args) {
      .println(" = " + (3.0));
   }
}
6.1. Les variables de classe
PI représente pi dans le type double ( 3,14159265358979323846 )
E représente e dans le type double ( 2,7182818284590452354 )
Exemple ( code java 1.1 ) :
public class Math2 {
        public static void main(.String[] args) {
        .println(" PI = ");
                .println(" E = "+Math.E);
        }
}
6.2. Les fonctions trigonométriques
Les méthodes sin(), cos(), tan(), asin(), acos(), atan() sont déclarées : public static double fonctiontrigo(double a)
Les angles doivent être exprimés en radians. Pour convertir des degrés en radian, il suffit du multiplier par PI/180
6.3. Les fonctions de comparaisons
max (n1, n2)
min (n1, n2)
Ces méthodes existent pour les types int, long, float et double : elles déterminent respectivement les valeurs maximales et
minimales des deux paramètres.
Développons en Java
90

Exemple ( code java 1.1 ) :
public class Math1 {
        public static void main(String[] args) {
                .println(" le plus grand = " + (5, 10));
                .println(" le plus petit = " + (7, 14));
        }
}
Résultat :
le plus grand = 10
le plus petit = 7
6.4. Les arrondis
6.4.1. La méthode round(n)
Cette méthode ajoute 0,5 à l'argument et restitue la plus grande valeur entière (int) inférieure ou égale au résultat. La
méthode est définie pour les types float et double.
Exemple ( code java 1.1 ) :
public class Math1 {
        public static void main(String[] args) {
        .println(" round(5.0) = "+Math.round(5.0));
        .println(" round(5.2) = "+Math.round(5.2));
        .println(" round(5.5) = "+Math.round(5.5));
        .println(" round(5.7) = "+Math.round(5.7));
        }
}
Résultat :
round(5.0) = 5
round(5.2) = 5
round(5.5) = 6
round(5.7) = 6
6.4.2. La méthode rint(double)
Cette méthode effectue la même opération mais renvoie un type double
Exemple ( code java 1.1 ) :
public class Math1 {
        public static void main(String[] args) {
        .println(" rint(5.0) = "(5.0));
        .println(" rint(5.2) = "(5.2));
        .println(" rint(5.5) = "(5.5));
        .println(" rint(5.7) = "(5.7));
        }
}
Développons en Java
91

Résultat :
rint(5.0) = 5.0
rint(5.2) = 5.0
rint(5.5) = 6.0
rint(5.7) = 6.0
6.4.3. La méthode floor(double)
Cette méthode renvoie l'entier le plus proche inférieur ou égal à l'argument
Exemple ( code java 1.1 ) :
public class Math1 {
        public static void main(String[] args) {
        .println(" floor(5.0) = "+Math.floor(5.0));
        .println(" floor(5.2) = "+Math.floor(5.2));
        .println(" floor(5.5) = "+Math.floor(5.5));
        .println(" floor(5.7) = "+Math.floor(5.7));
        }
}
résultat :
floor(5.0) = 5.0
floor(5.2) = 5.0
floor(5.5) = 5.0
floor(5.7) = 5.0
6.4.4. La méthode ceil(double)
Cette méthode renvoie l'entier le plus proche supérieur ou égal à l'argument
Exemple ( code java 1.1 ) :
public class Math1 {
        public static void main(String[] args) {
        .println(" ceil(5.0) = "(5.0));
        .println(" ceil(5.2) = "(5.2));
        .println(" ceil(5.5) = "(5.5));
        .println(" ceil(5.7) = "(5.7));
        }
}
résultat :
ceil(5.0) = 5.0
ceil(5.2) = 6.0
ceil(5.5) = 6.0
ceil(5.7) = 6.0
Développons en Java
92

6.4.5. La méthode abs(x)
Cette méthode donne la valeur absolue de x (les nombre négatifs sont convertis en leur opposé). La méthode est définie
pour les types int, long, float et double.
Exemple ( code java 1.1 ) :
public class Math1 {
        public static void main(String[] args) {
        .println(" abs(?5.7) = "+abs(?5.7));
        }
}
Résultat :
abs(?5.7) = 5.7
6.5. La méthode IEEEremainder(double, double)
Cette méthode renvoie le reste de la division du premier argument par le deuxieme
Exemple ( code java 1.1 ) :
public class Math1 {
        public static void main(String[] args) {
        .println(" reste de la division de 3 par 10 = "
           +Math.IEEEremainder(10.0, 3.0) );
        }
}
Résultat :
reste de la division de 3 par 10 = 1.0
6.6. Les Exponentielles et puissances
6.6.1. La méthode pow(double, double)
Cette méthode elève le premier argument à la puissance indiquée par le second.
Exemple ( code java 1.1 ) :
public static void main(.String[] args) {
        .println(" 5 au cube  = "(5.0, 3.0) );
}
Résultat :
Développons en Java
93

5 au cube  = 125.0
6.6.2. La méthode sqrt(double)
Cette méthode calcule la racine carrée de son paramètre.
Exemple ( code java 1.1 ) :
public static void main(.String[] args) {
  .println(" racine carree de 25  = "(25.0) );
}
Résultat :
racine carree de 25  = 5.0
6.6.3. La méthode exp(double)
Cette méthode calcule l'exponentielle de l'argument
Exemple ( code java 1.1 ) :
public static void main(.String[] args) {
        .println(" exponentiel de 5  = "(5.0) );
}
Résultat :
exponentiel de 5  = 148.4131591025766
6.6.4. La méthode log(double)
Cette méthode calcule le logarithme naturel de l'argument
Exemple ( code java 1.1 ) :
public static void main(.String[] args) {
        .println(" logarithme de 5  = "(5.0) );
}
Résultat :
logarithme de 5  = 1.6094379124341003
Développons en Java
94

6.7. La génération de nombres aléatoires
6.7.1. La méthode random()
Cette méthode renvoie un nombre aléatoire compris entre 0.0 et 1.0.
Exemple ( code java 1.1 ) :
public static void main(.String[] args) {
        .println(" un nombre aléatoire  = "+Math.random() );
}
Résultat :
un nombre aléatoire  = 0.8178819778125899
Développons en Java
95

7. La gestion des exceptions
Les exceptions représentent le mécanisme de gestion des erreurs intégré au langage java. Il se compose d'objets
représentant les erreurs et d'un ensemble de trois mots clés qui permettent de détecter et de traiter ces erreurs ( try, catch
et finally ) et de les lever ou les propager (throw et throws).
Lors de la détection d'une erreur, un objet qui hérite de la classe Exception est créé (on dit qu'une exception est levée) et
propagé à travers la pile d'execution jusqu'à ce qu'il soit traitée.
Ces mécanismes permettent de renforcer la sécurité du code java.
Exemple ( code java 1.1 ) : une exception levée à l'exécution non capturée
public class TestException {
   public static void main(.String[] args) {
      int i = 3;
      int j = 0;
      .println("résultat = " + (i / j));
   }
}
Résultat :
C:>java TestException
Exception in thread "main" .ArithmeticException: / 
by zero
        at (:23)
Si dans un bloc de code on fait appel à une méthode qui peut potentiellement générer une exception, on doit soit essayer
de la récupérer avec try/catch, soit ajouter le mot clé throws dans la déclaration du bloc. Si on ne le fait pas, il y a une
erreur à la compilation. Les erreurs et exceptions du paquetage échappe à cette contrainte. Throws permet de
déléguer la responsabilité des erreurs vers la méthode appelante
Ce procédé présente un inconvénient : de nombreuses méthodes des packages java indiquent dans leur déclaration
qu'elles peuvent lever une exception. Cependant ceci garantie que certaines exceptions critiques seront prises
explicitement en compte par le programmeur.
7.1. Les mots clés try, catch et finally
Le bloc try rassemble les appels de méthodes susceptibles de produire des erreurs ou des exceptions. L'instruction try est
suivie d'instructions entre des accolades.
Exemple ( code java 1.1 ) :
Développons en Java
96

   try {
        operation_risquée1;
        opération_risquée2;
    } catch (ExceptionInteressante e) {
        traitements
    } catch (ExceptionParticulière e) {
        traitements
    } catch (Exception e) {
        traitements
    } finally {
        traitement_pour_terminer_proprement;
    }
Si un événement indésirable survient dans le bloc try, la partie éventuellement non exécutée de ce bloc est abandonnée et
le premier bloc catch est traité. Si catch est défini pour capturer l'exception issue du bloc try alors elle est traitée en
exécutant le code associé au bloc. Si le bloc catch est vide (aucunes instructions entre les accolades) alors l'exception
capturée est ignorée.
Si il y a plusieurs type d'erreurs et d'exceptions à intercepter, il faut définir autant de bloc catch que de type d'événement .
Par type d'exception, il faut comprendre « qui est du type de la classe de l'exception ou d'une de ces sous classes ». Ainsi
dans l'ordre séquentiel des clauses catch, un type d'exception de ne doit pas venir après un type d'une exception d'une
super classe. Il faut faire attention à l'ordre des clauses catch pour traiter en premier les exceptions les plus précises (sous
classes) avant les exceptions plus générales. Un message d'erreur est émis par le compilateur dans le cas contraire.
Exemple ( code java 1.1 ) : erreur à la compil car Exception est traité en premier alors que ArithmeticException est une
sous classe de Exception
public class TestException {
    public static void main(.String[] args) {
        // Insert code to start the application here.
        int i = 3;
        int j = 0;
        try {
            .println("résultat = " + (i / j));
        }
        catch (Exception e) {
        }
        catch (ArithmeticException e) {
        }
    }
}
Résultat :
C:\tests>javac
:11: catch not reached.
        catch (ArithmeticException e) {
        ^
1 error
Si l'exception générée est une instance de la classe déclarée dans la clause catch ou d'une classe dérivée, alors on exécute
le bloc associé. Si l'exception n'est pas traitées par un bloc catch, elle sera transmise au bloc de niveau supérieur. Si l'on
ne se trouve pas dans un autre bloc try, on quitte la méthode en cours, qui regénère à son tour une exception dans la
méthode appelante.
L'exécution totale du bloc try et d'un bloc d'une clause catch sont mutuellement exclusives : si une exception est levée,
l'exécution du bloc try est arrêtée et si elle existe, la clause catch adéquate est exécutée.
La clause finally définit un bloc qui sera toujours exécuté, qu'une exception soit levée ou non. Ce bloc est facultatif. Il est
aussi exécuté si dans le bloc try il y a une instruction break ou continue.
Développons en Java
97

7.2. La classe Throwable
Cette classe descend directement de Object : c'est la classe de base pour le traitements des erreurs.
Cette classe possède deux constructeurs :
Méthode
Rôle
Throwable()
La chaine en paramètre permet de définir un message qui décrit
Throwable(String)
l'exception et qui pourra être consultée dans un bloc catch.
Les principales méthodes de la classe Throwable sont :
Méthodes
Rôle
String getMessage( )
lecture du message
void printStackTrace( )
affiche l'exception et l'état de la pile d'execution au moment de son appel
void printStackTrace(PrintStream s)
Idem mais envoie le résultat dans un flux
Exemple ( code java 1.1 ) :
public class TestException {
    public static void main(.String[] args) {
        // Insert code to start the application here.
        int i = 3;
        int j = 0;
        try {
            .println("résultat = " + (i / j));
        }
        catch (ArithmeticException e) {
            .println("getmessage");
            .println(e.getMessage());
            .println(" ");
            .println("toString");
            .println(e.toString());
            .println(" ");
            .println("printStackTrace");
            e.printStackTrace();
        }
    }
}
Résultat :
C:>java TestException
getmessage
/ by zero
toString
.ArithmeticException: / by zero
printStackTrace
.ArithmeticException: / by zero
        at (:24)
Développons en Java
98

7.3. Les classes Exception, RunTimeException et Error
Ces trois classes descendent de Throwable : en fait, toutes les exceptions dérivent de la classe Throwable.
La classe Error représente une erreur grave intervenue dans la machine virtuelle Java ou dans un sous système Java.
L'application Java s'arrête instantanement dès l'apparition d'une exception de la classe Error.
La classe Exception représente des erreurs moins graves. La classe RuntimeException n'ont pas besoin d'être détectées
impérativement par des blocs try/catch
7.4. Les exceptions personnalisées
Pour générer une exception, il suffit d'utiliser le mot clé throw, suivi d'un objet dont la classe dérive de Thowable. Si l'on
veut générer une exception dans une méthode avec throw, il faut l'indiquer dans la déclaration de la méthode, en utilisant
le mot clé throws.
En cas de nécessité, on peut créer ces propres exceptions. Elles descendent des classes Exception ou RunTimeException
mais pas de la classe Error. Il est préférable (par convention) d'inclure le mot « Exception » dans le nom de la nouvelle
classe.
Exemple ( code java 1.1 ) :
public class SaisieErroneeException extends Exception {
    public SaisieErroneeException() {
        super();
    }
    public SaisieErroneeException(String s) {
        super(s);
    }
}
public class TestSaisieErroneeException {
    public static void controle(String chaine) throws 
SaisieErroneeException {
        if (chaine.equals("") == true)
            throw new SaisieErroneeException("Saisie erronee : chaine vide");
    }
    public static void main(.String[] args) {
        String chaine1 = "bonjour";
        String chaine2 = "";
        try {
            controle(chaine1);
        }
        catch (SaisieErroneeException e) {
            .println("Chaine1 saisie erronee");
        };
        try {
            controle(chaine2);
        }
        catch (SaisieErroneeException e) {
            .println("Chaine2 saisie erronee");
        };
    }
}
Les méthodes pouvant lever des exceptions doivent inclure une clause throws nom_exception dans leur en tête. L'objectif
est double : avoir une valeur documentaire et préciser au compilateur que cette méthode pourra lever cette exception et
que toute méthode qui l'appelle devra prendre en compte cette exception (traitement ou propagation).
Développons en Java
99

Si la méthode appelante ne traite pas l'erreur ou ne la propage pas, le compilateur génère l'exception nom_exception must
be caught or it must be déclared in the thows clause of this méthode.
Java n'oblige la déclaration des exceptions dans l'en tête de la méthode que pour les exceptions dites controlées
(checked). Les exception non controlées (unchecked) peuvent être capturée mais n'ont pas a être déclarée. Les exceptions
et erreurs qui héritent de RunTimeException et de Error sont non controlées. Toutes les autres exceptions sont controlées.
Développons en Java
100

8. Le multitâche
La suite de ce chapitre sera développée dans une version future de ce document
Un thread est une unité d’éxecution faisant partie d’un programme. Cette unité fonctionne de façon autonome et
parallèlement à d'autres threads. En fait, sur une machine mono processeur, chaque unité se voie attribuer des intervalles
de temps au cours desquels elles ont le droit d’utiliser le processeur pour accomplir leurs traitements.
La gestion de ces unités de temps par le système d'exploitation est appellé scheduling. Il en existe deux grands types de
scheduller:
le découpage de temps : utilisé par Windows et Macintosh OS jusqu'à la version 9. Ce système attribue un
• 
intervalle de temps prédéfini quelque soit le thread et la priorité qu'il peut avoir
la préemption : utilisé par les systèmes de type Unix. Ce système attribut les intervalles de temps en tenant
• 
compte de la priorité d'exécution de chaque thread. Les threads possédant une priorité plus élevée s'exécutent
avant ceux possédant une priorité plus faible.
Le principal avantage des threads est de pouvoir répartir différents traitements d’un même programme en plusieurs unités
distinctes pour permettre leur exécution "simultanée".
La classe .Thread et l’interface .Runnable sont les bases pour le développement des threads en java.
Par exemple, pour exécuter des applets dans un thread, il faut que celles ci implémentent l’interface Runnable.
Le cycle de vie d’un thread est toujours le même qu’il hérite de la classe Thread ou qu’il implémente l’interface
Runnable. L’objet correspondant au thread doit être créé, puis la méthode start() est appellée qui à son tour invoque la
méthode run(). La méthode stop() permet d’interrompre le thread.
Avant que le thread ne s’exécute, il doit être démarré par un appel à la méthode start(). On peut créer l’objet qui
encapsule le thread  dans la méthode start() d’une applet, dans sa méthode init() ou dans le constructeur d'une classe.
8.1. L’interface Runnable
Cette interface doit être implémentée par toute classe qui contiendra des traitements à exécuter dans un thread.
Développons en Java
101

Cette interface ne définit qu’une seule méthode : void run().
Dans les classes qui implémentent cette interface, la méthode run() doit être redéfinie pour contenir le code des
traitements qui seront exécutés dans le thread.
Exemple :
package ;
public class MonThread3 implements Runnable {
  public void run() {
    int i = 0;
    for (i = 0; i <10; i++) {
      .println("" + i);
    }
  }
}
Lors du démarrage du thread, la méthode run() est appelée.
8.2. La classe Thread
La classe Thread est définie dans le package . Elle implémente l’interface Runnable.
Elle possède plusieurs constructeurs : un constructeur par défaut et plusieurs autres qui peuvent avoir un ou plusieurs des
paramètres suivants :
Paramètre
Rôle
le nom du thread : si aucun n’est précisé alors le nom sera thread?nnn ou nnn
un nom
est un numéro séquentiel
un objet qui implémente l’interface
l’objet qui contient les traitements du thread
Runnable
un groupe
le groupe auquel sera rattaché le thread
Un thread possède une priorité et un nom. Si aucun nom particulier n'est donné dans le constructeur du thread, un nom
par défaut composé du sufixe "Thread?" suivi d'un numéro séquentiel incrémenté automatiquement lui est attribué.
La classe thread possède plusieurs méthodes pour gérer le cycle de vie du thread.
Méthode
Rôle
void destroy()
met fin brutablement au thread : a n’utiliser qu’en dernier recours.
int getPriority()
renvoie la priorité du thread
ThreadGroup getThreadGroup()
renvoie un objet qui encapsule le groupe auquel appartient le thread
boolean isAlive()
renvoie un booléen qui indique si le thread est actif ou non
boolean isInterrupted()
renvoie un booléen qui indique si le thread a été interrompu
void join()
reprend l’exécution du thread( ) préalablement suspendu par suspend( ). Cette
void resume()
méthode est dépréciée
Développons en Java
102

méthode déclarée par l’interface Runnable : elle doit contenir le code qui sera
void run()
éxécuté par le thread
mettre le thread en attente durant le temp exprimé en millisecondes fourni en
void sleep(long)
paramètre. Cette méthode peut lever un exception de type InterruptedException si le
thread est réactivé avant la fin du temp.
void start()
démarrer le thread et éxécuter la méthode run()
void stop()
arrêter le thread. Cette méthode est dépréciée
suspend le thread jusqu’au moment où il sera relancé par la méthode resume( ).
void suspend()
Cette méthode est dépréciée
indique à l’interpréteur que le thread peut être suspendu pour permettre à d'autres
void yield()
threads de s'exécuter.
Le cycle de vie avec le JDK 1.0 est le suivant :
Le comportement de la méthode start() de la classe Thread dépend de la façon dont l'objet est instancié. Si l’objet qui
reçoit le message start() est instancié avec un constructeur qui prend en paramètre un objet Runnable, c’est la méthode
run() de cet objet qui est appelée. Si l’objet qui reçoit le message start() est instancié avec un constructeur qui ne prend
pas en paramètre une référence sur un objet Runnable, c’est la méthode run() de l’objet qui reçoit le message start() qui
est appelée.
A partir du J.D.K. 1.2, les méthodes stop(), suspend() et resume() sont dépréciées. Le plus simple et le plus efficace est
de définir un attribut booléen dans la classe du thread initialisé à true. Il faut définir une méthode qui permet de basculer
cet attribut à false. Enfin dans la méthode run() du thread, il suffit de continuer les traitements tant que l'attribut est à true
et que les autres conditions fonctionnelles d'arrêt du thread sont négatives.
Exemple : exécution du thread jusqu'à l'appui sur la touche Entrée
public class MonThread6 extends Thread {
  private boolean actif = true;
  public static void main(String[] args) {
    try {
      MonThread6 t = new MonThread6();
      t.start();
      ();
      t.arreter();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  public void run() {
    int i = 0;
Développons en Java
103

    while (actif) {
      .println("i = " + i);
      i++;
    }
  }
  public void arreter() {
    actif = false;
  }
}
Si la méthode start() est appelée alors que le thread est déjà en cours d’éxécution, une exception de type
IllegalThreadStateException est levée.
Exemple :
package ;
public class MonThread5 {
  public static void main(String[] args) {
    Thread t = new Thread(new MonThread3());
    t.start();
    t.start();
  }
}
Résultat :
.IllegalThreadStateException
      at .Thread.start(Native Method)
      at (:14)
Exception in thread "main"
La méthode sleep() permet d’endormir le thread durant le temps en millisecondes fournis en paramètres de la méthode.
La méthode statique currentThread() renvoie le thread en cours d’exécution.
La méthode isAlive() renvoie un booléen qui indique si le thread est en cours d’exécution.
8.3. La création et l'exécution d’un thread
Pour que les traitements d'une classe soient exécutés dans un thread, il faut obligatoirement que cette classe implémente
l’interface Runnable puis que celle ci soit associée directement ou indirectement à un objet de type Thread
Il y a ainsi deux façons de définir une telle classe
la classe hérite de la classe Thread
• 
la classe implémente l’interface Runnable
• 
8.3.1. La dérivation de la classe Thread
Le plus simple pour définir un thread est de créer une classe qui hérite de la classe .Thread.
Il suffit alors simplement de redéfinir la méthode run() pour y inclure les traitements à exécuter par le thread.
Développons en Java
104

Exemple :
package ;
public class MonThread2 extends Thread {
  public void run() {
    int i = 0;
    for (i = 0; i <10; i++) {
      .println("" + i);
    }
  }
}
Pour créer et exécuter un tel thread, il faut instancier un objet et appeler sa méthode start(). Il est obligatoire d'appeler la
méthode start() qui va créer le thread et elle?même appeler la méthode run().
Exemple :
package ;
public class MonThread2 extends Thread {
  public static void main(String[] args) {
        Thread t = new MonThread2();
        t.start();
  }
  public void run() {
    int i = 0;
    for (i = 0; i <10; i++) {
      .println("" + i);
    }
  }
}
8.3.2. Implémentation de l’interface Runnable
Si on utilise l’interface Runnable , il faut uniquement redéfinir sa seule et unique méthode run() pour y inclure les
traitements à exécuter dans le thread.
Exemple :
package ;
public class MonThread3 implements Runnable {
  public void run() {
    int i = 0;
    for (i = 0; i <10; i++) {
      .println("" + i);
    }
  }
}
Pour pouvoir utiliser cette classe dans un thread, il faut l’associer à un objet de la classe Thread. Ceci ce fait en utilisant
un des constructeurs de la classe Thread qui accepte un objet implémentant l’interface Runnable en paramètre.
Développons en Java
105

Exemple :
package ;
public class MonThread4 {
  public static void main(String[] args) {
    Thread t = new Thread(new MonThread3());
    t.start();
  }
}
Il ne reste plus alors qu'à appeller la méthode start() du nouvel objet.
8.3.3. Modification de la priorité d’un thread
Lors de la création d’un thread, la priorité du nouveau thread est égale à celle du thread dans lequel il est créé. Si le
thread n’est pas créé dans un autre thread, la priorité moyenne est attribué au thread. Il est cependant possible d’attribuer
une autre priorité plus ou moins élevée.
En java, la gestion des threads est intimement liée au système d'exploitation dans lequel s'exécute la machine virtuelle.
Sur des machines de type Mac ou Unix, le thread qui a la plus grande priorité a systématiquement accès au processeur si
il ne se trouve pas en mode « en attente ». Sous Windows 95, le système ne gère pas correctement les priorités et il
choisit lui même le thread a exécuter : l’attribution d’un priorité supérieure permet simplement d'augmenter ses chances
d’exécution.
La priorité d’un thread varie de 1 à 10 , la valeur 5 étant la valeur par défaut. La classe Thread définit trois constantes :
MIN_PRIORITY :
priorité inférieure
NORM_PRIORITY :
priorité standard
MAX_PRIORITY :
priorité supérieure
Exemple :
package ;
public class MonThread10 {
  public static void main(String[] args) {
    .println("Thread.MIN_PRIORITY  = " + Thread.MIN_PRIORITY);
    .println("Thread.NORM_PRIORITY = " + Thread.NORM_PRIORITY);
    .println("Thread.MAX_PRIORITY  = " + Thread.MAX_PRIORITY);
  }
}
Résultat :
Thread.MIN_PRIORITY  = 1
Thread.NORM_PRIORITY = 5
Thread.MAX_PRIORITY  = 10
Pour déterminer ou modifier la priorité d’un thread, la classe Thread contient les méthodes suivantes :
Méthode
Rôle
int getPriority()
retourne la priorité d’un thread
Développons en Java
106

void setPriority(int)
modifie la priorité d’un thread
La méthode setPriority() peut lever l’exception IllegalArgumentException si la priorité fournie en paramètre n’est pas
comprise en 1 et 10.
Exemple :
package ;
public class MonThread9 {
  public static void main(String[] args) {
    Thread t = new Thread();
    t.setPriority(20);
  }
}
Résultat :
.IllegalArgumentException
        at .Thread.setPriority(Unknown Source)
        at (:8)
Exception in thread "main" 
8.4. La classe ThreadGroup
La classe ThreadGroup représente un ensemble de threads. Il est ainsi possible de regrouper des threads selon différents
critères. Il suffit de créer un objet de la classe ThreadGroup  et de lui affecter les différents threads. Un objet
ThreadGroup peut contenir des threads mais aussi d’autres objets de type ThreadGroup.
La notion de groupe permet de limiter l’accès aux autres threads. Chaque thread ne peut manipuler que les threads de son
groupe d'appartenance ou des groupes subordonnés.
La classe ThreadGroup possède deux constructeurs :
Constructeur
Rôle
ThreadGroup(String nom)
création d’un groupe avec attribution d’un nom
ThreadGroup(ThreadGoup groupe_parent, String
création d’un groupe à l’intérieur du groupe spécifié avec
nom)
l’attribution d’un nom
Pour ajouter un thread à un groupe, il suffit de préciser le groupe en paramètre du constructeur du tread.
Exemple :
package ;
public class MonThread11 {
  public static void main(String[] args) {
    ThreadGroup tg = new ThreadGroup("groupe");
    Thread t1 = new Thread(tg,new MonThread3(), "numero 1");
    Thread t2 = new Thread(tg,new MonThread3(), "numero 2");
Développons en Java
107

  }
}
L’un des avantages de la classe ThreadGroup  est de permettre d’effectuer une action sur tous les threads d’un même
groupe. On peut, par exemple avec Java 1.0, arrêter tous les threads du groupe en lui appliquant la méthode stop().
8.5. Thread en tâche de fond (démon)
Il existe une catégorie de threads qualifiés de démons : leur exécution peut se poursuivre même après l'arrêt de
l'application qui les a lancés.
Une application dans laquelle les seuls threads actifs sont des démons est automatiquement fermée.
Le thread doit d’abord être créé comme thread standard puis transformé en demon par un appel à la méthode
setDaemon() avec le paramètre true. Cet appel se fait avant le lancement du thread, sinon une exception de type
IllegalThreadStateException est levée.
8.6. Exclusion mutuelle
Chaque fois que plusieurs threads s’exécutent en même temps, il faut prendre des précautions concernant leur bonne
exécution. Par exemple, si deux threads veulent accéder à la même variable, il ne faut pas qu’ils le fassent en même
temps.
Java offre un système simple et efficace pour réaliser cette tache. Si une méthode déclarée avec le mot clé synchronized
 est déjà en cours d’exécution, alors les threads qui en auraient également besoin doivent attendre leur tour.
Le mécanisme d’exclusion mutuelle en Java est basé sur le moniteur. Pour définir une méthode protégée, afin de
s’assurer de la cohérence des données, il faut utiliser le mot clé synchronized. Cela créé à l'exécution, un moniteur
associé à l'objet qui empèche les méthodes déclarées synchronized d'être utilisées par d'autres objets dès lors qu'un objet
utilise déjà une des méthodes synchronisées de cet objet. Dès l'appel d'une méthode synchronisée, le moniteur vérouille
tous les autres appels de méthodes synchronisées de l'objet. L'accès est de nouveau automatiquement possible dès la fin
de l'exécution de la méthode.
Ce procédé peut bien évidemment dégrader les performances lors de l'exécution mais il garantit, dès lors qu'il est
correctement utilisé, la cohérence des données.
8.6.1. Sécurisation d’une méthode
Lorsque l’on crée une instance d’une classe, on crée également un moniteur qui lui est associé. Le modificateur
synchronized  place la méthode (le bloc de code) dans ce moniteur, ce qui assure l’exclusion mutuelle
Le méthode ainsi déclarée ne peut être exécutée par plusieurs processus simultanement. Si le moniteur est occupée, les
autres processus seront mis en attente. L’ordre de reveille des processus pour accéder à la méthode n’est pas prévisible.
Si un objet dispose de plusieurs méthodes synchronized, ces dernières ne peuvent être appelées que par le thread
possédant le verou sur l'objet.
Développons en Java
108

8.6.2. Sécurisation d’un bloc
L’utilisation de méthodes synchronisées trop longues à exécuter peut entrainer une baisse d’efficacité lors de l'exécution.
Avec java, il est possible de placer n’importe quel bloc de code dans un moniteur pour permettre de réduire la longueur
des sections de code sensibles.
     synchronized  void methode1() {
        // bloc de code sensible
        ...
     }
           void methode2(Object obj) {
        ...
        synchronized (obj) {
           // bloc de code sensible
           ...
        }
     }
L'objet dont le moniteur est à utiliser doit être passé en paramètre de l’instruction synchronized .
8.6.3. Sécurisation de variables de classes
Pour sécuriser une variable de classe, il faut un moniteur commun à toutes les instances de la classe. La méthode
getClass() retourne la classe de l’instance dans laquelle on l’appelle. Il suffit d’utiliser un moniteur qui utilise le résultat
de getClass() comme verrou.
8.6.4. La synchronisation : les méthodes wait() et notify()
Développons en Java
109

Partie 2 : Développement des interfaces graphiques
Les interfaces graphiques assurent le dialogue entre les utilisateurs et une application.
Dans un premier temps, java propose l'API AWT pour créer des interfaces graphiques. Depuis, java propose une
nouvelle API nommée Swing.
Ces deux API peuvent être utilisées pour développer des applications ou des applets.
Cette partie contient les chapitres suivants :
le graphisme : entame une série de chapitres sur les l'interfaces graphiques en détaillant les objets et méthodes
• 
de base pour le graphisme
les éléments de l'AWT : recense les différents composants qui sont fournis dans l'AWT
• 
la création d'interfaces graphiques avec AWT : indique comment réaliser des interfaces graphiques avec l'AWT
• 
l'interception des actions de l'utilisateur : détaille les mécanismes qui permettent de réagir aux actions de
• 
l'utilisateur via une interface graphique
le développement d'interface graphique avec Swing : indique comment réaliser des interfaces graphiques avec
• 
Swing
les applets : plonge au coeur des premières applications qui ont rendu java célèbre
• 
Développons en Java
110

9. Le graphisme
La classe Graphics contient les outils nécessaires pour dessiner. Cette classe est abstraite et elle ne possède pas de
constructeur public : il n'est pas possible de construire des instances de graphics nous même. Les instances nécessaires
sont fournies par le système d'exploitation qui instanciera via à la machine virtuelle une sous classe de Graphics
dépendante de la plateforme utilisée.
9.1. Les opérations sur le contexte graphique
9.1.1. Le tracé de formes géométriques
A l 'exception des lignes, toutes les formes peuvent être dessinées vides (méthode drawXXX) ou pleines (fillXXX).
La classe Graphics possède de nombreuses méthodes qui permettent de réaliser des dessins.
Méthode
Role
drawRect(x, y, largeur, hauteur)
dessiner un carré ou un rectangle
fillRect(x, y, largeur, hauteur)
drawRoundRect(x, y, largeur, hauteur,
hor_arr,ver_arr)
dessiner un carré ou un rectangle arrondi
fillRoundRect(x, y, largeur, hauteur, hor_arr,
ver_arr)
drawLine(x1, y1, x2, y2)
Dessiner une ligne
drawOval(x, y, largeur, hauteur)
dessiner un cercle ou une elipse en spécifiant le rectangle
fillOval(x, y, largeur, hauteur)
dans lequel ils s'incrivent
drawPolygon(int[], int[], int)
Dessiner un polygone ouvert ou fermé. Les deux premiers
fillPolygon(int[], int[], int)
paramètres sont les coordonnées en abscisses et en
ordonnées. Le dernier paramètres est le nombre de points du
polygone.
Pour dessiner un polygone fermé il faut joindre le dernier
point au premier.
Exemple ( code java 1.1 ) :
int[] x={10,60,100,80,150,10};
int[] y={15,15,25,35,45,15};
g.drawPolygon(x,y,x.length);
g.fillPolygon(x,y,x.length);
Développons en Java
111

Il est possible de définir un objet Polygon.
Exemple ( code java 1.1 ) :
int[] x={10,60,100,80,150,10};
int[] y={15,15,25,35,45,15};
Polygon p = new Polygon(x, y,x.length );
g.drawPolygon(p);
drawArc(x, y, largeur, hauteur, angle_deb,
dessiner un arc d'ellipse inscrit dans un rectangle ou un carré.
angle_bal)
L'angle 0 se situe à 3 heures. Il faut indiquer l'angle de début
fillArc(x, y, largeur, hauteur, angle_deb,
et l'angle balayé
angle_bal);
9.1.2. Le tracé de texte
La méthode drawString() permet d'afficher un texte aux coordonnées précisées
Exemple ( code java 1.1 ) :
g.drawString(texte, x, y );
Pour afficher des nombres int ou float, il suffit de les concatener à une chaine éventuellement vide avec l'opérateur +.
9.1.3. L'utilisation des fontes
La classe Font permet d'utiliser une police de caractères particulière pour affiche un texte.
Exemple ( code java 1.1 ) :
Font fonte = new Font(« TimesRoman »,,30);
Le constructeur de la classe Font est Font(String, int, int). Les paramètres sont : le nom de la police, le style (BOLD,
ITALIC, PLAIN ou 0,1,2) et la taille des caractères en points.
Pour associer plusieurs styles, il suffit de les additionner
Exemple ( code java 1.1 ) :
+ Font.ITALIC
Si la police spécifiée n'existe pas, Java prend la fonte par défaut même si une autre a été spécifiée précedemment. Le
style et la taille seront tout de même adpatés. La méthode getName() de la classe Font retourne le nom de la fonte.
La méthode setFont() de la classe Graphics permet de changer la police d'affichage des textes
Exemple ( code java 1.1 ) :
Font fonte = new Font("
TimesRoman ",,30);
Développons en Java
112

g.setFont(fonte);
g.drawString("bonjour",50,50);
Les polices suivantes sont utilisables : Dialog, Helvetica, TimesRoman, Courier, ZapfDingBats
9.1.4. La gestion de la couleur
La méthode setColor() permet de fixer la couleur des éléments graphiques des objets de type Graphics créés après à son
appel.
Exemple ( code java 1.1 ) :
g.setColor(Color.black); //(green, blue, red, white, black, ...)
9.1.5. Le chevauchement de figures graphiques
Si 2 surfaces de couleur différentes se superposent, alors la derniere dessinée recouvre la précédente sauf si on invoque la
méthode setXORMode(). Dans ce cas, la couleur de l'intersection prend une autre couleur. L'argument à fournir est une
couleur alternative. La couleur d'intersection représente une combinaison de la couleur originale et de la couleur
alternative.
9.1.6. L'effacement d'une aire
La méthode clearRect(x1, y1, x2, y2) dessine un rectangle dans la couleur de fond courante.
9.1.7. La copier une aire rectangulaire
La méthode copyArea(x1, y1, x2, y2, dx, dy) permet de copier une aire rectangulaire. Les paramètres dx et dy permettent
de spécifier un décalage en pixels de la copie par rapport à l'originale.
Développons en Java
113

10. Les éléments d'interface graphique de l'AWT
Les classes du toolkit AWT (Abstract Windows Toolkit) permettent d'écrire des interfaces graphiques indépendantes du
système d'exploitation sur lesquelles elles vont fonctionner. Cette librairie utilise le système graphique de la plateforme
d'exécution (Windows, MacOS, X?Window) pour afficher les objets graphiques. Le toolkit contient des classes décrivant
les composants graphiques, les polices, les couleurs et les images.
Développons en Java
114

Le diagramme ci dessus définit une vue partielle de la hiérarchie des classes (les relations d'héritage) qu'il ne faut pas
confondre avec la hiérarchie interne à chaque application qui définit l'imbrication des différents composants graphiques.
Les deux classes principales de AWT sont Component et Container. Chaque type d'objet de l'interface graphique est une
classe dérivée de Component. La classe Container, qui hérite de Component est capable de contenir d'autres objets
graphiques (tout objet dérivant de Component).
Ce chapitre contient plusieurs sections :
Les composants graphiques
• 
Les étiquettes

Les boutons

Les panels

Les listes déroulantes (combobox)

La classe TextComponent

Le champs de texte

Les zones de texte multilignes

Les listes

Les cases à cocher

Les boutons radio

Les barres de défilement

La classe Canvas

La classe Component
• 
Les conteneurs
• 
Le conteneur Panel

Le conteneur Window

Le conteneur Frame

Le conteneur Dialog

Les menus
• 
10.1. Les composants graphiques
Pour utiliser un composant, il faut créer un nouvel objet représentant le composant et l'ajouter à un de type conteneur qui
existe avec la méthode add().
Exemple ( code java 1.1 ) : ajout d'un bouton dans une applet (Applet hérite de Panel)
import java.applet.*;
import .*;
public class AppletButton extends Applet {
   Button b = new Button(" Bouton ");
   public void init() {
      ();
      add(b);
   }
}
Développons en Java
115

10.1.1. Les étiquettes
Il faut utiliser un objet de la classe .Label
Exemple ( code java 1.1 ) :
Label la = new Label( );
la.setText("une etiquette");
// ou Label la = new Label("une etiquette");
Il est possible de créer un objet de la classe .Label en précisant l'alignement du texte
Exemple ( code java 1.1 ) :
Label la = new Label("etiquette", Label.RIGHT);
Le texte à afficher et l'alignement peuvent être modifiés dynamiquement lors de l'éxecution :
Exemple ( code java 1.1 ) :
la.setText("nouveau texte");
la.setAlignment();
10.1.2. Les boutons
Il faut utiliser un objet de la classe .Button
Cette classe possède deux constructeurs :
Constructeur
Rôle
Button()
Button(String)
Permet de préciser le libellé du bouton
Exemple ( code java 1.1 ) :
Button bouton = new Button();
bouton.setLabel("bouton");
// ou Button bouton = new Button("bouton");
Le libellé du bouton peut être modifié dynamiquement grace à la méthode setLabel() :
Exemple ( code java 1.1 ) :
bouton.setLabel("nouveau libellé");
Développons en Java
116

10.1.3. Les panneaux
Les panneaux sont des conteneurs qui permettent de rassembler des composants et de les positionner grace à un
gestionnaire de présentation. Il faut utiliser un objet de la classe .Panel.
Par défaut le gestionnaire de présentation d'un panel est de type FlowLayout.
Constructeur
Role
Créer un panneau avec un gestionnaire de présentation de type
Panel()
FlowLayout
Panel(LayoutManager)
Créer un panneau avec le gestionnaire précisé en paramètre
Exemple ( code java 1.1 ) :
Panel p = new Panel();
L'ajout d'un composant au panel se fait grace à la méthode add().
Exemple ( code java 1.1 ) :
p.add(new Button("bouton");
10.1.4. Les listes déroulantes (combobox)
Il faut utiliser un objet de la classe .Choice
Cette classe ne possède qu'un seul constructeur qui ne possèdent pas de paramètres.
Exemple ( code java 1.1 ) :
Choice maCombo = new Choice();
Les méthodes add() et addItem() permettent d'ajouter des éléments à la combo.
Exemple ( code java 1.1 ) :
maCombo.addItem("element 1");
// ou ("element 2");
Plusieurs méthodes permettent la gestion des sélections :
Méthodes
Role
Deprecated
void select( int );
sélectionner un élément par son indice
: le premier élément correspond à
l'indice 0.
Une exception
IllegalArgumentException est levée si
l'indice ne correspond pas à un
Développons en Java
117

élément.
Exemple ( code java 1.1 ) :
maCombo.select(0);
sélectionner un élément par son
contenu
Aucune exception est levée si la chaine
de caractères ne correspond à aucun
élément : l'élément sélectionné ne
change pas.
void select( String);
Exemple ( code java 1.1 ) :
maCombo.select("element 1");
déterminer le nombre d'élément de la
liste. La méthode countItems() permet
d'obtenir le nombre d'éléments de la
il faut utiliser getItemCount() à la place
combo.
int countItems( );
Exemple ( code java 1.1 ) :
Exemple ( code java 1.1 ) :
int n;
int n;
n=maCombo.countItems();
n=maCombo.getItemCount();
lire le contenu de l'élément d'indice n
Exemple ( code java 1.1 ) :
String getItem( int );
String c = new String( );
c = maCombo.getItem(n);
déterminer le contenu de l'élément
sélectionné
Exemple ( code java 1.1 ) :
String getSelectedItem();
String s = new String( );
s = maCombo.getSelectedItem();
déterminer l'index de l'élément
selectionné
Exemple ( code java 1.1 ) :
int getSelectedIndex( );
int n;
n=maCombo.getSelectedIndex();
Développons en Java
118

10.1.5. La classe TextComponent
La classe TextComponent est la classe des mères des classes qui permettent l'édition de texte : TextArea et TextField.
Elle définit un certain nombre de méthodes dont ces classes héritent.
Méthodes
Role
String getSelectedText( );
Renvoie le texte sélectionné
int getSelectionStart( );
Renvoie la position de début de sélection
int getSelectionEnd( );
Renvoie la position de fin de sélection
String getText( );
Renvoie le texte contenu dans l'objet
boolean isEditable( );
Retourne un booleen indiquant si le texte est modifiable
void select(int start, int end );
Sélection des caractères situés entre start et end
void selectAll( );
Sélection de tout le texte
void setEditable(boolean b);
Autoriser ou interdire la modification du texte
void setText(String s );
Définir un nouveau texte
10.1.6. Les champs de texte
Il faut déclarer un objet de la classe .TextField
Il existe plusieurs constructeurs :
Constructeurs
Role
TextField();
TextField( int );
prédetermination du nombre de caractères à saisir
TextField( String );
avec texte par défaut
TextField( String, int );
avec texte par défaut et nombre de caractères à saisir
Cette classe possède quelques méthodes utiles :
Méthodes
Role
Deprecated
lecture de la chaine saisie
Exemple ( code java 1.1 ) :
String getText( )
String saisie = new String();
saisie = tf.getText( );
int getColumns( )
lecture du nombre de caractères predéfini
Exemple ( code java 1.1 ) :
int i;
Développons en Java
119

i = tf.getColumns( );
pour la saisie d'un mot de passe : remplace
chaque caractère saisi par celui fourni en
il faut utiliser la méthode
paramètre
setEchoChar()
void setEchoCharacter()
Exemple ( code java 1.1 ) :
Exemple ( code java 1.1 ) :
tf.setEchoCharacter('*');
TextField tf = new TextField(10);
tf.setEchoChar('*');
10.1.7. Les zones de texte multilignes
Il faut déclarer un objet de la classe .TextArea
Il existe plusieurs constructeurs :
Constructeur
Role
TextArea()
TextArea( int, int )
avec prédetermination du nombre de lignes et de colonnes
TextArea( String )
avec texte par défaut
TextArea( String, int, int )
avec texte par défaut et taille
Les principales méthodes sont :
Méthodes
Role
Deprecated
lecture du contenu intégral de la zone de
texte
Exemple ( code java 1.1 ) :
String getText()
String contenu = new String;
contenu = ta.getText( );
lecture de la portion de texte sélectionnée
Exemple ( code java 1.1 ) :
String getSelectedText( )
String contenu = new String;
contenu = ta.getSelectedText( );
int getRows()
détermination du nombre de lignes
Exemple ( code java 1.1 ) :
int n;
Développons en Java
120

n = ta.getRows( );
détermination du nombre de colonnes
Exemple ( code java 1.1 ) :
int getColumns( )
int n;
n = ta.getColumns( );
Il faut utiliser la méthode insert()
insertion de la chaine à la position fournie
Exemple ( code java 1.1 ) :
void insertText(String, int)
Exemple ( code java 1.1 ) :
String text = 
new String(«texte inséré»);
String text = new
int n =10;
String(«texte inséré»);
ta.insertText(text,n);
int n =10;
ta.insert(text,n);
Autoriser la modification
Exemple ( code java 1.1 ) :
void setEditable(boolean)
ta.setEditable(False); 
//texte non modifiable
Ajouter le texte transmis au texte existant
Exemple ( code java 1.1 ) :
Il faut utiliser la méthode
void appendText(String)
append()
ta.appendTexte(String text);
Remplacer par text le texte entre les
positions start et end
il faut utiliser la méthode
void replaceText(String, int,
Exemple ( code java 1.1 ) :
replaceRange()
int)
ta.replaceText(text, 10, 20);
10.1.8. Les listes
Il faut déclarer un objet de la classe .
Il existe plusieurs constructeurs :
Constructeur
Role
List( )
Développons en Java
121

List( int )
Permet de préciser le nombre de lignes affichées
Permet de préciser le nombre de lignes affichées et l'indicateur
List( int, boolean )
de sélection multiple
Les principales méthodes sont :
Méthodes
Role
Deprecated
ajouter un élément
Exemple ( code java 1.1 ) :
il faut utiliser la
void addItem(String)
méthode add()
li.addItem("nouvel element"); 
// a jout en fin de liste
insérer un élément à un certain emplacement :
le premier element est en position 0
il faut utiliser la
void addItem(String, int)
Exemple ( code java 1.1 ) :
méthode add()
li.addItem("ajout ligne",2);
retirer un élément de la liste
Exemple ( code java 1.1 ) :
il faut utiliser la méthode
void delItem(int)
remove()
li.delItem(0); 
// supprime le premier element
supprimer plusieurs éléments consécutifs entre
les deux indices
cette méthode est
void delItems(int, int)
Exemple ( code java 1.1 ) :
deprecated
li.delItems(1, 3); 
effacement complet du contenu de la liste
Exemple ( code java 1.1 ) :
il faut utiliser la
void clear()
méthode removeAll()
li.clear( );
remplacer un élément
Exemple ( code java 1.1 ) :
void replaceItem(String, int)
li.replaceItem(
"ligne remplacee", 1);
Développons en Java
122

nombre d'élément de la liste
Exemple ( code java 1.1 ) :
il faut utiliser la méthode
int countItems()
getItemCount()
int n;
n = li.countItems( );
nombre de ligne de la liste
Exemple ( code java 1.1 ) :
int getRows()
int n;
n = li.getRows( );
contenu d'un élément
Exemple ( code java 1.1 ) :
String getItem(int)
String text = new String( );
text = li.getItem(1);
sélectionner un élément
Exemple ( code java 1.1 ) :
void select(int)
li.select(0);
déterminer si la sélection multiple est
autorisée
il faut utiliser la méthode
setMultipleSelections(boolean)
Exemple ( code java 1.1 ) :
setMultipleMode()
li.setMultipleSelections(true);
désélectionner un élément
Exemple ( code java 1.1 ) :
void deselect(int)
li.deselect(0);
déterminer l'élément sélectionné en cas de
selection simple : renvoi l'indice ou ?1 si
aucun element n est selectionne
int getSelectedIndex( )
Exemple ( code java 1.1 ) :
int i;
i = li.getSelectedIndex();
Développons en Java
123

déterminer les éléments sélectionnées en cas
de sélection multiple
int[] getSelectedIndexes( )
Exemple ( code java 1.1 ) :
int i[]=li.getSelectedIndexes();
déterminer le contenu en cas de sélection
simple : renvoi le texte ou null si pas de
selection
String getSelectedItem( )
Exemple ( code java 1.1 ) :
String texte = new String( );
texte = li.getSelectedItem( ); 
déterminer les contenus des éléments
sélectionnés en cas de sélection multiple :
renvoi les textes sélectionnées ou null si pas
de sélection
Exemple ( code java 1.1 ) :
String[] getSelectedItems()
String texte[ ] = 
li.getSelectedItems(); 
for (i = 0 ; i < 
texte.length(); i++) 
  .println(texte[i]);
déterminer si un élément est sélectionné
Exemple ( code java 1.1 ) :
il faut utiliser la méthode
boolean isSelected(int)
isIndexSelect()
boolean selection;
selection = li.isSelected(0);
renvoie l'index de l'entrée en haut de la liste
Exemple ( code java 1.1 ) :
int getVisibleIndex()
int top = li.getVisibleIndex();
assure que l'élement précisé sera visible
Exemple ( code java 1.1 ) :
void makeVisible(int)
li.makeVisible(10);
Développons en Java
124

Exemple ( code java 1.1 ) : une liste de 5 éléments avec sélection multiple
import .*;  
class TestList {  
  static public void main (String arg [ ]) {  
    Frame frame = new Frame("Une liste");  
    List list = new List(5,true);  
    ("element 0");  
    ("element 1");  
    ("element 2");  
    ("element 3");  
    ("element 4");  
    (List);  
    ();  
    ();  
  }  
}
10.1.9. Les cases à cocher
Il faut déclarer un objet de la classe .Checkbox
Il existe plusieurs constructeurs :
Constructeur
Role
Checkbox( )
Checkbox( String)
avec une étiquette
Checkbox( String,boolean)
avec une étiquette et un état
Checkbox(String,CheckboxGroup, boolean)
avec une étiquette, dans un groupe de cases à cocher et un état
Les principales méthodes sont :
Méthodes
Role
modifier l'étiquette
Exemple ( code java 1.1 ) :
void setLabel(String)
cb.setLabel( "libelle de la case : " );
fixer l'état
Exemple ( code java 1.1 ) :
void setState( boolean )
cb.setState( true );
boolean getState( )
consulter l'état de la case
Exemple ( code java 1.1 ) :
Développons en Java
125

boolean etat;
etat = cb.getState( );
lire l'étiquette de la case
Exemple ( code java 1.1 ) :
String getLabel( )
String commentaire = new String( );
commentaire = cb.getLabel( );
10.1.10. Les boutons radio
Déclarer un objet de la classe .CheckboxGroup
Exemple ( code java 1.1 ) :
CheckboxGroup rb;
Checkbox cb1 = new Checkbox(« etiquette 1 », rb, etat1_boolean);
Checkbox cb2 = new Checkbox(« etiquette 2 », rb, etat1_boolean);
Checkbox cb3 = new Checkbox(« etiquette 3 », rb, etat1_boolean);
Les principales méthodes sont :
Méthodes
Role
Deprecated
retourne l'objet Checkbox
il faut utiliser la méthode
Checkbox getCurrent()
correspondant à la réponse
getSelectedCheckbox()
sélectionnée
il faut utiliser la méthode
Coche le bouton radio passé en
void setCurrent(Checkbox)
setSelectedCheckbox()
paramètre
10.1.11. Les barres de défilement
Il faut déclarer un objet de la classe .Scrollbar
Il existe plusieurs constructeurs :
Constructeur
Role
Scrollbar( )
Scrollbar(orientation)
Scrollbar( orientation, valeur_initiale, visible,
min, max )
Développons en Java
126

orientation : Scrollbar.VERTICALE ou Scrollbar.HORIZONTAL
valeur_initiale : position du curseur à la création
visible : taille de la partie visible de la zone défilante
min : valeur minimale associée à la barre
max : valeur maximale associée à la barre
Les principales méthodes sont :
Méthodes
Role
Deprecated
maj des parametres de la barre
Exemple ( code java 1.1 ) :
sb.setValues(int,int,int,int )
sb.setValues(
valeur, visible,
minimum, maximum );
modifer la valeur courante
Exemple ( code java 1.1 ) :
void setValue(int)
sb.setValue(10);
lecture du maximum
Exemple ( code java 1.1 ) :
int getMaximum( );
int max = 
sb.getMaximum( );
lecture du minimum
Exemple ( code java 1.1 ) :
int getMinimum( );
int min = 
sb.getMinimum( );
lecture de l'orientation
Exemple ( code java 1.1 ) :
int getOrientation( )
int o = 
sb.getOrientation( );
int getValue( );
lecture de la valeure courante
Développons en Java
127

Exemple ( code java 1.1 ) :
int valeur = 
sb.getValue( );
il faut utiliser la méthode
détermine la valeur à ajouter ou à oter quand
void setLineIncrement( int );
setUnitIncrement()
l'utilisateur clique sur une flèche de défilement
il faut utiliser la méthode
détermine la valeur à ajouter ou à oter quand
int setPageIncrement( );
setBlockIncrement()
l'utilisateur clique sur le conteneur
10.1.12. La classe Canvas
C'est un composant sans fonction particulière : il est utile pour créer des composants graphiques personnalisés.
Il est nécessaire d'étendre la classe Canvas pour en redéfinir la méthode Paint().
syntaxe : Cancas can = new Canvas( );
Exemple ( code java 1.1 ) :
import .*;
public class MonCanvas extends Canvas {
   public void paint(Graphics g) {
      g.setColor(Color.black);
      g.fillRect(10, 10, 100,50);
      g.setColor(Color.green);
      g.fillOval(40, 40, 10,10);
   }
}
import java.applet.*;
import .*;
public class AppletButton extends Applet {
   MonCanvas mc = new MonCanvas();
   public void paint(Graphics g) {
      super.paint(g);
      mc.paint(g);
   }
}
10.2. La classe Component
Les contrôles fenêtrés descendent plus ou moins directement de la classe AWT Component.
Cette classe contient de nombreuse méthodes :
Développons en Java
128

Méthodes
Role
Deprecated
utiliser la méthode
renvoie la position actuelle et la taille des
Rectangle bounds()
getBounds().
composants
utiliser la méthode
void disable()
désactive les composants
setEnabled(false).
utiliser la méthode
void enable()
active les composants
setEnabled(true).
utiliser la méthode
active ou désactive le composant selon la
void enable(boolean)
setEnabled(boolean).
valeur du paramètre
Color getBackGround()
renvoie la couleur actuelle d'arrière plan
renvoie la fonte utilisée pour afficher les
Font getFont()
caractères
Color getForeGround()
renvoie la couleur de premier plan
Graphics getGraphics()
renvoie le contexte graphique
renvoie le conteneur ( composant de niveau
Container getParent()
supérieure )
utiliser la méthode
void hide()
masque l'objet
setVisible().
indique si la coordonnée écran absolue se
utiliser la méthode contains().
boolean inside(int x, int y)
trouve dans l'objet
boolean isEnabled()
indique si l'objet est actif
boolean isShowing()
indique si l'objet est visible
indique si l'objet est visible lorque sont
boolean isVisible()
conteneur est visible
boolean isShowing()
indique si une partie de l'objet est visible
repositionne l'objet en fonction du Layout
utiliser la méthode doLayout().
void layout()
Manager courant
utiliser la méthode
Component locate(int x, int
retourne le composant situé à cet endroit
getComponentAt().
y)
Développons en Java
129

utiliser la méthode
Point location()
retourne l'origine du composant
getLocation().
utiliser la méthode
déplace les composants vers la position
void move(int x, int y)
setLocation().
spécifiée
void paint(Graphics);
dessine le composant
dessine le composant et ceux qui sont
void paintAll(Graphics)
contenus en lui
redessine le composant pat appel à la méthode
void repaint()
update()
void requestFocus();
demande le focus
utiliser la méthode
void reshape(int x, inty, int
modifie la position et la taille (unité : points
setBounds().
w, int h)
écran)
utiliser la méthode setSize().
void resize(int w, int h)
modifie la taille (unité : points écran)
void setBackground(Color)
définie la couleur d'arrière plan
void setFont(Font)
définie la police
void setForeground(Color)
définie la couleur de premier plan
utiliser la méthode
void show()
affiche le composant
setVisible(True).
utiliser la méthode getSize().
Dimension size()
détermine la taille actuelle
10.3. Les conteneurs
Les conteneurs sont des objets graphiques qui peuvent contenir d'autres objets graphiques, incluant éventuellement des
conteneurs. Ils héritent de la classe Container.
Un composant graphique doit toujours être incorporer dans un conteneur :
Conteneur
Role
Panel
conteneur sans fenetre propre. Utile pour ordonner les controles
fenêtre principale sans cadre ni menu. Les objets descendants de cette classe
Window
peuvent servir à implémenter des menus
Dialog (descendant de Window)
réaliser des boîtes de dialogue simples
Développons en Java
130

Frame (descendant de Window)
classe de fenêtre completement fonctionnelle
pas de menu. Pas de boîte de dialogue sans être incorporée dans une classe
Applet (descendant de Panel)
Frame.
L'insertion de composant dans un conteneur se fait grace à la méthode add(Component) de la classe Container.
Exemple ( code java 1.1 ) :
Panel p = new Panel();
Button b1 = new button(« premier »);
p.add(b1);
Button b2;
p.add(b2 = new Button (« Deuxième »);
p.add(new Button(«Troisième »);
10.3.1. Le conteneur Panel
C'est essentiellement un objet de rangement pour d'autres composants.
La classe Panel possède deux constructeurs :
Constructeur
Role
Panel()
Panel(LayoutManager)
Permet de préciser un layout manager
Exemple ( code java 1.1 ) :
Panel p = new Panel( );
Button b = new Button(« bouton »);
p.add( b);
10.3.2. Le conteneur Window
La classe Window contient plusieurs méthodes dont voici les plus utiles :
Méthodes
Role
Calculer la taille et la position de tous les controles de la fenetre. La méthode pack() agit en étroite
collaboration avec le layout manager et permet à chaque contrôle de garder, dans un premier temps sa
void
taille optimale. Une fois que tous les contrôles ont leur taille optimale, pack() utilise ces informations pour
pack()
positionner les contrôles. pack() calcule ensuite la taille de la fenêtre. L'appel à pack() doit se faire à
l'intérieur du constructeur de fenêtre après insertion de tous les contrôles.
void
Afficher la fenetre
show()
void
Liberer les ressources allouée à la fenetre
dispose()
Développons en Java
131

10.3.3. Le conteneur Frame
Permet de créer des fenêtre d'encadrement. Il hérite de Window qui ne s'occupe que de l'ouverture de la fenêtre. Window
ne connait pas les menus ni les bordures qui sont gérés par Frame. Dans une applet, elle n'apparait pas dans le navigateur
mais comme un fenêtre indépendante.
Il existe deux constructeurs :
Constructeur
Role
Frame()
Exemple : Frame f = new Frame( );
Precise le nom de la fenetre
Frame(String)
Exemple : Frame f = new Frame(« titre »);
Les principales méthodes sont :
Méthodes
Role
Deprecated
changer le pointeur de la souris dans la fenetre
utiliser la méthode
setCursor(int)
Exemple :
setCursor(Cursor).
f.setCursor(Frame.CROSSHAIR_CURSOR);
utiliser la méthode
int getCursorType()
déterminer la forme actuelle du curseur
getCursor().
Image getIconImage()
déterminer l'icone actuelle de la fenetre
MenuBar getMenuBar()
déterminer la barre de menus actuelle
String getTitle()
déterminer le titre de la fenêtre
boolean isResizeable()
déteriner si la taille est modifiable
void
Supprimer un menu
remove(MenuComponent)
void setIconImage(Image);
définir l'icone de la fenêtre
void setMenuBar(MenuBar)
Définir la barre de menu
void setResizeable(boolean)
définir si la taille peut être modifiée
void SetTitle(String)
définir le titre de la fenêtre
Exemple ( code java 1.1 ) :
import java.applet.*;
import .*;
public class AppletFrame extends Applet {
   Frame f;
   public void init() {
      ();
      // insert code to initialize the applet here
      f = new Frame("titre");
      f.add(new Label("hello "));
      f.show();
Développons en Java
132

      f.setSize(300, 100);
   }
}
Le message « Warning : Applet window » est impossible à enlever dans la fenetre : cela permet d'éviter la création d'une
applet qui demande un mot de passe.
Le gestionnaire de mise en page par défaut d'une Frame est BorderLayout (FlowLayout pour une applet).
Exemple ( code java 1.1 ) : Exemple : construction d'une fenêtre simple
import .*;
public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle(" Titre de la Fenetre ");
      setSize(300, 150);
      show(); // affiche la fenetre
   }
   public static void main(String[] args) {
      new MaFrame();
   }
}
10.3.4. Le conteneur Dialog
La classe Dialog hérite de la classe Window.
Une boîte de dialogue doit dérivée de la Classe Dialog de package .
Un objet de la classe Dialog doit dépendre d'un objet de la classe Frame.
Exemple ( code java 1.1 ) :
import .*;
import .event.*;
public class Apropos extends Dialog {
   public APropos(Frame parent) {
      super(parent, "A propos ", true);
      addWindowListener(new
      AProposListener(this));
      setSize(300, 300);
      setResizable(False);
   }
}
class AProposListener extends WindowAdapter {
   Dialog dialogue;
   public AProposListener(Dialog dialogue) {
      this.dialogue = dialog;
Développons en Java
133

   }
   public void windowClosing(WindowEvent e) {
      dialogue.dispose();
   }
}
L'appel du constructeur Dialog(Frame, String, Boolean) permet de créer une instance avec comme paramètres : la fenetre
à laquelle appartient la boîte de dialogue, le titre de la boîte, le caractère modale de la boîte.
La méthode dispose() de la classe Dialog ferme la boîte et libère les ressources associées. Il ne faut pas associer cette
action à la méthode windowClosed() car dispose provoque l'appel de windowClosed ce qui entrainerait un appel récursif
infinie.
10.4. Les menus
Il faut insérer les menus dans des objets de la classe Frame (fenêtre d'encadrement). Il n'est donc pas possible d'insérer
directement des menus dans une applet.
Il faut créer une barre de menu et l'affecter à la fenêtre d'encadrement. Il faut créer ensuite créer les entrées de chaque
menu et les rattacher à la barre. Ajouter ensuite les éléments à chacun des menus.
Exemple ( code java 1.1 ) :
import .*;
public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle(" Titre de la Fenetre ");
      setSize(300, 150);
      MenuBar mb = new MenuBar();
      setMenuBar(mb);
      Menu m = new Menu(" un menu ");
      (m);
      m.add(new MenuItem(" 1er element "));
      m.add(new MenuItem(" 2eme element "));
      Menu m2 = new Menu(" sous menu ");
      CheckboxMenuItem cbm1 = new CheckboxMenuItem(" menu item 1.3.1 ");
      (cbm1);
      cbm1.setState(true);
      CheckboxMenuItem cbm2 = new CheckboxMenuItem(" menu item 1.3.2 ");
      (cbm2);
      m.add(m2);
      pack();
      show(); // affiche la fenetre
   }
   public static void main(String[] args) {
      new MaFrame();
   }
}
Développons en Java
134

Exemple ( code java 1.1 ) : création d'une classe qui définit un menu
import .*;
public class MenuFenetre extends .MenuBar {
   public MenuItem menuQuitter, menuNouveau, menuApropos;
   public MenuFenetre() {
      Menu menuFichier = new Menu(" Fichier ");
      menuNouveau = new MenuItem(" Nouveau ");
      menuQuitter = new MenuItem(" Quitter ");
      (menuNouveau);
      menuFichier.addSeparator();
      (menuQuitter);
      Menu menuAide = new Menu(" Aide ");
      menuApropos = new MenuItem(" A propos ");
      (menuApropos);
      add(menuFichier);
      setHelpMenu(menuAide);
   }
}
La méthode setHelpMenu() confère sous certaines plateformes un comportement particulier à ce menu.
La méthode setMenuBar() de la classe Frame prend en paramètre une instance de la classe MenuBar. Cette instance peut
être directement une instance de la classe MenuBar qui aura été modifiée grace aux méthodes add() ou alors une classe
dérivée de MenuBar qui est adaptée aux besoins (voir Exemple);
Exemple ( code java 1.1 ) :
import .*;
public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle(" Titre de la Fenetre ");
      setSize(300, 150);
      MenuFenetre mf = new
      MenuFenetre();
      setMenuBar(mf);
      pack();
      show(); // affiche la fenetre
   }
   public static void main(String[] args) {
      new MaFrame();
Développons en Java
135

   }
}
10.4.1. Les méthodes de la classe MenuBar
Méthodes
Role
Deprecated
void add(Menu)
ajouter un menu dans la barre
utiliser la méthode
int countMenus()
renvoie le nombre de menus
getMenuCount().
Menu getMenu(int pos)
renvoie le menu à la position spécifiée
void remove(int pos)
supprimer le menu à la position spécifiée
void remove(Menu)
supprimer le menu de la barre de menu
10.4.2. Les méthodes de la classe Menu
Méthodes
Role
Deprecated
MenuItem add(MenuItem)
ajouter une option dans le menu
void add(String)
void addSeparator()
ajouter un trait de séparation dans le menu
utiliser la méthode
int countItems()
renvoie le nombre d'options du menu
getItemCount().
déterminer l'option du menu à la position
MenuItem getItem(int pos)
spécifiée
void remove(MenuItem mi)
supprimer la commande spécifiée
void remove(int pos)
supprimer la commande à la position spécifiée
10.4.3. Les méthodes de la classe MenuItem
Méthodes
Role
Deprecated
utiliser la méthode
void disable()
désactiver l'élément
setEnabled(false).
Développons en Java
136

utiliser la méthode
void enable()
activer l'élément
setEnabled(true).
utiliser la méthode
désactiver ou activer l'élément en fonction du
void enable(boolean cond)
setEnabled(boolean).
paramètre
String getLabel()
Renvoie le texte de l'élément
boolean isEnabled()
renvoie l'état de l'élément (actif / inactif)
void setLabel(String text)
définir une nouveau texte pour la commande
10.4.4. Les méthodes de la classe CheckboxMenuItem
Méthodes
Role
boolean getState()
renvoie l'état d'activation de l'élément
Void setState(boolean)
définir l'état d'activation de l'élément
Développons en Java
137

11. La création d'interface graphique avec AWT
Ce chapitre contient plusieurs sections :
Le dimensionnement des composants
• 
Le positionnement des composants
• 
Mise en page par flot (FlowLayout)

Mise en page bordure (BorderLayout)

Mise en page de type carte (CardLayout)

Mise en page GridLayout

Mise en page GridBagLayout

La création de nouveaux composants à partir de Panel
• 
Activer ou desactiver des composants
• 
Afficher une image dans une application.
• 
11.1. Le dimensionnement des composants
En principe, il est automatique grace au LayoutManager. Pour donner à un composant une taille donnée, il faut redéfinir
la méthode getPreferedSize de la classe Component.
Exemple ( code java 1.1 ) :
import .*;
public class MonBouton extends Button {
   public Dimension getPreferredSize() {
      return new Dimension(800, 250);
   }
}
Le méthode getPreferedSize() indique la taille souhaitée mais pas celle imposée. En fonction du Layout Manager, le
composant pourra ou non imposer sa taille.
Layout
Hauteur
Largeur
Sans Layout
oui
oui
FlowLayout
oui
oui
BorderLayout(East, West)
non
oui
BorderLayout(North, South)
oui
non
BorderLayout(Center)
non
non
Développons en Java
138

GridLayout
non
non
Cette méthode oblige à sous classer tous les composants.
Une autre façon de faire est de se passer des Layout et de placer les composants à la main en indiquant leurs coordonnées
et leurs dimensions.
Pour supprimer le Layout par défaut d'une classe, il faut appeler la méthode setLayout() avec comme paramètre null.
Trois méthodes de la classe Component permettent de positionner des composants :
setBounds(int x, int y, int largeur, int hauteur)
• 
setLocation(int x , int y)
• 
setSize(int largeur, int hauteur)
• 
Ces méthodes permettent de placer un composant à la position (x,y) par rapport au conteneur dans lequel il est inclus et
d'indiquer sa largeur et sa hauteur.
Toutefois, les Layout Manager constituent un des facteurs importants de la portabilité des interfaces graphiques
notamment en gérant la disposition et le placement des composants après redimentionnement du conteneur.
11.2. Le positionnement des composants
Lorsqu'on intègre un composant graphique dans un conteneur, il n'est pas nécessaire de préciser son emplacement car il
est déterminé de façon automatique : la mise en forme est dynamique. On peut influencer cette mise en page en utilisant
un gestionnaire de mise en page (Layout Manager) qui définit la position de chaque composant inséré. Dans ce cas, la
position spécifiée est relative par rapport aux autres composants.
Chaque layout manager implémente l'interface .LayoutManager.
Il est possible d'utiliser plusieurs gestionnaires de mise en forme pour définir la présentation des composants. Par défaut,
c'est la classe FlowLayout qui est utilisée pour la classe Panel et la classe BorderLayout pour Frame et Dialog.
Pour affecter une nouvelle mise en page, il faut utiliser la méthode setLayout() de la classe Container.
Exemple ( code java 1.1 ) :
  Panel p = new Panel();
   FlowLayout fl = new GridLayout(5,5);
   p.setLayout(fl);
   // ou p.setLayout( new GridLayout(5,5));
Les layout manager ont 3 avantages :
l'aménagement des composants graphiques est délégué aux layout manager (il est inutile d'utiliser les
• 
coordonnées absolues)
en cas de redimensionnement de la fenêtre, les contrôles sont automatiquement agrandis ou réduits
• 
ils permettent une indépendance vis à vis des plateformes.
• 
Pour créer un espace entre les composants et le bord de leur conteneur, il faut rédifinir la méthode getInsets() d'un
conteneur : cette méthode est héritée de la classe Container.
Exemple ( code java 1.1 ) :
Développons en Java
139

public Insets getInsets() {
   Insets normal = super.getInsets();
   return new Insets( + 10, + 10,
   normal.bottom + 10, normal.right + 10);
}
Cette Exemple permet de laisser 10 pixels en plus entre chaque bords du conteneur.
11.2.1. La mise en page par flot (FlowLayout)
La classe FlowLayout (mise en page flot) place les composants ligne par ligne de gauche à droite. Chaque ligne est
complétée progressivement jusqu'à être remplie, puis passe à la suivante. Chaque ligne est centrée par défaut. C'est la
mise en page par défaut des applets.
Il existe plusieurs constructeurs :
Constructeur
Role
FlowLayout( );
Permet de préciser l'alignement des composants dans le conteneur (CENTER,
FlowLayout( int align);
LEFT, RIGHT ... ). Par défaut, align vaut CENTER
FlowLayout( int, int hgap, int
Permet de préciser et l'alignement horizontal et vertival dont la valeur par défaut
vgap);
est 5.
Exemple ( code java 1.1 ) :
import .*;
public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle(" Titre de la Fenetre ");
      setSize(300, 150);
      setLayout(new FlowLayout());
      add(new Button("Bouton 1"));
      add(new Button("Bouton 2"));
      add(new Button("Bouton 3"));
      pack();
      show(); // affiche la fenetre
   }
   public static void main(String[] args) {
      new MaFrame();
   }
}
Développons en Java
140

Chaque applet possède une mise en page flot implicitement initialisée à FlowLayout(FloawLayout.CENTER,5,5).
FlowLayout utilise les dimensions de son conteneur comme seul prinicipe de mise en forme des composants. Si les
dimensions du conteneurs changent, le positionnement des composants est recalculé.
Exemple : la fenêtre précédente est simplement redimensionnée
11.2.2. La mise en page bordure (BorderLayout)
Avec ce Layout Manager, la disposition des composants est commandée par une mise en page en bordure qui découpe la
surface en cinq zones : North, South, East, West, Center. On peut librement utiliser une ou plusieurs zones.
BorderLayout consacre tout l'espace du conteneur aux composants. Le composant du milieu dispose de la place inutilisée
par les autres composants.
Il existe plusieurrs constructeurs :
Constructeur
Role
BorderLayout( )
BorderLayout (int hgap,int vgap)
Permet de préciser l'espacement horizontal et vertical des composants.
Exemple ( code java 1.1 ) :
import .*;
public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle("
      Titre de la Fenetre ");
      setSize(300, 150);
      setLayout(new
      BorderLayout());
      add("North", new Button(" bouton haut "));
      add("South", new Button(" bouton bas "));
      add("West",  new Button(" bouton gauche "));
      add("East",  new Button(" bouton droite "));
      add("Center", new Button(" bouton milieu "));
      pack();
      show(); // affiche la fenetre
   }
   public static void
      main(String[] args) {
      new MaFrame();
   }
}
Développons en Java
141

Il est possible d'utiliser deux méthodes add surchargées de la classe Container : add(String, Component) ou le premier
paramètre précise l'orientation du composants ou add(Component, Objet) ou le second paramètre précise la position sous
forme de constante définie dans la classe BorderLayout.
Exemple ( code java 1.1 ) :
import .*;
public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle(" Titre de la Fenetre ");
      setSize(300, 150);
      setLayout(new BorderLayout());
      add(new Button("North"), BorderLayout.NORTH);
      add(new Button("South"), BorderLayout.SOUTH);
      pack();
      show(); // affiche la fenetre
   }
   public static void main(String[] args) {
      new MaFrame();
   }
}
11.2.3. La mise en page de type carte (CardLayout)
Aide à construire des boîtes de dialogue composée de plusieurs onglets. Un onglet se compose généralement de plusieurs
contrôles : on insère des panneaux dans la fenêtre utilisée par le CardLayout Manager. Chaque panneau correspond à un
onglet de boîte de dialogue et contient plusieurs contrôles. Par défaut, c'est le premier onglet qui est affiché.
Ce layout possède deux constructeurs :
Constructeurs
Role
CardLayout()
CardLayout(int, int)
Permet de préciser l'espace horizontal et vertical du tour du composant
Exemple ( code java 1.1 ) :
Développons en Java
142

import .*;
public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle("Titre de la Fenetre ");
      setSize(300,150);
      CardLayout cl = new CardLayout();
      setLayout(cl);
      //création d'un panneau contenant les controles d'un onglet
      Panel p = new Panel();
      //ajouter les composants au panel
      p.add(new Button("Bouton 1 panneau 1"));
      p.add(new Button("Bouton 2 panneau 1"));
      //inclure le panneau dans la fentre sous le nom "Page1"
      // ce nom est utilisé par show()
      add("Page1",p);
      //déclaration et insertion de l'onglet suivant
      p = new Panel();
      p.add(new Button("Bouton 1 panneau 2"));
      add("Page2", p);
      // affiche la fenetre      
      pack();
      show();
   }
   public static void main(String[] args) {
      new MaFrame();
   }
}
Lors de l'insertion d'un onglet, un nom doit lui être attribué. Les fonctions nécessaires pour afficher un onglet de boîte de
dialogue ne sont pas fournies par les méthodes du conteneur, mais seulement par le Layout Manager. Il est nécessaire de
sauvegarder temporairement le Layout Manager dans une variable ou déterminer le gestionnaire en cours par un appel à
getLayout(). Pour appeler un onglet donné, il faut utiliser la méthode show() du CardLayout Manager.
Exemple ( code java 1.1 ) :
((CardLayout)getLayout()).show(this, "Page2");
Les méthodes first(), last(), next() et previous() servent à parcourir les onglets de boîte de dialogue :
Exemple ( code java 1.1 ) :
((CardLayout)getLayout()).first(this);
Développons en Java
143

11.2.4. La mise en page GridLayout
Ce Layout Manager établit un réseau de cellule identiques qui forment une sorte de quadrillage invisible : les composants
sont organisés en lignes et en colonnes. Les éléments insérés dans la grille ont tous la même taille. Les cellules du
quadrillage se remplissent de droite à gauche ou de haut en bas.
Il existe plusieurs constructeurs :
Constructeur
Role
Les deux premiers entiers spécifient le nombre de lignes ou de
GridLayout( int, int );
colonnes de la grille.
permet de préciser en plus l'espacement horizontal et vertical des
GridLayout( int, int, int, int );
composants.
Exemple ( code java 1.1 ) :
import .*;
public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle(" Titre de la Fenetre ");
      setSize(300, 150);
      setLayout(new GridLayout(2, 3));
      add(new Button("bouton 1"));
      add(new Button("bouton 2"));
      add(new Button("bouton 3"));
      add(new Button("bouton 4")); 
      add(new Button("bouton 5 tres long"));
      add(new Button("bouton 6"));
      pack();
      show(); // affiche la fenetre
   } 
   public static void main(String[] args) {
      new MaFrame();
   }
}
Attention : lorsque le nombre de ligne et de colonne est spécifié alors le nombre de colonne est
ignoré. Ainsi par Exemple GridLayout(5,4) est équivalent à GridLayout(5,0).
Exemple ( code java 1.1 ) :
import .*;
Développons en Java
144

public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle(" Titre de la Fenetre ");
      setSize(300, 150);
      setLayout(new GridLayout(2, 3));
      add(new Button("bouton 1"));
      add(new Button("bouton 2"));
      add(new Button("bouton 3"));
      add(new Button("bouton 4"));
      add(new Button("bouton 5 tres long"));
      add(new Button("bouton 6"));
      add(new Button("bouton 7"));
      add(new Button("bouton 8"));
      add(new Button("bouton 9"));
      pack();
      show(); // affiche la fenetre
   }
   public static void
      main(String[] args) {
      new MaFrame();
   }
}
11.2.5. La mise en page GridBagLayout
Ce gestionnaire (grille étendue) est le plus riche en fonctionnalités : le conteneur est divisé en cellules égales mais un
composants peut occuper plusieurs cellules de la grille et il est possible de faire une distribution dans des cellules
distinctes. Un objet de la classe GridBagConstraints permet de donner les indications de positionnement et de dimension
à l'objet GridBagLayout.
Les lignes et les colonnes prennent naissance au moment ou les controles sont ajoutés. Chaque controle est associé à un
objet de la classe GridBagConstraints qui indique l'emplacement voulu pour le contrôle.
Exemple ( code java 1.1 ) :
GridBagLayout gb1 = new GridBagLayout( );
GridBagConstraints gbc = new GridBagConstraints( );
Les variables d'instances pour manipuler l'objet GridBagLayoutConstrainst sont :
Variable
Role
Ces variables contiennent les coordonnées de l'origine de la grille. Elles permettent un
positionnement précis à une certaine position d'un composant. Par défaut elles ont la
gridx et gridy
valeur GrigBagConstraint.RELATIVE qui indique qu'un composant se range à droite du
précédent
gridwidth, gridheight
Définissent combien de cellules va occuper le composant (en hauteur et largeur). Par
défaut la valeur est 1. L'indication est relative aux autres composants de la ligne ou de la
colonne. La valeur GridBagConstraints.REMAINDER spécifie que le prochain composant
Développons en Java
145

inséré sera le dernier de la ligne ou de la colonne courante. La valeur
GridBagConstraints.RELATIVE place le composant après le dernier composant d'une
ligne ou d'une colonne.
Définit le sort d'un composant plus petit que la cellule de la grille.
conserve la taille d'origine : valeur par défaut
fill
GridBagConstraints.HORIZONTAL dilaté horizontalement
GridBagConstraints.VERTICAL dilaté verticalement dilatés
aux dimensions de la cellule
Permettent de définir l'agrandissement horizontal et vertical des composants. Ne
ipadx, ipady
fonctionne que si une dilatation est demandée par fill. La valeur par défaut est (0,0).
Lorsqu'un composant est plus petit que la cellule dans laquelle il est inséré, il peut être
positionné à l'aide de cette variable pour définir le côté par lequel le controle doit être
anchor
aligné dans la cellule. Les variables possibles sont NORTH, NORTHWEST,
NORTHEAST, SOUTH, SOUTHWEST, SOUTHEAST, WEST et EAST
weightx, weighty
Permettent de définir la répartition de l'espace en cas de changement de dimension
Exemple ( code java 1.1 ) :
import .*;
public class MaFrame extends Frame {
   public MaFrame() {
      super();
      setTitle(" Titre de la Fenetre ");
      setSize(300, 150);
      Button b1 = new Button(" bouton 1 ");
      Button b2 = new Button(" bouton 2 ");
      Button b3 = new Button(" bouton 3 ");
      GridBagLayout gb = new GridBagLayout();
      GridBagConstraints gbc = new GridBagConstraints();
      setLayout(gb);
      = ;
      gbc.weightx = 1;
      gbc.weighty = 1;
      gb.setConstraints(b1, gbc); // mise en forme des objets
      gb.setConstraints(b2, gbc);
      gb.setConstraints(b3, gbc);
      add(b1);
      add(b2);
      add(b3);
      pack();
      show(); // affiche la fenetre
   }
   public static void main(String[] args) {
      new MaFrame();
   }
}
Développons en Java
146

Cette Exemple place trois boutons l'un à coté de l'autre. Ceci permet en cas de changement de dimension du conteneur de
conserver la mise en page : la taille des composants est automatiquement ajustée.
Pour placer les 3 boutons l'un au dessus de l'autre, il faut affecter la valeur 1 à la variable gbc.gridx.
11.3. La création de nouveaux composants à partir de Panel
Il est possible de définir de nouveau composant qui hérite directement de Panel
Exemple ( code java 1.1 ) :
class PanneauClavier extends Panel {
   PanneauClavier()
   {
      setLayout(new GridLayout(4,3));
      for (int num=1; num <= 9 ; num++) add(new Button(Integer.toString(num)));
      add(new Button(«*»);
      add(new Button(«0»);
      add(new Button(«# »);
   }
}
public class demo exteds Applet {
   public void init() { add(new PanneauClavier()); }
}
11.4. Activer ou desactiver des composants
L'activation ou la désactivation d'un composant se fait grace à sa méthode setEnabled(boolean). La valeur booléenne
passée en paramètres indique l'état du composant (false : interdit l'usage du composant). Cette méthode est un moyen
d'interdire à un composant d'envoyer des évenements utilisateurs.
11.5. Afficher une image dans une application.
L'image doit préalablement être charger grace à la classe Toolkit.
La suite de ce chapitre sera développée dans une version future de ce document
Développons en Java
147

12. L'interception des actions de l'utilisateur
N'importe quel interface graphique doit interagir avec l'utilisateur et donc réagir a certains événements. Le modèle de
gestion de ces évenements à changer entre le JDK 1.0 et 1.1.
Ce chapitre traite de la capture des ces événements pour leur associer des traitements. Il contient plusieurs sections :
Intercepter les actions de l'utilisateur avec Java version 1.0
• 
Intercepter les actions de l'utilisateur avec Java version 1.1
• 
L'interface ItemListener

L'interface TextListener

L'interface MouseMotionListener

L'interface MouseListener

L'interface WindowListener

Les différentes implémentations des Listener

Résumé

12.1. Intercepter les actions de l'utilisateur avec Java version 1.0
Cette section sera développée dans une version future de ce document
12.2. Intercepter les actions de l'utilisateur avec Java version 1.1
Les événements utilisateurs sont gérés par plusieurs interfaces EventListener.
Les interfaces EventListener permettent à un composants de générer des événements utilisateurs. Une classe doit contenir
une interface auditeur pour chaque type de composant :
ActionListener : clic de souris ou enfoncement de la touche Enter
• 
ItemListener : utilisation d'une liste ou d'une case à cocher
• 
MouseMotionListener : evénément de souris
• 
WindowListener : événement de fenetre
• 
L'ajout d'une interface EventListener impose plusieurs ajouts dans le code :
Développons en Java
148

importer le groupe de classe .event
1. 
Exemple ( code java 1.1 ) :
import .event.*;
la classe doit déclarer qu'elle utilisera une ou plusieurs interfaces d'écoute
2. 
Exemple ( code java 1.1 ) :
public class AppletAction extends Applet implements ActionListener{
Pour déclarer plusieurs interfaces, il suffit de les séparer par des virgules
Exemple ( code java 1.1 ) :
public class MonApplet extends Applet implements ActionListener, MouseListener {
Appel à la méthode addXXX() pour enregistrer l'objet qui gerera les évenements XXX du composant
3. 
Il faut configurer le composant pour qu'il possède un "écouteur" pour l'événement utilisateur concerné.
Exemple ( code java 1.1 ) : création d'un bouton capable de réagir à un evénements
Button b = new Button(«boutton»);
b.addActionListener(this);
Ce code créé l'objet de la classe Button et appelle sa méthode addActionListener(). Cette méthode permet de
préciser qu'elle sera la classe qui va gérer l'évenement utilisateur de type ActionListener du bouton. Cette classe
doit impérativement implémenter l'interface de type EventListener correspondante soit dans cette exemple
ActionListener. L'instruction this indique que la classe elle même recevra et gérera l'évenement utilisateur.
L'apparition d'un évenement utilisateur généré par un composant doté d'un auditeur appelle automatiquement
une méthode, qui doit se trouver dans la classe référencée dans l'instruction qui lie l'auditeur au composant.
Dans l'exemple, cette méthode doit être située dans la même classe parce que c'est l'objet lui même qui est
spécifié avec l'instruction this. Une autre classe indépendante peut être utilisée : dans ce cas il faut préciser une
instance de cette classe en temps que paramètre.
implémenter les méthodes déclarées dans les interfaces
4. 
Chaque auditeur possède des méthodes différentes qui sont appelées pour traiter leurs évenéments. Par exemple,
l'interface ActionListener envoie des évenements à une classe nommée actionPerformed( ).
Exemple ( code java 1.1 ) :
public void actionPerformed(ActionEvent evt) {
   //insérer ici le code de la méthode 
};
Pour identifier le composant qui a généré l'evénement il faut utiliser la méthode getActionCommand() de l'objet
ActionEvent fourni en paramètre de la méthode :
Exemple ( code java 1.1 ) :
String composant = evt.getActionCommand();
getActionCommand renvoie une chaine de caractères. Si le composant est un bouton, alors il renvoie le texte du
Développons en Java
149

bouton, si le composant est une zone de saisie, c'est le texte saisie qui sera renvoyé (il faut appuyer sur "Entrer"
pour générer l'événement), etc ...
La méthode getSource() renvoie l'objet qui a généré l'événement. Cette méthode est plus sure que la précédente
Exemple ( code java 1.1 ) :
Button b = new Button(« bouton »);
...
void public actionPerformed(actionEvent evt) {
   Object source = evt.getSource();
   if (source == b) // action a effectuer
}
La méthode getSource() peut être utilisé avec tous les évenements utilisateur.
Exemple ( code java 1.1 ) : Exemple complet qui affiche le composant qui a généré l'événement
package applets;
import java.applet.*;
import .*;
import .event.*;
public class AppletAction extends Applet implements ActionListener{
   public void actionPerformed(ActionEvent evt) {
      String composant = evt.getActionCommand();
      showStatus("Action sur le composant : " + composant);
   }
   public void init() {
      ();
      Button b1 = new Button("boutton 1");
      b1.addActionListener(this);
      add(b1);
      Button b2 = new Button("boutton 2");
      b2.addActionListener(this);
      add(b2);
      Button b3 = new Button("boutton 3");
      b3.addActionListener(this);
      add(b3);
   }
}
12.2.1. L'interface ItemListener
Cette interface permet de réagir à la sélection de cases à cocher et de liste d'options. Pour qu'un composant genère des
évenements, il faut utiliser la méthode addItemListener().
Exemple ( code java 1.1 ) :
Checkbox cb = new Checkbox(« choix »,true);
cb.addItemListener(this);
Développons en Java
150

Ces évenements sont reçus par la méthode itemStateChanged() qui attend un objet de type ItemEvent en argument
Pour déterminer si une case à cocher est sélectionnée ou inactive, utiliser la méthode getStateChange() avec les
constantes ItemEvent.SELECTED ou ItemEvent.DESELECTED.
Exemple ( code java 1.1 ) :
package applets;
import java.applet.*;
import .*;
import .event.*;
public class AppletItem extends Applet implements ItemListener{
   public void init() { 
      ();
      Checkbox cb = new Checkbox("choix 1", true);
      cb.addItemListener(this);
      add(cb);
   }
   public void itemStateChanged(ItemEvent item) {
      int status = item.getStateChange();
      if (status == ItemEvent.SELECTED)
         showStatus("choix selectionne");
      else
         showStatus("choix non selectionne");
   }
}
Pour connaitre l'objet qui a généré l'événement, il faut utiliser la méthode getItem().
Pour déterminer la valeur sélectionnée dans une combo box, il faut utiliser la méthode getItem() et convertir la valeur en
chaine de caractères.
Exemple ( code java 1.1 ) :
package applets;
import java.applet.*;
import .*;
import .event.*;
public class AppletItem extends Applet implements ItemListener{
   public void init() { 
      Choice c = new Choice();
      c.add("choix 1");
      c.add("choix 2");
      c.add("choix 3");
      c.addItemListener(this);
      add(c);
}
   public void itemStateChanged(ItemEvent item) {
      Object obj = item.getItem();
      String selection = (String)obj;
      showStatus("choix : "+selection);
   }
}
Développons en Java
151

12.2.2. L'interface TextListener
Cette interface permet de réagir au modification de zone de saisie ou de texte.
La méthode addTextListener() permet à un composant de texte de générer des événements utilisateur. La méthode
TextValueChanged() reçoit les évenements.
Exemple ( code java 1.1 ) :
package applets;
import java.applet.*;
import .*;
import .event.*;
public class AppletText extends Applet implements TextListener{
   public void init() { 
      ();
      TextField t = new TextField("");
      t.addTextListener(this);
      add(t);   
   }
   public void textValueChanged(TextEvent txt) {
      Object source = txt.getSource();
      showStatus("saisi = "+((TextField)source).getText());
   }
}
12.2.3. L'interface MouseMotionListener
La méthode addMouseMotionListener() permet de gérer les évenements liés à des mouvements de souris. La méthode
mouseDragged() et mouseMoved() reçoivent les évenements.
Exemple ( code java 1.1 ) :
package applets;
import java.applet.*;
import .*;
import .event.*;
public class AppletMotion extends Applet implements MouseMotionListener{
   private int x;
   private int y;
   public void init() { 
      ();
      this.addMouseMotionListener(this);
   }
   public void mouseDragged(.event.MouseEvent e) {}
   public void mouseMoved(MouseEvent e) {
      x = e.getX();
      y = e.getY();
      repaint();
      showStatus("x = "+x+" ; y = "+y);
   }
   public void paint(Graphics g) {
      super.paint(g);
      g.drawString("x = "+x+" ; y = "+y,20,20);
   }
}
Développons en Java
152

12.2.4. L'interface MouseListener
Cette interface permet de réagir aux clics de souris. Les méthodes de cette interface sont :
public void mouseClicked(MouseEvent e);
• 
public void mousePressed(MouseEvent e);
• 
public void mouseReleased(MouseEvent e);
• 
public void mouseEntered(MouseEvent e);
• 
public void mouseExited(MouseEvent e);
• 
Exemple ( code java 1.1 ) :
package applets;
import java.applet.*;
import .*;
import .event.*;
public class AppletMouse extends Applet implements MouseListener {
   int nbClick = 0;
   public void init() {
      ();
      addMouseListener(this);
   }
   public void mouseClicked(MouseEvent e) {
      nbClick++;
      repaint();
   }
   public void mouseEntered(MouseEvent e) {}
   public void mouseExited(MouseEvent e) {}
   public void mousePressed(MouseEvent e) {}
   public void mouseReleased(MouseEvent e) {}
   public void paint(Graphics g) {
      super.paint(g);
      g.drawString("Nombre de clics : "+nbClick,10,10);
   }
}
Une classe qui implémente cette interface doit définir ces 5 méthodes. Si toutes les méthodes ne doivent pas être utiliser,
il est possible de définir une classe qui hérite de MouseAdapter. Cette classe fournit une implémentation par défaut de
l'interface MouseListener.
Exemple ( code java 1.1 ) :
class gestionClics extends MouseAdapter {
   public void mousePressed(MouseEvent e) {
      //traitement
   }
}
Dans le cas d'une classe qui hérite d'une classe Adapter, il suffit de redéfinir la ou les méthodes qui contiendront du code
pour traiter les événements concernés. Par défaut, les différentes méthodes définies dans l'Adapter ne font rien.
Cette nouvelle classe ainsi définie doit etre passée en paramètre à la méthode addMouseListener() au lieu de this qui
indiquait que la classe répondait elle même au événement.
Développons en Java
153

12.2.5. L'interface WindowListener
La méthode addWindwowListener() permet à un objet Frame de générer des événements. Les méthodes de cette interface
sont :
public void windowOpened(WindowEvent e)
• 
public void windowClosing(WindowEvent e)
• 
public void windowClosed(WindowEvent e)
• 
public void windowIconified(WindowEvent e)
• 
public void windowDeinconified(WindowEvent e)
• 
public void windowActivated(WindowEvent e)
• 
public void windowDeactivated(WindowEvent e)
• 
windowClosing est appelée lorque l'on clique sur la case système de fermeture de fenetre. windowClosed est appelé
après la fermeture de la fenetre : cette méthode n'est utile que si la fermeture de la fenetre n'entraine pas la fin de
l'application.
Exemple ( code java 1.1 ) :
package test;
import .event.*;
class GestionnaireFenetre extends WindowAdpter {
   public void windowClosing(WindowEvent e) {
      (0);
   }
}
Exemple ( code java 1.1 ) :
package test;
import .*;
import .event.*;
public class TestFrame extends Frame {
   private GestionnaireFenetre gf = new GestionnaireFenetre();
   public TestFrame(String title) {
     super(title);
     addWindowListener(gf);
   }
   public static void main(.String[] args) {
      try {
         TestFrame tf = new TestFrame("TestFrame");       
         tf.setVisible(true);
      } catch (Throwable e) {
         .println("Erreur");
         e.printStackTrace();
      }
   }
}
12.2.6. Les différentes implémentations des Listener
La mise en oeuvre des Listeners peut se faire selon différentes formes : la classe implémentant elle même l'interface, une
classe indépendante, une classe interne, une classe interne anonyme.
Développons en Java
154

12.2.6.1. Une classe implémentant elle même le listener
Exemple ( code java 1.1 ) :
package test;
import .*;
import .event.*;
public class TestFrame3 extends Frame implements WindowListener {
   public TestFrame3(String title) {
      super(title);
      this.addWindowListener(this);
   }
   public static void main(.String[] args) {
      try {
         TestFrame3 tf = new TestFrame3("testFrame3");  
         tf.setVisible(true);
      } catch (Throwable e) {
         .println("Erreur");
         e.printStackTrace();
      }
   }
   public void windowActivated(.event.WindowEvent e) {}
   public void windowClosed(.event.WindowEvent e) {}
   public void windowClosing(.event.WindowEvent e) {
      (0);
   }
   public void windowDeactivated(.event.WindowEvent e) {}
   public void windowDeiconified(.event.WindowEvent e) {}
   public void windowIconified(.event.WindowEvent e) {}
   public void windowOpened(.event.WindowEvent e) {}
}
12.2.6.2. Une classe indépendante implémentant le listener
Exemple ( code java 1.1 ) :
package test;
import .*;
import .event.*;
public class TestFrame4 extends Frame {
   public TestFrame4(String title) {
      super(title);
      gestEvt ge = new gestEvt();
      addWindowListener(ge);
   }
   public static void main(.String[] args) {
      try {
         TestFrame4 tf = new TestFrame4("testFrame4");
         tf.setVisible(true);
      } catch (Throwable e) {
         .println("Erreur");
         e.printStackTrace();
      }
Développons en Java
155

   }
}
Exemple ( code java 1.1 ) :
package test;
import .event.*;
public class gestEvt implements WindowListener {
   public void windowActivated(WindowEvent e) {}
   public void windowClosed(WindowEvent e) {}
   public void windowClosing(WindowEvent e) {
      (0);
   }
   public void windowDeactivated(WindowEvent e) {}
   public void windowDeiconified(WindowEvent e) {}
   public void windowIconified(WindowEvent e) {}
   public void windowOpened(WindowEvent e) {}
}
12.2.6.3. Une classe interne
Exemple ( code java 1.1 ) :
package test;
import .*;
import .event.*;
public class TestFrame2 extends Frame {
   class gestEvt implements WindowListener {
      public void windowActivated(WindowEvent e) {};
      public void windowClosed(WindowEvent e) {};
      public void windowClosing(WindowEvent e) {
         (0);
      };
      public void windowDeactivated(WindowEvent e) {};
      public void windowDeiconified(WindowEvent e) {};
      public void windowIconified(WindowEvent e) {};
      public void windowOpened(WindowEvent e) {};
   };
   private gestEvt ge = new TestFrame2.gestEvt();
   public TestFrame2(String title) {
     super(title);
     addWindowListener(ge);
   }
   public static void main(.String[] args) {
      try {
         TestFrame2 tf = new TestFrame2("TestFrame2");       
         tf.setVisible(true);
      } catch (Throwable e) {
         .println("Erreur");
         e.printStackTrace();
      }
   }
}
12.2.6.4. Une classe interne anonyme
Exemple ( code java 1.1 ) :
Développons en Java
156

package test;
import .*;
import .event.*;
public class TestFrame1 extends Frame {
   public TestFrame1(String title) {
      super(title);
      addWindowListener(new WindowAdapter() {
         public void windowClosed(.WindowEvent e) {
            (0);
         };
      });               
   }
   public static void main(.String[] args) {
      try {
         TestFrame1 tf = new TestFrame1("TestFrame");           
         tf.setVisible(true);
      } catch (Throwable e) {
         .println("Erreur");
         e.printStackTrace();
      }
   }
}
12.2.7. Résumé
Le mécanisme mis en place pour intercepter des événéments est le même quel que soit ces événements :
associer au composant qui est à l'origine de l'évenement un controleur adéquat : utilisation des méthodes
• 
addXXXListener() Le paramètre de ces méthodes indique l'objet qui a la charge de répondre au message : cet
objet doit implémenter l'interface XXXListener correspondant ou dérivé d'une classe XXXAdapter (créer une
classe qui implémente l'interface associé à l'événement que l'on veut gérer. Cette classe peut être celle du
composant qui est à l'origine de l'événement (facilité d'implémentation) ou une classe indépendante qui
détermine la frontière entre l'interface graphique (émission d'événement) et celle qui représente la logique de
l'application (traitement des événements) ).
les classes XXXAdapter sont utiles pour créer des classes dédiées au traitement des évenements car elles
• 
implémentent des méthodes par défaut pour celles définies dans l'interface XXXListener dérivées de
EventListener. Il n'existe une classe Adapter que pour les interface qui possédent plusieurs méthodes.
implémenter la méthode associé à l'événement qui fournit en paramètre un objet de type AWTEvent (classe
• 
mère de tout événement) qui contient des informations utiles (position du curseur, état du clavier ...).
Développons en Java
157

13. Le développement d'interface graphique avec SWING
Swing fait partie de la bibliothèque Java Foundation Classes. C'est une extension de l'AWT qui a été intégrée au JDK
depuis sa version 1.2. Cette bibliothèque existe séparement pour le JDK 1.1.
La bibliothèque JFC contient :
l'API Swing : de nouvelles classes et interfaces pour construire des interfaces graphiques
• 
Accessibility API :
• 
2D API: support de graphisme en 2D
• 
API pour l'impression et le cliquer?glisser
• 
13.1. Présentation de Swing
Swing propose de nombreux composants dont certains possède des fonctions étendues, une utilisation des mécanismes de
gestion d'événements performants (ceux introduits par le JDK 1.1) et une apparence modifiable à la volée (une interface
qui emploie le style du système d'exploitation Windows ou Motif ou un nouveau style spécifique à Java nommé Metal).
Tous les éléments de Swing font partie d'un package qui a changé plusieurs fois de nom : le nom du package dépend de
la version du J.D.K. utilisé :
.swing : jusqu'à la version 1.1 beta 2 de Swing des JFC 1.1 et J.D.K. 1.2 beta 4
• 
.swing : utilisé par le J.D.K. 1.2 beta 2 et 3
• 
javax.swing : à partir des versions de Swing 1.1 beta 3 et J.D.K. 1.2 RC1
• 
Les composants Swing forment un nouvelle hériarchie parallèle à celle de l'AWT. L'ancètre de cette hiérarchie est le
composant JComponent. Presque tous ces composants sont écrits en pure Java : ils ne possèdent aucune partie native sauf
ceux qui assurent l'interface avec le système d'exploitation : JApplet, JDialog, JFrame, et JWindow. Cela permet aux
composants de toujours avoir la même apparence quelque soit le système.
Tous les composants Swing possèdent les caractèristiques suivantes :
ce sont des beans
• 
ce sont des composants légers (pas de partie native)  hormis quelques exceptions.
• 
leurs bords peuvent être changés
• 
La procédure à suivre pour utiliser un composant Swing est identique à celle des composants AWT : créer le composant
en appelant son constructeur, appeler les méthodes du composant si nécessaire pour le personnaliser et l'ajouter dans un
conteneur.
Swing utilise la même infrastructure de classes que AWT, ce qui permet de mélanger des composants Swing et AWT
dans la même interface. Sun recommande toutefois d'éviter de les mélanger car certains peuvent ne pas être restitués
correctement.
Les composants Swing utilisent des modèles pour contenir leurs états ou leur données. Ces modèles sont des classes
particulières qui possèdent toutes un comportement par défaut.
Développons en Java
158

13.2. Les packages Swing
Swing contient plusieurs packages :
package principal : il contient les interfaces, les principaux composants, les
javax.swing
modèles par défaut
javax.swing.border
Classes représentant les bordures
javax.swing.colorchooser
Classes définissant un composant pour la sélection de couleurs
Classes et interfaces pour les événements spécifique à Swing. Les autres
javax.swing.event
événements sont ceux de AWT (.event)
javax.swing.filechooser
Classes définissant un composant pour la sélection de fichiers

Classes et interfaces génériques pour gérer l'apparence
.basic
Classes et interfaces de base pour gérer l'apparence
.metal
Classes et interfaces pour définir l'apparence Metal qui est l'apparence par défaut
Classes définissant un composant pour la présentation de données sous forme de
javax.swing.table
tableau

Classes et interfaces de bases pour les composants manipulant du texte

Classes permettant le support du format HTML
.parser
Classes permettant d'analyser des données au format HTML

Classes permettant le support du format RTF
Classes définissant un composant pour la présentation de données sous forme

d'arbre

Classes permettant d'implémenter les fonctions annuler/refaire
13.3. Un exemple de fenêtre autonome
La classe de base d'une application est la classe JFrame. Son rôle est équivalent à la classe Frame de l'AWT et elle
s'utilise de la même façon
Exemple ( code java 1.1 ) :
import javax.swing.*;
import .event.*;
public class swing1 extends JFrame {
   public swing1() {
      super("titre de l'application");
      WindowListener l = new WindowAdapter() {
         public void windowClosing(WindowEvent e){
            (0);
         }
      };
      addWindowListener(l);
      setSize(200,100);
      setVisible(true);
   }
   public static void main(String [] args){
      JFrame frame = new swing1();
   }
}
Développons en Java
159

13.4. Les composants Swing
Il existe des composants Swing équivalents pour chacun des composants AWT avec des constructeurs semblables. De
nombreux constructeurs acceptent comme argument un objet de type Icon, qui représente une petite image généralement
stockée au format Gif.
Le constructeur d'un objet Icon admet comme seul paramètre le nom ou l'URL d'un fichier graphique
Exemple ( code java 1.1 ) :
import javax.swing.*;
import .event.*;
public class swing3 extends JFrame {
  public swing3() {
     super("titre de l'application");
      WindowListener l = new WindowAdapter() {
         public void windowClosing(WindowEvent e){
            (0);
         }
      };
      addWindowListener(l);
      ImageIcon img = new ImageIcon("");
      JButton bouton = new JButton("Mon bouton",img);
      JPanel panneau = new JPanel();
      (bouton);
      setContentPane(panneau);
      setSize(200,100);
      setVisible(true);
   }
  public static void main(String [] args){
      JFrame frame = new swing3();
  }
}
13.4.1. La classe JFrame
JFrame est l'équivalent de la classe Frame de l'AWT : les principales différences sont l'utilisation du double buffering qui
améliore les rafraichissements et l'utilisation d'un panneau de contenu (contentPane) pour insérer des composants (ils ne
sont plus insérer directement au JFrame mais à l'objet contentPane qui lui est associé). Elle représente une fenêtre
principale qui possède un titre, une taille modifiable et éventuellement un menu.
La classe possède plusieurs constructeurs :
Constructeur
Rôle
JFrame()
JFrame(String)
Création d'une instance en précisant le titre
Par défaut, la fenêtre créée n'est pas visible. La méthode setVisible() permet de l'afficher.
Exemple ( code java 1.1 ) :
Développons en Java
160

import javax.swing.*;
public class TestJFrame1 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    f.setVisible(true);
  }
}
La gestion des événements est identique à celle utilisée dans l'AWT depuis le J.D.K. 1.1.
Exemple ( code java 1.1 ) :
import javax.swing.*;
import .event.*;
public class swing2 extends JFrame {
   public swing2() {
     super("titre de l'application");
      WindowListener l = new WindowAdapter() {
         public void windowClosing(WindowEvent e){
           (0);
         }
      };
     addWindowListener(l);
     JButton bouton = new JButton("Mon bouton");
     JPanel panneau = new JPanel();
     (bouton);
     setContentPane(panneau);
     setSize(200,100);
     setVisible(true);
   }
   public static void main(String [] args){
      JFrame frame = new swing2();
   }
}
Tous les composants associés à un objet JFrame sont gérer par un objet de la classe JRootPane. Un objet JRootPane
contient plusieurs Panes. Tous les composants ajoutés au JFame doivent être ajouté à un Pane du JRootPane et non au
JFrame directement. C'est aussi à un de ces Panes qu'il faut associer un layout manager si nécessaire.
Développons en Java
161

Le  Pane le plus utilisé est le ContentPane. Le Layout manager par défaut du contentPane est BorderLayout. Il est
possible de le changer :
Exemple ( code java 1.1 ) :
...
f.getContentPane().setLayout(new FlowLayout());
...
Exemple ( code java 1.1 ) :
import javax.swing.*;
public class TestJFrame2 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    JButton b =new JButton("Mon bouton");
    f.getContentPane().add(b);
    f.setVisible(true);
  }
}
Le JRootPane se compose de plusieurs éléments :
glassPane : un JPanel par défaut
• 
layeredPane qui se compose du contentPane (un JPanel par défaut) et du menuBar (un objet de type JMenuBar)
• 
Le glassPane est un JPanel transparent qui se situe au dessus du layeredPane. Le glassPane peut être n'importe quel
composant : pour le modifier il faut utiliser la méthode setGlassPane() en fournissant le composant en paramètre.
Le layeredPane regroupe le contentPane et le menuBar.
Le contentPane est par défaut un JPanel opaque dont le gestionnaire de présentation est un BorderLayout. Ce panel peut
être remplacé par n'importe quel composant grâce à la méthode setContentPane().
Attention : il ne faut pas utiliser directement la méthode setLayout() d'un objet JFrame sinon une exception
est levée.
Exemple ( code java 1.1 ) :
import javax.swing.*;
import .*;
public class TestJFrame7 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setLayout(new FlowLayout());
    f.setSize(300,100);
    f.setVisible(true);
  }
}
Développons en Java
162

Résultat :
C:\swing\code>java TestJFrame7
Exception in thread "main" .Error: Do not use javax.swing.JFrame.setLay
out() use javax.swing.JFrame.getContentPane().setLayout() instead
        at javax.swing.JFrame.createRootPaneException(Unknown Source)
        at javax.swing.JFrame.setLayout(Unknown Source)
        at (:8)
Le menuBar permet d'attacher un menu à la JFrame. Par défaut, le menuBar est vide. La méthode setJMenuBar() permet
d'affecter un menu à la JFrame.
Exemple ( code java 1.1 ) : Création d'un menu très simple
import javax.swing.*;
import .*;
public class TestJFrame6 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    JButton b =new JButton("Mon bouton"); 
    f.getContentPane().add(b);
    JMenuBar menuBar = new JMenuBar();
    f.setJMenuBar(menuBar);
    JMenu menu = new JMenu("Fichier");
    (menuItem);
    (menu);
    f.setVisible(true);
  }
}
13.4.1.1. Le comportement par défaut à la fermeture
Il possible préciser comment un objet JFrame, JInternalFrame, ou Jdialog réagit à sa fermeture grâce à la méthode
setDefaultCloseOperation(). Cette méthode attend en paramètre une valeur qui peut être :
Constante
Rôle
WindowConstants.DISPOSE_ON_CLOSE
 détruit la fenêtre
WindowConstants.DO_NOTHING_ON_CLOSE
 rend le bouton de fermeture inactif
WindowConstants.HIDE_ON_CLOSE
 cache la fenêtre
Cette méthode ne permet pas d'associer d'autres traitements. Dans ce cas, il faut intercepter l'évenement  et lui associer
les traitements.
Exemple ( code java 1.1 ) : la fenêtre disparaît lors de sa fermeture mais l'application ne se termine pas.
import javax.swing.*;
public class TestJFrame3 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
Développons en Java
163

    f.setSize(300,100);
    JButton b =new JButton("Mon bouton"); 
    f.getContentPane().add(b);
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    f.setVisible(true);
  }
}
13.4.1.2. La personnalisation de l'icone
La méthode setIconImage() permet de modifier l'icône de la JFrame.
Exemple ( code java 1.1 ) :
import javax.swing.*;
public class TestJFrame4 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    JButton b =new JButton("Mon bouton"); 
    f.getContentPane().add(b);
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    ImageIcon image = new ImageIcon("");
    f.setIconImage(image.getImage());
    f.setVisible(true);
  }
}
Si l'image n'est pas trouvée, alors l'icône est vide. Si l'image est trop grande, elle est redimensionnée.
13.4.1.3. Centrer une JFrame à l'écran
Par défaut, une JFrame est affichée dans le coin supérieur gauche de l'écran. Pour la centrer dans l'écran, il faut procéder
comme pour une Frame : déterminer la position de la Frame en fonction de sa dimension et de celle de l'écran et utiliser
la méthode setLocation() pour affecter cette position.
Exemple ( code java 1.1 ) :
import javax.swing.*;
import .*;
public class TestJFrame5 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
Développons en Java
164

    JButton b =new JButton("Mon bouton"); 
    f.getContentPane().add(b);
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
    f.setLocation(dim.width/2 ? f.getWidth()/2, dim.height/2 ? f.getHeight()/2);
    f.setVisible(true);
  }
}
13.4.1.4. Les évenements associées à un JFrame
La gestion des évenements associés à un objet JFrame est identique à celle utilisée pour un objet de type Frame de AWT.
Exemple ( code java 1.1 ) :
import javax.swing.*;
import .event.*;
public class TestJFrame8 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    f.setVisible(true);
    f.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          (0);
        }        
      }
    );
  }
}
13.4.2. Les étiquettes : la classe JLabel
Le composant JLabel propose les mêmes fonctionnalités que les intitulés AWT mais ils peuvent en plus contenir des
icônes .
Cette classe possède plusieurs constructeurs :
Constructeurs
Rôle
JLabel()
Création d'une instance sans texte ni image
JLabel(Icon)
Création d'une instance en précisant l'image
JLabel(Icon, int)
Création d'une instance en précisant l'image et l'alignement horizontal
JLabel(String)
Création d'une instance en précisant le texte
JLabel(String, Icon, int)
Création d'une instance en précisant le texte, l'image et l'alignement horizontal
JLabel(String, int)
Création d'une instance en précisant le texte et l'alignement horizontal
Le composant JLabel permet d'afficher un texte et/ou une icône en précisant leur alignement. L'icône doit être au format
GIF et peut être une animation dans ce format.
Développons en Java
165

Exemple ( code java 1.1 ) :
import javax.swing.*;
import .*;
public class TestJLabel1 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(100,200);
    JPanel pannel = new JPanel(); 
    JLabel jLabel1 =new JLabel("Mon texte dans JLabel"); 
    (jLabel1);
    ImageIcon icone = new ImageIcon("");
    JLabel jLabel2 =new JLabel(icone); 
    (jLabel2);
    JLabel jLabel3 =new JLabel("Mon texte",icone,); 
    (jLabel3);
    f.getContentPane().add(pannel);
    f.setVisible(true);
  }
}
La classe JLabel définie plusieurs méthodes pour modifier l'apparence du composant :
Méthodes
Rôle
setText()
Permet d'initialiser ou de modifier le texte affiché
setOpaque()
Indiquer si le composant est transparent (paramètre false) ou opaque (true)
setBackground()
Indique la couleur de fond du composant (setOpaque doit être à true)
setFont()
Permet de présicer la police du texte
setForeGround()
Permet de préciser la couleur du texte
setHorizontalAlignment()
Permet de modifier l'alignement horizontal du texte et de l'icône
setVerticalAlignment()
Permet de modifier l'alignement vertical du texte et de l'icône
setHorizontalTextAlignment()
Permet de modifier l'alignement horizontal du texte uniquement
Permet de modifier l'alignement vertical du texte uniquement
setVerticalTextAlignment()
Exemple :
jLabel.setVerticalTextPosition();
setIcon()
Permet d'assigner une icône
setDisabledIcon()
Permet d'assigner une icône dans un état désactivée
L'alignement vertical par défaut d'un JLabel est centré. L'alignement horizontal par défaut est soit à droite si il ne contient
que du texte, soit centré si il contient un image avec ou sans texte. Pour modifier cette alignement, il suffit d'utiliser les
méthodes ci dessus en utilisant des constantes en paramètres :  , SwingConstants.CENTER,
SwingConstants.RIGHT, , SwingConstants.BOTTOM
Par défaut, un JLabel est transparent : son fond n'est pas dessiné. Pour le dessiner, il faut utiliser la méthode
setOpaque() :
Développons en Java
166

Exemple ( code java 1.1 ) :
import javax.swing.*;
import .*;
public class TestJLabel2 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(100,200);
    JPanel pannel = new JPanel(); 
    JLabel jLabel1 =new JLabel("Mon texte dans JLabel 1"); 
    jLabel1.setBackground();
    (jLabel1);
    JLabel jLabel2 =new JLabel("Mon texte dans JLabel 2"); 
    jLabel2.setBackground();
    jLabel2.setOpaque(true);
    (jLabel2);
    f.getContentPane().add(pannel);
    f.setVisible(true);
  }
}
Dans l'exemple, les 2 JLabel ont le fond rouge demandé par la méthode setBackground(). Seul le deuxième affiche un
fond rouge car il est rendu opaque avec la méthode setOpaque().
Il est possible d'associer un raccourci clavier au JLabel qui permet de donner le focus à un autre composant. La méthode
setDisplayedMnemonic() permet de définir le raccourci clavier. Celui ci sera activé en utilisant la touche Alt avec le
caractère fourni en paramètre. La méthode  setLabelFor() permet d'associer le composant fourni en paramètre au
raccourci.
Exemple ( code java 1.1 ) :
import javax.swing.*;
import .*;
public class TestJLabel3 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    JPanel pannel = new JPanel(); 
    JButton bouton = new JButton("saisir");
    (bouton);
    JTextField jEdit = new JTextField("votre nom");
    JLabel jLabel1 =new JLabel("Nom : "); 
    jLabel1.setBackground();
    jLabel1.setDisplayedMnemonic('n');
    jLabel1.setLabelFor(jEdit);
    (jLabel1);
    (jEdit);
    f.getContentPane().add(pannel);
    f.setVisible(true);
  }
}
Développons en Java
167

Dans l'exemple, à l'ouverture de la fenêtre, le focus est sur le bouton. Un appui sur Alt+'n' donne le focus au champ de
saisie.
13.4.3. Les panneaux : la classe Jpanel
La classe JPanel est un conteneur utilisé pour regrouper et organiser des composants grâce à un gestionnaire de
présentation (layout manager). Le gestionnaire par défaut d'un JPanel est un objet de la classe FlowLayout.
13.5. Les boutons
Il existe plusieurs boutons définis par Swing.
13.5.1. La classe AbstractButton
C'est une classe abstraite dont hérite les boutons Swing JButton, JMenuItem et JToggleButton.
Cette classe définie de nombreuses méthodes dont les principales sont :
Méthode
Rôle
AddActionListener
Associer un écouteur sur un évenement de type ActionEvent
AddChangeListener
Associer un écouteur sur un évenement de type ChangeEvent
AddItemListener
Associer un écouteur sur un évenement de type ItemEvent
doClick()
Déclencher un clic par programmation
getText()
Texte affiché par le composant
setDisabledIcon()
Associé une icone affichée lorsque le composant à l'état désélectionné
Associé une icone affichée lors du passage de la souris sur le composant à l'état
setDisabledSelectedIcon() désélectionné
setEnabled()
activer/désactiver le composant
setMnemonic() 
associer un raccouci clavier
setPressedIcon()
Associé une icone affichée lorsque le composant est préssé
setRolloverIcon()
Associé une icone affichée lors du passage de la souris sur le composant
Développons en Java
168

setRolloverSelectedIcon() Associé une icone affichée lors du passage de la souris sur le composant à l'état sélectionné
setSelectedIcon()
Associé une icone affichée lorsque le composant à l'état sélectionné
setText()
Mise à jour du texte du composant
isSelected()
Indique si le composant est dans l'état sélectionné
setSelected()
Mise à jour de l'état selectionné du composant
Tous les boutons peuvent afficher du texte et/ou une image.
Il est possible de préciser une image différente lors du passage de la souris sur le composant et lors de l'enfoncement du
bouton : dans ce cas, il faut créer trois images pour chacun des états (normal, enfoncé et survolé). L'image normale est
associée au bouton grace au constructeur, l'image enfoncée grâce à la méthode setPressedIcon() et l'image lors d'un
survole grâce à la méthode setRolloverIcon(). Il suffit enfin d'appeler la méthode setRolloverEnable() avec en paramètre
la valeur true.
Exemple ( code java 1.1 ) :
import javax.swing.*;
import .event.*;
public class swing4 extends JFrame {
   public swing4() {
     super("titre de l'application");
     WindowListener l = new WindowAdapter() {
       public void windowClosing(WindowEvent e){
         (0);
       }
     };
     addWindowListener(l);
     ImageIcon imageNormale = new ImageIcon("");
     ImageIcon imagePassage =  new ImageIcon("");
     ImageIcon imageEnfoncee = new ImageIcon("");
     JButton bouton = new JButton("Mon bouton",imageNormale);
     bouton.setPressedIcon(imageEnfoncee);
     bouton.setRolloverIcon(imagePassage);
     bouton.setRolloverEnabled(true);
     getContentPane().add(bouton, "Center");
     JPanel panneau = new JPanel();
     (bouton);
     setContentPane(panneau);
     setSize(200,100);
     setVisible(true);
   }
   public static void main(String [] args){
      JFrame frame = new swing4();
   }
}
Un bouton peut recevoir des évenements de type ActionEvents (le bouton a été activé), ChangeEvents, et ItemEvents.
Exemple ( code java 1.1 ) : fermeture de l'application lors de l'activation du bouton
import javax.swing.*;
import .event.*;
public class TestJButton3 {
Développons en Java
169

  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    JPanel pannel = new JPanel(); 
    JButton bouton1 = new JButton("Bouton1");
    bouton1.addActionListener( new ActionListener() {
       public void actionPerformed(ActionEvent e) {
         (0);
       }
    }
    );
    (bouton1);
    f.getContentPane().add(pannel);
    f.setVisible(true);
  }
}
Pour de plus amplements informations sur la gestion des événements, voir le chapitre correspondant.
13.5.2. La classe JButton : les boutons
JButton est un composant qui représente un bouton : il peut contenir un texte et/ou une icône.
Il ne gère pas d'état.
Les constructeurs sont :
Constructeur
Rôle
JButton()
JButton(String)
 préciser le texte du bouton
JButton(Icon)
 préciser une icône
JButton(String, Icon)
 préciser un texte et une icone
Il ne gère pas d'état. Toutes les indications concernant le contenu du composant JLabel sont valables pour le composant
JButton.
Exemple ( code java 1.1 ) : un bouton avec une image
import javax.swing.*;
import .event.*;
public class swing3 extends JFrame {
   public swing3() {
      super("titre de l'application");
      WindowListener l = new WindowAdapter() {
         public void windowClosing(WindowEvent e){
            (0);
         }
      };
      addWindowListener(l);
Développons en Java
170

      ImageIcon img = new ImageIcon("");
      JButton bouton = new JButton("Mon bouton",img);
      JPanel panneau = new JPanel();
      (bouton);
      setContentPane(panneau);
      setSize(200,100);
      setVisible(true);
  }
  public static void main(String [] args){
      JFrame frame = new swing3();
  }
}
L'image gif peut être une animation.
Dans un conteneur de type JRootPane, il est possible de définir un bouton par défaut grace à sa méthode
setDefaultButton().
Exemple ( code java 1.1 ) : définition d'un bouton par défaut dans un JFrame
import javax.swing.*;
import .*;
public class TestJButton2 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    JPanel pannel = new JPanel(); 
    JButton bouton1 = new JButton("Bouton 1");
    (bouton1);
    JButton bouton2 = new JButton("Bouton 2");
    (bouton2);
    JButton bouton3 = new JButton("Bouton 3");
    (bouton3);
    f.getContentPane().add(pannel);
    f.getRootPane().setDefaultButton(bouton3);
    f.setVisible(true);
  }
}
Le bouton par défaut est activé par un appui sur la touche Entrée alors que le bouton actif est activé par un appui sur la
barre d'espace.
La méthode isDefaultButton() de JButton permet de savoir si le composant est le bouton par défaut.
13.5.3. La classe JToggleButton
Cette classe définit un bouton à deux états : c'est la classe mère des composants JCheckBox et JRadioButton.
La méthode setSelected() héritée de AbstractButton permet de mettre à jour l'état du bouton. La méthode isSelected()
permet de connaître cet état.
Développons en Java
171

13.5.4. La classe ButtonGroup
La classe ButtonGroup permet de gérer un ensemble de boutons en garantissant qu'un seul bouton du groupe sera
sélectionné.
Pour utiliser la classe ButtonGroup, il suffit d'instancier un objet et d'ajouter des boutons (objet héritant de la classe
AbstractButton grâce à la méthode add(). Il est préférable d'utiliser des objets de la classe JToggleButton ou d'une de ces
classes filles car elles sont capables de gérer leurs états.
Exemple ( code java 1.1 ) :
import javax.swing.*;
public class TestGroupButton1 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    JPanel pannel = new JPanel();
    ButtonGroup groupe = new ButtonGroup();
    JRadioButton bouton1 = new JRadioButton("Bouton 1");
    (bouton1);
    (bouton1);
    JRadioButton bouton2 = new JRadioButton("Bouton 2");
    (bouton2);
    (bouton2);
    JRadioButton bouton3 = new JRadioButton("Bouton 3");
    (bouton3);
    (bouton3);
    f.getContentPane().add(pannel);
    f.setVisible(true);
  }
}
13.5.5. Les cases à cocher : la classe JCheckBox
Les constructeurs sont les suivants :
Constructeur
Rôle
JCheckBox(String)
précise l'intitulé
JCheckBox(String, boolean)
précise l'intitulé et l'état
JCheckBox(Icon)
précise une icône comme intitulé
JCheckBox(Icon, boolean)
précise une icône comme intitulé et l'état
JCheckBox(String, Icon)
précise un texte et une icône comme intitulé
JCheckBox(String, Icon, boolean)
précise un texte et une icône comme intitulé et l'état
Un groupe de cases à cocher peut être défini avec la classe ButtonGroup. Dans ce cas, un seul composant du groupe peut
être sélectionné. Pour l'utiliser, il faut créer un objet de la classe ButtonGroup et utiliser la méthode add() pour ajouter un
composant au groupe.
Exemple ( code java 1.1 ) :
import javax.swing.*;
public class TestJCheckBox1 {
Développons en Java
172

  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    JPanel pannel = new JPanel();
    JCheckBox bouton1 = new JCheckBox("Bouton 1");
    (bouton1);
    JCheckBox bouton2 = new JCheckBox("Bouton 2");
    (bouton2);
    JCheckBox bouton3 = new JCheckBox("Bouton 3");
    (bouton3);
    f.getContentPane().add(pannel);
    f.setVisible(true);
  }
}
13.5.6. Les boutons radio : la classe JRadioButton
Les constructeurs sont les même que ceux de la classe JCheckBox.
Exemple ( code java 1.1 ) :
import javax.swing.*;
public class TestJRadioButton1 {
  public static void main(String argv[]) {
    JFrame f = new JFrame("ma fenetre");
    f.setSize(300,100);
    JPanel pannel = new JPanel();
    JRadioButton bouton1 = new JRadioButton("Bouton 1");
    (bouton1);
    JRadioButton bouton2 = new JRadioButton("Bouton 2");
    (bouton2);
    JRadioButton bouton3 = new JRadioButton("Bouton 3");
    (bouton3);
    f.getContentPane().add(pannel);
    f.setVisible(true);
  }
}
Pour regrouper plusieurs boutons radio, il faut utiliser la classe CheckboxGroup
La suite de ce chapitre sera développée dans une version future de ce document
Développons en Java
173

14. Les applets
Une appet est une programme Java qui s'éxécute dans un logiciel de navigation supportant java ou dans l'appletviewer du
JDK.
Attention : il est recommandé de tester les applets avec l'appletviewer car les navigateurs peuvent prendre
l'applet contenu dans leur cache plutôt que la dernière version compilée.
Le mécanisme d'initialisation d'une applet se fait en deux temps :
la machine virtuelle java instancie l'objet Applet en utilisant le constructeur par défaut
1. 
la machine virtuelle java envoie le message init à l'objet Applet
2. 
Ce chapitre contient plusieurs sections :
L'intégration d'applets dans une page HTML
• 
Les méthodes des applets
• 
Les interfaces utiles pour les applets
• 
La transmission de paramètres à une applet
• 
Applet et le multimédia
• 
Applet et application (applet pouvant s'éxécuter comme application)
• 
Les droits des applets
• 
14.1. L'intégration d'applets dans une page HTML
Dans une page HTML, il faut utiliser le tag APPLET avec la syntaxe suivante :
<APPLET CODE=« Exemple.class » WIDTH=200 HEIGHT=300 > </APPLET>
Le nom de l'applet est indiqué entre guillement à la suite du parametre CODE.
Les paramètres WIDTH et HEIGHT fixent la taille de la fenêtre de l'applet dans la page HTML. L'unité est le pixel. Il est
préférable de ne pas dépasser 640 * 480 (VGA standard).
Le tag APPLET peut comporter les attributs facultatifs suivants :
Tag
Role
permet de spécifier le chemin relatif par rapport au dossier de la page contenant l'applet. Ce
paramètre suit le paramètre CODE.
CODEBASE
Exemple : CODE=nomApplet.class CODEBASE=/nomDossier
HSPACE et
permettent de fixer la distance en pixels entre l'applet et le texte
VSPACE
Développons en Java
174

affiche le texte specifié par le parametre lorsque le navigateur ne supporte pas Java ou que son
ALT
support est désactivé.
Le tag PARAM permet de passer des paramètres à l'applet. Il doit etre inclus entre les tags APPLET et /APPLET.
<PARAM nomParametre value=« valeurParametre »> </APPLET>
La valeur est toujours passée sous forme de chaine de caractères donc entourée de guillemets.
Exemple : <APPLET code=« Exemple.class » width=200 height=300>
Le texte contenu entre <APPLET> et </APPLET> est afficher si le navigateur ne supporte pas java.
14.2. Les méthodes des applets
Une classe dérivée de la classe java.applet.Applet hérite de méthodes qu'il faut redéfinir en fonction des besoins et doit
être déclarée public pour fonctionner.
En général, il n'est pas nécessaire de faire un appel explicite aux méthode init(), start(), stop() et destroy() : le navigateur
se charge d'appeler ces méthodes en fonction de l'état de la page HTML contenant l'applet.
14.2.1. La méthode init()
Cette méthode permet l'initialisation de l'applet : elle n'est éxécutée qu'une seule et unique fois après le chargement de
l'applet.
14.2.2. La méthode start()
Cette méthode est appelée automatiquement après le chargement et l'initialisation (via la méthode init()) lors du premier
affichage de l'applet.
14.2.3. La méthode stop()
Le navigateur appelle automatiquement la méthode lorsque l'on quitte la page HTML. Elle interrompt les traitements de
tous les processus en cours.
14.2.4. La méthode destroy()
Elle est appelée après l'arrêt de l'applet ou lors de l'arret de la machine virtuelle. Elle libère les ressources et détruit les
threads restants
14.2.5. La méthode update()
Elle est appelée à chaque rafraichissement de l'écran ou appel de la méthode repaint(). Elle efface l'écran et appelle la
méthode paint(). Ces actions provoquent souvent des scintillements. Il est préférable de redéfinir cette méthode pour
qu'elle n'efface plus l'écran :
Développons en Java
175

Exemple :
public void update(Graphics g) { paint (g);}
14.2.6. La méthode paint()
Cette méthode permet d'afficher le contenu de l'applet à l'écran. Ce refraîchissement peut être provoqué par le navigateur
ou par le système d'exploitation si l'ordre des fenêtres ou leur taille ont été modifiés ou si une fenêtre recouvre l'applet.
Exemple :
public void paint(Graphics g)
La méthode repaint() force l'utilisation de la méthode paint().
Il existe des méthodes dédié à la gestion de la couleur de fond et de premier plan
La méthode setBackground(Color), héritée de Component, permet de définir la couleur de fond d'une applet. Elle attend
en paramètre un objet de la classe Color.
La méthode setForeground(Color) fixe la couleur d'affichage par défaut. Elle s'applique au texte et aux graphiques.
Les couleurs peuvent être spécifiées de 3 manières différentes :
Color.nomDeLaCouleur
utiliser les noms standard predéfinis
Les noms predéfinis de la classe Color sont : black, blue, cyan, darkGray,
gray, green, lightGray, magenta, orange, pink, red, white, yellow
(Red,Green,Blue : rouge,vert, bleu)
Exemple :
utiliser 3 nombres entiers représentant le
RGB
Color macouleur = new Color(150,200,250);
setBackground (macouleur);
// ou setBackground(150,200,250);
(Hue, Saturation, Brightness : teinte, saturation, luminance). Ce système est
moins répandu que le RGB mais il permet notamment de modifier la
luminance sans modifier les autres caractéristiques
utiliser 3 nombre de type float utilisant
Exemple :
le systeme HSB
setBackground(0.0,0.5,1.0);
dans ce cas 0.0,0.0,0.0 représente le noir et 1.0,1.0,1.0 représente le blanc.
Développons en Java
176

14.2.7. Les méthodes size() et getSize()
L'origine des coordonnées en Java est le coin supérieur gauche. Elles s'expriment en pixels avec le type int.
La détermination des dimensions d'une applet se fait de la façon suivante :
Exemple ( code java 1.0 ) :
Dimension dim = size();
int applargeur = dim.width;
int apphauteur = dim.height;
Avec le JDK 1.1, il faut utiliser getSize() à la place de size().
Exemple ( code java 1.1 ) :
public void paint(Graphics g) {
   super.paint(g);
   Dimension dim = getSize();
   int applargeur = dim.width;
   int apphauteur = dim.height;
   g.drawString("width = "+applargeur,10,15);
   g.drawString("height = "+apphauteur,10,30);
}
14.2.8. Les méthodes getCodeBase() et getDocumentBase()
Ces méthodes renvoient respectivement l'emplacement de l'applet sous forme d'adresse Web ou de dossier et
l'emplacement de la page HTML qui contient l'applet.
Exemple :
public void paint(Graphics g) {
   super.paint(g);
   g.drawString("CodeBase = "+getCodeBase(),10,15);
   g.drawString("DocumentBase = "+getDocumentBase(),10,30);
}
14.2.9. La méthode showStatus()
Affiche une message dans la barre de status de l'applet
Exemple :
public void paint(Graphics g) {
   super.paint(g);
   showStatus("message à afficher dans la barre d'état");
}
Développons en Java
177

14.2.10. La méthode getAppletInfo()
Permet de fournir des informations concernant l'auteur, la version et le copyright de l'applet
Exemple :
static final String appletInfo = " test applet : auteur, 1999 \n\nCommentaires";
public String getAppletInfo() {
   return appletInfo;
}
Pour voir les informations, il faut utiliser l'option info du menu Applet de l'appletviewer.
14.2.11. La méthode getParameterInfo()
Permet de fournir des informations sur les paramètres reconnus par l'applet
Le format du tableau est le suivant :
{ {nom du paramètre, valeurs possibles, description} , ... }
Exemple :
static final String[][] parameterInfo = 
{ {"texte1", "texte1", " commentaires du texte 1" } ,
  {"texte2", "texte2", " commentaires du texte 2" } };
public String[][] getParameterInfo() {
   return parameterInfo;
}
Pour voir les informations, il faut utiliser l'option info du menu Applet de l'appletviewer.
14.2.12. La méthode getGraphics()
Elle retourne la zone graphique d'une applet : utile pour dessiner dans l'applet avec des méthodes qui ne possèdent pas le
contexte graphique en paramètres (ex : mouseDown ou mouseDrag).
14.2.13. La méthode getAppletContext()
Cette méthode permet l'accès à des fonctionnalités du navigateur.
14.2.14. La méthode setStub()
Cette méthode permet d'attacher l'applet au navigateur.
Développons en Java
178

14.3. Les interfaces utiles pour les applets
14.3.1. L'interface Runnable
Cette interface fournit le comportement nécessaire à un applet pour devenir un thread.
Les méthodes start() et stop() de l'applet peuvent permettre d'arrêter et de démarrer un thread pour permettre de limiter
l'usage des ressources machines lorsque la page contenant l'applet est inactive.
14.3.2. L'interface ActionListener
Cette interface permet à l'applet de répondre aux actions de l'utilisateur avec la souris
La méthode actionPerformed() permet de définir les traitements associés aux événements.
Exemple ( code java 1.1 ) :
public void actionPerformed(ActionEvent evt) { ... }
Pour plus d'information, voir le chapitre Gestion des événements avec Java 1.1
14.3.3. L'interface MouseListener pour répondre à un clic de souris
Exemple ( code java 1.1 ) :
import java.applet.*;
import .*;
import .event.*;
public class AppletMouse extends Applet implements MouseListener {
   int nbClick = 0;
   public void init() {
      ();
      addMouseListener(this);
   }
   public void mouseClicked(MouseEvent e) {
      nbClick++;
      repaint();
   }
   public void mouseEntered(MouseEvent e) {
   }
   public void mouseExited(MouseEvent e) {
   }
   public void mousePressed(MouseEvent e) {
   }
   public void mouseReleased(MouseEvent e) {
   }
   public void paint(Graphics g) {
      super.paint(g);
Développons en Java
179

      g.drawString("Nombre de clics : " + nbClick, 10, 10);
   }
}
Pour plus d'information, voir le chapitre Gestion des événements avec Java 1.1 et celui sur l'interface MouseListener
14.4. La transmission de paramètres à une applet
La méthode getParameter() retourne les paramètres écrits dans la page HTML. Elle retourne une chaine de caractères de
type String.
Exemple :
Sting parametre;
parametre = getParameter(« nom?parametre »);
Si le paramètre n'est pas renseigné dans la page HTML alors getParameter retourne null
Pour utiliser les valeurs des paramètres, il sera souvent nécessaire de faire une conversion de la chaine de caractères dans
le type voulu en utilisant les Wrappers
Exemple :
String taille;
int hauteur;
taille = getParameter(« hauteur »);
Integer temp = new Integer(taille)
hauteur = temp.intValue();
Exemple :
int vitesse;
String paramvitesse = getParameter(« VITESSE »);
if (paramvitesse != null) vitesse = Integer.parseInt(paramVitesse);
// parseInt ne fonctionne pas avec une chaine vide
Attention : l'appel à la méthode getParameter() dans le constructeur pas défaut lève une exception de type
NullPointerException.
Exemple :
public MonApplet() {
   String taille;
   taille = getParameter(" message ");
}
14.5. Applet et le multimédia
Développons en Java
180

14.5.1. Insertion d'images.
Java supporte deux standards :
le format GIF de Compuserve qui est beaucoup utilisé sur internet car il génère des fichiers de petite taille
• 
contenant des images d'au plus 256 couleurs.
et le format JPEG. qui convient mieux aux grandes images et à celles de plus de 256 couleurs car le taux de
• 
compression avec perte de qualité peut être précisé.
Pour la manipulation des images, le package nécessaire est .image.
La méthode getImage() possède deux signatures : getImage(URL url) et getImage (URL url, String name).
On procède en deux étapes : le chargement puis l'affichage. Si les paramètres fournies à getImage ne désignent pas une
image, aucune exception n'est levée.
La méthode getImage() ne charge pas de données sur le poste client. Celles ci seront chargées quand l'image sera
dessinée pour la première fois.
Exemple :
public void paint(Graphics g) {
   super.paint(g);
   Image image=null;
   image=getImage(getDocumentBase( ), ""); //chargement de l'image
   g.drawImage(image, 40, 70, this);
}
Le sixième paramètre de la méthode drawImage() est un objet qui implémente l'interface ImageObserver. ImageObserver
est une interface déclarée dans le package .image qui sert à donner des informations sur le fichier image.
Souvent, on indique this à la place de cette argument représentant l'applet elle même. La classe ImageObserver détecte le
chargement et la fin de l'affichage d'une image. La classe Applet contient le comportement qui se charge de faire ces
actions d'ou le fait de mettre this.
Pour obtenir les dimensions de l'image à afficher on peut utiliser les méthodes getWidth() et getHeight() qui retourne un
nombre entier en pixels.
Exemple :
int largeur = 0;
int hauteur = 0;
largeur = image.getWidth(this);
hauteur = image.getHeight(this);
14.5.2. Insertion de sons
Seul le format d'extension .AU de Sun est supporté par java. Pour utiliser un autre format, il faut le convertir.
La méthode play() permet de jouer un son.
Exemple :
import ;
   ...
   try {
      play(new URL(getDocumentBase(), « »));
   } catch (.MalformedURLException e) {}
Développons en Java
181

La méthode getDocumentBase() détermine et renvoie l'URL de l'applet.
Ce mode d'exécution n'est valable que si le son n'est à reproduire qu'une seule fois, sinon il faut utiliser l'interface
AudioClip.
Avec trois méthodes, l'interface AudioClip facilite l'utilisation des sons :
public abstract void play() // jouer une seule fois le fichier
• 
public abstract void loop() // relancer le son jusqu'à interruption par la méthode stop ou la fin de l'applet
• 
public abstract void stop() // fin de la reproduction du clip audio
• 
Exemple :
import java.applet.*;
import .*;
import .*;
public class AppletMusic extends Applet {
   protected AudioClip aC = null;
   public void init() {
      ();
      try {
      AppletContext ac = getAppletContext();
      if (ac != null)
         aC = ac.getAudioClip(new URL(getDocumentBase(), ""));
      else
         .println(" fichier son introuvable ");
      }
      catch (MalformedURLException e) {}
      ();
   }
}
Pour utiliser plusieurs sons dans une applet, il suffit de déclarer plusieurs variables AudioClip.
L'objet retourné par la méthode getAudioClip() est un objet qui implémente l'interface AudioClip défini dans la machine
virtuelle car il est très dépendant du système de la plate forme d'exécution.
14.5.3. Animation d'un logo
Exemple :
import java.applet.*;
import .*;
public class AppletAnimation extends Applet implements Runnable {
   Thread thread;
   protected Image tabImage[];
   protected int index;
   public void init() {
      ();
      //chargement du tableau d'image
      index = 0;
      tabImage = new Image[2];
      for (int i = 0; i < tabImage.length; i++) {
         String fichier = new String("monimage" + (i + 1) + ".gif ");
         tabImage[i] = getImage(getDocumentBase(), fichier);
      }
   }
   public void paint(Graphics g) {
      super.paint(g);
      // affichage de l'image
      g.drawImage(tabImage[index], 10, 10, this);
Développons en Java
182

   }
   public void run() {
      //traitements éxécuté par le thread
      while (true) {
         repaint();
         index++;
         if (index >= tabImage.length)
            index = 0;
         try {
            thread.sleep(500);
         }
         catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
   public void start() {
      //demarrage du tread
      if (thread == null) {
         thread = new Thread(this);
         thread.start();
      }
   }
   public void stop() {
      // arret du thread
      if (thread != null) {
         ();
         thread = null;
      }
   }
   public void update(Graphics g) {
      //la redéfinition de la méthode permet d'éviter les scintillements
      paint(g);
   }
}
La surcharge de la méthode paint() permet d'éviter le scintillement de l'écran due à l'effacement de l'écran et à son
rafraichissement. Dans ce cas, seul le rafraichissement est effectué.
14.6. Applet et application (applet pouvant s'éxécuter comme
application)

Il faut rajouter une classe main à l'applet, définir une fenêtre qui recevra l'affichage de l'applet, appeler les méthodes
init() et start() et afficher la fenetre.
Exemple ( code java 1.1 ) :
import java.applet.*;
import .*;
import .event.*;
public class AppletApplication extends Applet implements WindowListener {
   public static void main(.String[] args) {
      AppletApplication applet = new AppletApplication();
      Frame frame = new Frame("Applet");
      frame.addWindowListener(applet);
      ("Center", applet);
      frame.setSize(350, 250);
      ();
      ();
Développons en Java
183

      applet.start();
   }
   public void paint(Graphics g) {
      super.paint(g);
      g.drawString("Bonjour", 10, 10);
   }
   public void windowActivated(WindowEvent e) { }
   public void windowClosed(WindowEvent e) { }
   public void windowClosing(WindowEvent e) {
      (0);
   }
   public void windowDeactivated(WindowEvent e) { }
   public void windowDeiconified(WindowEvent e) { }
   public void windowIconified(WindowEvent e) { }
   public void windowOpened(WindowEvent e) { }
}
14.7. Les droits des applets
Une applet est une application Java hébergée sur une machine distante (un serveur Web) et qui s'éxécute, après
chargement, sur la machine client équipée d'un navigateur. Ce navigateur controle les accès de l'applet aux ressources
locales et ne les autorisent pas systématiquement : chaque navigateur définit sa propre règle.
Le modèle classique de sécurité pour l 'exécution des applets, recommandé par Sun, distingue deux types d'applets : les
applets non dignes de confiance (untrusted) qui non pas accès aux ressources locales et externes, les applets dignes de
confiance (trusted) qui ont l'accès. Dans ce modèle, une applet est par défaut untrusted.
La signature d'une applet permet de désigner son auteur et de garantir que le code charger par le client est bien celui
demandé au serveur. Cependant, une applet signée n'est pas forcement digne de confiance.
La suite de ce chapitre sera développée dans une version future de ce document
Développons en Java
184

Partie 3 : Les API avancées
Le JDK fourni un certains nombres d'API intégrés au JDK pour des fonctionnalités avancées.
Plusieurs chapitres dans cette partie détaillent les API pour utiliser les fonctionnalités suivantes :
les collections : propose une revue des classes fournies par le JDK pour gérer des ensembles d'objets
• 
les flux : explore les classes utiles à la mise en oeuvre d'un des mécanismes de base pour échanger des données
• 
la sérialisation : présente un mécanisme qui permet de rendre persistant un objet
• 
l'intéraction avec le réseau :
• 
l'accès aux bases de données : indique comment utiliser JDBC pour accéder
• 
l'appel de méthodes distantes : étudie la mise en oeuvre de la technologie RMI pour permettre l'appel de
• 
méthodes distantes.
l'internationalisation : traite d'une façon pratique de la possibilité d'internationnaliser une application
• 
les composants java beans : examine comment développer et utiliser des composants réutilisables
• 
logging : indique comment mettre en oeuvre deux API pour la gestion des logs : Log4J du projet open source
• 
jakarta et l'API logging du JDK 1.4
Développons en Java
185

15. Les collections
Les collections sont des objets qui permettent de gérer des ensembles d'objets. Ces ensembles de données peuvent être
définis avec plusieurs caractéristiques : la possibilité de gérer des doublons, de gérer un ordre de tri, etc. ...
Chaque objet contenu dans une collection est appelé un élément.
15.1. Présentation du framework collection
Dans la version 1 du J.D.K., il n'existe qu'un nombre restreint de classes pour gérer des ensembles de données :
Vector
• 
Stack
• 
Hashtable
• 
Bitset
• 
L'interface Enumeration permet de parcourir le contenu de ces objets.
Pour combler le manque d'objets adaptés, la version 2 du J.D.K. apporte un framework complet pour gérer les
collections. Cette bibliothèque contient un ensemble de classes et interfaces. Elle fourni également un certain nombre de
classes abstraites qui implémentent partiellement certaines interfaces.
Les interfaces à utiliser par des objets qui gèrent des collections sont :
Collection : interface qui est implementée par la plupart des objets qui gèrent des collections
• 
Map : interface qui définie des méthodes pour des objets qui gèrent des collections sous la forme clé/valeur
• 
Set : interface pour des objets qui n'autorisent pas la gestion des doublons dans l'ensemble
• 
List : interface pour des objets qui autorisent la gestion des doublons et un accès direct à un élément
• 
SortedSet : interface qui étend l'interface Set et permet d'ordonner l'ensemble
• 
SortedMap : interface qui étend l'interface Map et permet d'ordonner l'ensemble
• 
Certaines méthodes définies dans ces interfaces sont dites optionnelles : leur définition est donc obligatoire mais si
l'opération n'est pas supportées alors la méthode doit lever une exception particulière. Ceci permet de réduire le nombre
d'interfaces et de répondre au maximum de cas.
Le framework propose plusieurs objets qui implémentent ces interfaces et qui peuvent être directement utilisés :
HashSet : HashTable qui implémente l'interface Set
• 
TreeSet : arbre qui implémente l'interface SortedSet
• 
ArrayList : tableau dynamique qui  implémente l'interface List
• 
LinkedList : liste doublement chaînée (parcours de la liste dans les deux sens) qui implémente l'interface List
• 
HashMap : HashTable qui implémente l'interface Map
• 
TreeMap : arbre qui implémente l'interface SortedMap
• 
Le framework définit aussi des interfaces pour faciliter le parcours des collections et leur tri :
Iterator : interface pour le parcours des collections
• 
Développons en Java
186

ListIterator : interface pour le parcours des listes dans les deux sens et modifier les éléments lors de ce parcours
• 
Comparable : interface pour définir un ordre de tri naturel pour un objet
• 
Comparator : interface pour définir un ordre de tri quelconque
• 
Deux classes existantes dans les précédentes versions du JDK ont été modifiées pour implémenter certaines interfaces du
framework :
Vector : tableau à taille variable qui implémente maintenant l'interface List
• 
HashTable : table de hashage qui implémente maintenant l'interface Map
• 
Le framework propose la classe Collections qui contient de nombreuses méthodes statiques pour réaliser certaines
opérations sur une collection. Plusieurs méthodes unmodifiableXXX() (ou XXX représente une interface d'une
collection) permettent de rendre une collection non modifiable. Plusieurs méthodes synchronizedXXX() permettent
d'obtenir une version synchronisée d'une collection pouvant ainsi être manipulée de façon sûre par plusieurs threads.
Enfin plusieurs méthodes permettent de réaliser des traitements sur la collection : tri et duplication d'une liste, recherche
du plus petit et du plus grand élément, etc. ...
Le framework fourni plusieurs classes abstraites qui proposent une implémentation partielle d'une interface pour faciliter
la création d'un collection personnalisée : AbstractCollection, AbstractList, AbstractMap, AbstractSequentialList et
AbstractSet.
Les objets du framework stockent toujours des références sur les objets contenus dans la collection et non les objets eux
mêmes. Ce sont obligatoirement des objets qui doivent être ajoutés dans une collection. Il n'est pas possible de stocker
directement des types primitifs : il faut obligatoirement encapsuler ces données dans des wrappers.
Toutes les classes de gestion de collection du framework ne sont pas synchronisées : elles ne prennent pas en charge les
traitements multi?threads. Le framework propose des méthodes pour obtenir des objets de gestion de collections qui
prennent en charge cette fonctionnalité. Les classes Vector et Hashtable était synchronisée mais l'utilisation d'une
collection ne se fait généralement pas de ce contexte. Pour réduire les temps de traitement dans la plupart des cas, elles
ne sont pas synchronisées par défaut.
Lors de l'utilisation de ces classes, il est préférable de stocker la référence de ces objets sous la forme d'une interface
qu'ils implémentent plutôt que sous leur forme objet. Ceci rend le code plus facile à modifier si le type de l'objet qui
gèrent la collection doit être changé.
15.2. Les interfaces des collections
Le framework de java 2 définit 6 interfaces en relation directe avec les collections qui sont regroupées dans deux
arborescences :
Le JDK ne fourni pas de classes qui implémentent directement l'interface Collection.
Le tableau ci dessous présente les différentes classes qui implémentent les interfaces de bases Set, List et Map :
Set
List
Map
Hashtable
HashSet
HashMap
ArrayList,
Tableau redimensionnable
Vector
Développons en Java
187

Arbre
TreeSet
TreeMap
Liste chaînée
LinkedList
Classes du JDK 1.1
Stack
Hashtable
Pour gérer toutes les situations de façon simple, certaines méthodes peuvent être définies dans une interface comme
«optionnelles ». Pour celles ci, les classes qui implémentent une telle interface, ne sont pas obligées d'implémenter du
code qui réalise un traitement mais simplement lève une exception si cette fonctionnalité n'est pas supportée.
Le  nombre d'interfaces est ainsi grandement réduit.
Cette exception est du type UnsupportedOperationException. Pour éviter de protéger tous les appels de méthodes d'un
objet gérant les collections dans un bloc try?catch, cette exception hérite  de la classe RuntimeException.
Toutes les classes fournies par le J.D.K. qui implémentent une des interfaces héritant de Collection implémentent toutes
les opérations optionnelles.
15.2.1. L'interface Collection
Cette interface définit des méthodes pour des objets qui gèrent des éléments d'une façon assez générale. Elle est la super
interface de plusieurs interfaces du framework.
Plusieurs classes qui gèrent une collection implémentent une interface qui hérite de l'interface Collection. Cette interface
est une des deux racines de l'arborescence des collections.
Cette interface définit plusieurs méthodes :
Méthode
Rôle
ajoute l'élément fourni en paramètre à la collection. La valeur de retour
boolean add(Object)
indique si la collection a été mise à jour
boolean addAll(Collection)
ajoute à la collection tous les éléments de la collection fournie en paramètre
void clear()
supprime tous les éléments de la collection
indique si la collection contient au moins un élément identique à celui fourni
boolean contains(Object)
en paramètre
indique si tous les éléments de la collection fournie en paramètre sont
boolean containsAll(Collection)
contenus dans la collection
boolean isEmpty()
indique si la collection est vide
renvoie un objet qui permet de parcourir l'ensemble des éléments de la
Iterator iterator()
collection
supprime l'élément fourni en paramètre de la collection. La valeur de retour
boolean remove(Object)
indique si la collection a été mise à jour
supprime tous les éléments de la collection qui sont contenus dans la
boolean removeAll(Collection)
collection fournie en paramètre
int size()
renvoie le nombre d'éléments contenu dans la collection
Object[] toArray()
renvoie d'un tableau d'objets qui contient tous les éléments de la collection
Cette interface représente un minimum commun pour les objets qui gèrent des collections : ajout d'éléments, suppression
d'éléments, vérifier la présence d'un objet dans la collection, parcours de la collection et quelques opérations diverses sur
Développons en Java
188

la totalité de la collection.
Ce tronc commun permet entre autre de définir pour chaque objet gérant une collection, un constructeur pour cette objet
demandant un objet de type Collection en paramètre. La collection est ainsi initialisée avec les éléments contenus dans la
collection fournie en paramètre.
Attention : il ne faut pas ajouter dans une collection une référence à la collection elle?même.
15.2.2. L'interface Iterator
Cette interface définie des méthodes pour des objets capables de parcourir les données d'une collection.
La définition de cette nouvelle interface par rapport à l'interface Enumeration a été justifiée par l'ajout de la
fonctionnalité de suppression et la réduction des noms de méthodes.
Méthode
Rôle
boolean hasNext()
indique si il reste au moins à parcourir dans la collection
Object next()
renvoie la prochain élément dans la collection
void remove()
supprime le dernier élément parcouru
La méthode hasNext() est équivalente à la méthode hasMoreElements() de l'interface Enumeration.
La méthode next() est équivalente à la méthode nextElement() de l'interface Enumeration.
La méthode next() lève une exception de type NoSuchElementException si elle est appelée alors que la fin du parcours
des éléments est atteinte. Pour éviter la lever de cette exception, il suffit d'appeler la méthode hasNext() et de
conditionner avec le résultat l'appel à la méthode next().
Exemple ( code java 1.2 ) :
Iterator iterator = collection.Iterator();
while (iterator.hasNext()) {
            .println(“objet = ”());
}
La méthode remove() permet de supprimer l'élément renvoyé par le dernier appel à la méthode next(). Il est ainsi
impossible d'appeler la méthode remove() sans un appel correspondant à next() : on ne peut pas appeler deux fois de suite
la méthode remove().
Exemple ( code java 1.2 ) : suppression du premier élément
     Iterator iterator = collection.Iterator();
      if (iterator.hasNext()) {
            ();
            itérator.remove();
      }
Si aucun appel à la méthode next() ne correspond à celui de la méthode remove(), une exception de type
IllegalStateException est levée
Développons en Java
189

15.3. Les listes
Une liste est une collection ordonnée d'éléments qui autorise d'avoir des doublons. Etant ordonnée, un élément d'une liste
peut être accédé à partir de son index.
15.3.1. L'interface List
Cette interface étend l'interface Collection.
Les collections qui implémentent cette interface autorisent les doublons dans les éléments de la liste. Ils autorisent aussi
l'insertion d'éléments null.
L'interface List propose plusieurs méthodes pour un accès à partir d'un index aux éléments de la liste. La gestion de cet
index commence à zéro.
Pour les listes, une interface particulière est définie pour assurer le parcours dans les deux sens de la liste et assurer des
mises à jour : l'interface ListIterator
Méthode
Rôle
ListIterator listIterator()
renvoie un objet capable de parcourir la liste
Object set (int, Object)
remplace l'élément contenu à la position précisée par l'objet fourni en paramètre
void add(int, Object)
ajouter l'élément fourni en paramètre à la position précisée
Object get(int)
renvoie l'élément à la position précisée
renvoie l'index du premier élément fourni en paramètre dans la liste ou ?1 si
int indexOf(Object)
l'élément n'est pas dans la liste
ListIterator listIterator()
renvoie un objet pour parcourir la liste et la mettre à jour
renvoie un extrait de la liste contenant les éléments entre les deux index fournis (le
premier index est inclus et le second est exclus). Les éléments contenus dans la
List subList(int,int)
liste de retour sont des références sur la liste originale. Des mises à jour de ces
éléments impactent la liste originale.
renvoie l'index du dernier élément fourni en paramètre dans la liste ou ?1 si
int lastIndexOf(Object)
l'élément n'est pas dans la liste
Object set(int, Object)
remplace  l'élément à la position indiquée avec l'objet fourni
Le framework propose de classes qui implémentent l'interface List : LinkedList et ArrayList.
15.3.2. Les listes chaînées : la classe LinkedList
Cette classe hérite de la classe AbstractSequentialList et implémente donc l'interface List.
Elle représente une liste doublement chaînée.
Cette classe possède un constructeur sans paramètre et un qui demande une collection. Dans ce dernier cas, la liste sera
initialisée avec les éléments de la collection fournie en paramètre.
Exemple ( code java 1.2 ) :
     LinkedList listeChainee = new LinkedList();
      Iterator iterator = listeChainee.Iterator();
Développons en Java
190

      (“element 1”);
      (“element 2”);
      (“element 3”);
      while (iterator.hasNext()) {
            .println(“objet = ”());
      }
Une liste chaînée gère une collection de façon ordonnée : l'ajout d'un élément peut se faire à la fin de la collection ou
après n'importe quel élément. Dans ce cas, l'ajout est lié à la position courante lors d'un parcours.
Pour répondre à ce besoin, l'interface qui permet le parcours de la collection est une sous classe de l'interface Iterator :
l'interface ListIterator.
C o m m e   l e s   i t e r a t o r   s o n t   u t i l i s é s   p o u r   f a i r e   d e s   m i s e s   à   j o u r   d a n s   l a   l i s t e ,   u n e   e x c e p t i o n   d e   t y p e
CurrentModificationException levé si un iterator parcours la liste alors qu'un autre fait des mises à jour (ajout ou
suppression d'un élément dans la liste).
Pour gérer facilement cette situation, il est préférable si l'on sait qu'il y ait des mises à jour à faire de n'avoir qu'un seul
iterator qui soit utilisé.
Plusieurs méthodes pour ajouter, supprimer ou obtenir le premier ou le dernier élément de la liste permettent d'utiliser
cette classe pour gérer une pile :
Méthode
Rôle
void addFirst(Object)
insère l'objet en début de la liste
void addLast(Object)
insère l'objet en fin de la liste
Object getFirst()
renvoie le premier élément de la liste
Object getLast()
renvoie le dernier élément de la liste
Object removeFirst()
supprime le premier élément de la liste et renvoie le premier élément
Object removeLast()
supprime le dernier élément de la liste et renvoie le premier élément
De par les caractéristiques d'une liste chaînée, il n'existe pas de moyen d'obtenir un élément de la liste directement.
Pourtant, la méthode contains() permet de savoir si un élément est contenu dans la liste et la méthode get() permet
d'obtenir l'élément à la position fournie en paramètre. Il ne faut toutefois pas oublier que ces méthodes parcours la liste
jusqu'à obtention du résultat, ce qui peut être particulièrement gourmand en terme de temps de réponse surtout si la
méthode get() est appelée dans une boucle.
Pour cette raison, il ne faut surtout pas utiliser la méthode get() pour parcourir la liste.
La méthode toString() renvoie une chaîne qui contient tous les éléments de la liste.
15.3.3. L'interface ListIterator
Cette interface définie des méthodes pour parcourir la liste dans les deux sens et effectuer des mises à jour qui agissent
par rapport à l'élément courant dans le parcours.
En plus des méthodes définies dans l'interface Iterator dont elle hérite, elle définie les méthodes suivantes :
Méthode
Roles
void add(Object)
ajoute un élément dans la liste en tenant de la position dans le parcours
Développons en Java
191

indique si il reste au moins un élément à parcourir dans la liste dans son sens
boolean hasPrevious()
inverse
Object previous()
renvoi l'élément précédent dans la liste
void set(Object)
remplace l'élément courante par celui fourni en paramètre
La méthode add() de cette interface ne retourne pas un booléen indiquant que l'ajout à réussi.
Pour ajouter un élément en début de liste, il suffit d'appeler la méthode add() sans avoir appeler une seule fois la méthode
next(). Pour ajouter un élément en fin de la liste, il suffit d'appeler la méthode next() autant de fois que nécessaire pour
atteindre la fin de la liste et appeler la méthode add(). Plusieurs appels à la méthode add() successifs, ajoute les éléments
à la position courante dans l'ordre d'appel de la méthode add().
15.3.4. Les tableaux redimensionnables : la classe ArrayList
Cette classe représente un tableau d'objets dont la taille est dynamique.
Elle hérite de la classe AbstractList donc elle implémente l'interface List.
Le fonctionnement de cette classe est identique à celui de la classe Vector.
La différence avec la classe Vector est que cette dernière est multi thread (toutes ces méthodes  sont synchronisées). Pour
une utilisation dans un thread unique, la synchronisation des méthodes est inutile et coûteuse. Il est alors préférable
d'utiliser un objet de la classe ArrayList.
Elle définit plusieurs méthodes dont les principales sont :
Méthode
Rôle
boolean add(Object)
ajoute un élément à la fin du tableau
ajoute tous les éléments de la collection fournie en paramètre à la fin du
boolean addAll(Collection)
tableau
ajoute tous les éléments de la collection fournie en paramètre dans la
boolean addAll(int, Collection)
collection à partir de la position précisée
void clear()
supprime tous les éléments du tableau
permet d'augmenter la capacité du tableau pour s'assurer qu'il puisse
void ensureCapacity(int)
contenir le nombre d'éléments passé en paramètre
Object get(index)
renvoie l'élément du tableau dont la position est précisée
renvoie la position de la première occurrence de l'élément fourni en
int indexOf(Object)
paramètre
boolean isEmpty()
indique si le tableau est vide
renvoie la position de la dernière occurrence de l'élément fourni en
int lastIndexOf(Object)
paramètre
Object remove(int)
supprime dans le tableau l'élément fourni en paramètre
supprime tous les éléments du tableau de la première position fourni incluse
void removeRange(int,int)
jusqu'à la dernière position fournie exclue
Object set(int, Object)
remplace l'élément à la position indiquée par celui fourni en paramètre
int size()
renvoie le nombre d'élément du tableau
void trimToSize()
ajuste la capacité du tableau sur sa taille actuelle
Développons en Java
192

Chaque objet de type ArrayList gère une capacité qui est le nombre total d'élément qu'il est possible d'insérer avant
d'agrandir le tableau. Cette capacité a donc une relation avec le nombre d'élément contenu dans la collection. Lors d'ajout
dans la collection, cette capacité et le nombre d'élément de la collection détermine si le tableau doit être agrandi. Si un
nombre important d'élément doit être ajouté, il est possible de forcer l'agrandissement de cette capacité avec la méthode
ensureCapacity(). Son usage évite une perte de temps liée au recalcul de la taille de la collection. Un constructeur permet
de préciser la capacité initiale.
15.4. Les ensembles
Un ensemble (Set) est une collection qui n'autorise pas l'insertion de doublons.
15.4.1. L'interface Set
Cette classe définit les méthodes d'une collection qui n'accepte pas de doublons dans ces éléments. Elle hérite de
l'interface Collection mais elle ne définie pas de nouvelle méthode.
Pour déterminer si un élément est déjà inséré dans la collection, la méthode equals() est utilisée.
Le framework propose deux classes qui implémentent l'interface Set : TreeSet et HashSet
Le choix entre ces deux objets est liés à la nécessité de trié les éléments :
les éléments d'un objet HashSet ne sont pas triés : l'insertion d'un nouvel élément est rapide
• 
les éléments d'un objet TreeSet sont triés : l'insertion d'un nouvel éléments est plus long
• 
15.4.2. L'interface SortedSet
Cette interface définie une collection de type ensemble triée. Elle hérite de l'interface Set.
Le tri de l'ensemble peut être assuré par deux façons :
les éléments contenus dans l'ensemble implémentent l'interface Comparable pour définir leur ordre naturel
• 
il faut fournir au constructeur de l'ensemble un objet Comparator qui définit l'ordre de tri à utiliser
• 
Elle définie plusieurs méthodes pour tirer parti de cette ordre :
Méthode
Rôle
Comparator comparator()
renvoie l'objet qui permet de trier l'ensemble
Object first()
renvoie le premier élément de l'ensemble
renvoie un sous ensemble contenant tous les éléments inférieurs à celui
SortedSet headSet(Object)
fourni en paramètre
Object last()
renvoie le dernier élément de l'ensemble
renvoie un sous ensemble contenant les éléments compris entre le premier
SortedSet subSet(Object, Object)
paramètre inclus et le second exclus
renvoie un sous ensemble contenant tous les éléments supérieurs ou égaux à
SortedSet tailSet(Object)
celui fourni en paramètre
Développons en Java
193

15.4.3. La classe HashSet
Cette classe est un ensemble sans ordre de tri particulier.
Les éléments sont stockés dans une table de hashage : cette table possède une capacité.
Exemple ( code java 1.2 ) :
import .*;
public class TestHashSet {
  public static void main(String args[]) {
    Set set = new HashSet();
    ("CCCCC");
    ("BBBBB");
    ("DDDDD");
    ("BBBBB");
    ("AAAAA");
    Iterator iterator = set.iterator();
    while (iterator.hasNext()) {.println(());}
  }
}
Résultat :
AAAAA
DDDDD
BBBBB
CCCCC
15.4.4. La classe TreeSet
Cette classe est un arbre qui représente un ensemble trié d'éléments.
Cette classe permet d'insérer des éléments dans n'importe quel ordre et de restituer  ces éléments dans un ordre précis lors
de son parcours.
L'implémentation de cette classe insère un nouvel élément dans l'arbre à la position correspondant à celle déterminée par
l'ordre de tri. L'insertion d'un nouvel élément dans un objet de la classe TreeSet est donc plus lent mais le tri est
directement effectué.
L'ordre utilisé est celui indiqué par les objets insérés si ils implémentent l'interface Comparable pour un ordre de tri
naturel ou fournir un objet de type Comparator au constructeur de l'objet TreeSet pour définir l'ordre de tri.
Exemple ( code java 1.2 ) :
import .*;
public class TestTreeSet {
  public static void main(String args[]) {
    Set set = new TreeSet();
    ("CCCCC");
    ("BBBBB");
    ("DDDDD");
    ("BBBBB");
    ("AAAAA");
    Iterator iterator = set.iterator();
    while (iterator.hasNext()) {.println(());}
  }
}
Développons en Java
194

Résultat :
AAAAA
BBBBB
CCCCC
DDDDD
15.5. Les collections gérées sous la forme clé/valeur
Ce type de collection gère les éléments avec deux entités : une clé et une valeur associée. La clé doit être unique donc il
ne peut y avoir de doublons. En revanche la même valeur peut être associées à plusieurs clés différentes.
Avant l'apparition du framework collections, la classe dédiée à cette gestion était la classe Hashtable.
15.5.1. L'interface Map
Cette interface est une des deux racines de l'arborescence des collections. Les collections qui implémentent cette
interface ne peuvent contenir des doublons. Les collections qui implémentent cette interface utilise une association entre
une clé et une valeur.
Elle définie plusieurs méthodes pour agir sur la collection :
Méthode
Rôle
void clear()
supprime tous les éléments de la collection
boolean containsKey(Object)
indique si la clé est contenue dans la collection
boolean containsValue(Object)
indique si la valeur est contenue dans la collection
Set entrySet()
renvoie un ensemble contenant les valeurs de la collection
Object get(Object)
renvoie la valeur associée à la clé fournie en paramètre
boolean isEmpty()
indique si la collection est vide
Set keySet()
renvoie un ensemble contenant les clés de la collection
Object put(Object, Object)
insère la clé et sa valeur associée fournies en paramètres
void putAll(Map)
insère toutes les clés/valeurs de l'objet fourni en paramètre
Collection values()
renvoie une collection qui contient toutes les éléments des éléments
Object remove(Object)
supprime l'élément dont la clé est fournie en paramètre
int size()
renvoie le nombre d'éléments de la collection
La méthode entrySet() permet d'obtenir un ensemble contenant toutes les clés.
La méthode values() permet d'obtenir une collection contenant toutes les valeurs. La valeur de retour est une Collection
et non un ensemble car il peut y avoir des doublons (plusieurs clés peuvent être associées à la même valeur).
Le J.D.K. 1.2 propose deux nouvelles classes qui implémentent cette interface :
HashMap qui stocke les éléments dans une table de hashage
• 
TreeMap qui stocke les éléments dans un arbre
• 
La classe HashTable a été mise à jour pour implémenter aussi cette interface.
Développons en Java
195

15.5.2. L'interface SortedMap
Cette interface définie une collection de type Map triée sur la clé. Elle hérite de l'interface Map.
Le tri peut être assuré par deux façons :
les clés contenues dans la collection implémentent l'interface Comparable pour définir leur ordre naturel
• 
il faut fournir au constructeur de la collection un objet Comparator qui définit l'ordre de tri à utiliser
• 
Elle définit plusieurs méthodes pour tirer parti de cette ordre :
Méthode
Rôle
Comparator comparator()
renvoie l'objet qui permet de trier la collection
Object first()
renvoie le premier élément de la collection
renvoie une sous collection contenant tous les éléments inférieurs à celui fourni en
SortedSet headMap(Object)
paramètre
Object last()
renvoie le dernier élément de la collection
SortedMap subMap(Object,
renvoie une sous collection contenant les éléments compris entre le premier
Object)
paramètre inclus et le second exclus
renvoie une sous collection contenant tous les éléments supérieurs ou égaux à celui
SortedMap tailMap(Object)
fourni en paramètre
15.5.3. La classe Hashtable
Cette classe qui existe depuis le premier jdk implémente une table de hachage. La clé et la valeur de chaque élément de la
collection peut être n'importe quel objet non nul.
A partir de Java 1.2 cette classe implémente l'interface Map.
Une des particularités de classe HashTable est quelle est synchronisée.
Exemple ( code java 1.2 ) :
import .*;
public class TestHashtable {
  public static void main(String[] args) {
    Hashtable  htable = new Hashtable();
    (new Integer(3), "données 3");
    (new Integer(1), "données 1");
    (new Integer(2), "données 2");
    .println((new Integer(2)));
  }
}
Résultat :
données 2
Développons en Java
196

15.5.4. La classe TreeMap
Cette classe gère une collection d'objets sous la forme clé/valeur stockés dans un arbre de type rouge?noir (Red?black
tree). Elle implémente l'interface SortedMap. L'ordre des éléments de la collection est maintenu grace à un objet de type
Comparable.
Elle possède plusieurs constructeurs dont un qui permet de préciser l'objet Comparable pour définir l'ordre dans la
collection.
Exemple ( code java 1.2 ) :
import .*;
public class TestTreeMap {
  public static void main(String[] args) {
    TreeMap arbre = new TreeMap();
    (new Integer(3), "données 3");
    (new Integer(1), "données 1");
    (new Integer(2), "données 2");
    Set cles = arbre.keySet();
    Iterator iterator = cles.iterator();
    while (iterator.hasNext()) {
      .println((()));
    }
  }
}
Résultat :
données 1
données 2
données 3
15.5.5. La classe HashMap
La classe HashMap est similaire à la classe Hashtable. Les trois grandes différences sont :
elle est apparue dans le JDK 1.2
• 
elle n'est pas synchronisée
• 
elle autorise les objets null comme clé ou valeur
• 
Cette classe n'étant pas synchonisée, pour assurer la gestion des accès concurents sur cet objet, il faut l'envelopper dans
un objet Map en tulisant la méthode synchronizedMap de la classe Collection.
15.6. Le tri des collections
L'ordre de tri est défini grace à deux interfaces :
Comparable
• 
Comparator
• 
Développons en Java
197

15.6.1. L'interface Comparable
Tous les objets qui doivent définir un ordre naturel utilisé par le tri d'une collection avec cet ordre doivent implémenter
cette interface.
Cette interface ne définit qu'une seule méthode : int compareTo(Object).
Cette méthode doit renvoyer :
une valeur entière négative si l'objet courant est inférieur à l'objet fourni
• 
une valeur entière positive si l'objet courant est supérieur à l'objet fourni
• 
une valeur nulle si l'objet courant est égal à l'objet fourni
• 
Les classes wrappers, String et Date implémentent cette interface.
15.6.2. L'interface Comparator
Cette interface représente un ordre de tri quelconque. Elle est utile pour permettre le tri d'objet qui n'implémente pas
l'interface Comparable ou pour définir un ordre de tri différent de celui défini avec Comparable ( l'interface Comparable
représente un ordre naturel : il ne peut y en avoir qu'un)
Cette interface ne définit qu'une seule méthode : int compare(Object, Object).
Cette méthode compare les deux objets fournis en paramètre et renvoie :
une valeur entière négative si le premier objet est inférieur au second
• 
une valeur entière positive si le premier objet est supérieur au second
• 
une valeur nulle si les deux objets sont égaux
• 
15.7. Les algorithmes
La classe Collections propose plusieurs méthodes statiques qui effectuer des opérations sur des collections. Ces
traitements sont polymorphiques car ils demandent en paramètre un objet qui implémente une interface et retourne une
collection.
Méthode
Rôle
void copy(List, List)
copie tous les éléments de la seconde liste dans la première
Enumaration
renvoie un objet Enumeration pour parcourir la collection
enumeration(Collection)
Object max(Collection)
renvoie le plus grand élément de la collection selon l'ordre naturel des éléments
Object max(Collection,
renvoie le plus grand élément de la collection selon l'ordre naturel précisé par
Comparator)
l'objet Comparator
Object min(Collection)
renvoie le plus petit élément de la collection selon l'ordre naturel des éléments
Object min(Collection,
renvoie le plus petit élément de la collection selon l'ordre précisé par l'objet
Comparator)
Comparator
void reverse(List)
inverse l'ordre de la liste fournie en paramètre
void shuffle(List)
réordonne tous les éléments de la liste de façon aléatoire
void sort(List)
trie la liste dans un ordre ascendant selon l'ordre naturel des éléments
void sort(List, Comparator)
trie la liste dans un ordre ascendant selon l'ordre précisé par l'objet Comparator
Développons en Java
198

Si la méthode sort(List) est utilisée, il faut obligatoirement que les éléments inclus dans la liste implémentent tous
l'interface Comparable sinon une exception de type ClassCastException est levée.
Cette classe propose aussi plusieurs méthodes pour obtenir une version multi?thread ou non modifiable des principales
interfaces des collections : Collection, List, Map, Set, SortedMap, SortedSet
XXX synchronizedXXX(XXX) pour obtenir une version multi?thread des objets implémentant l'interface XXX
• 
XXX unmodifiableXXX(XXX) pour obtenir une version non modifiable des objets implémentant l'interface
• 
XXX
Exemple ( code java 1.2 ) :
import .*;
public class TestUnmodifiable{
    public static void main(String args[])
    {
      List list = new LinkedList();
      ("1");
      ("2");
      list = Collections.unmodifiableList(list);
      ("3");
    }
}
Résultat :
C:\>java TestUnmodifiable
Exception in thread "main" .UnsupportedOperationException
        at .Collections$(Unknown Source)
        at (:13)
L'utilisation d'une méthode synchronizedXXX() renvoie une instance de l'objet qui supporte la synchronisation pour les
opérations d'ajout et de suppression d'éléments. Pour le parcours de la collection avec un objet Iterator, il est nécessaire
de synchroniser le bloc de code utilisé pour le parcours. Il est important d'inclure aussi dans ce bloc l'appel à la méthode
pour obtenir l'objet de type Iterator utilisé pour le parcours.
Exemple ( code java 1.2 ) :
import .*;
public class TestSynchronized{
    public static void main(String args[])
    {
      List maList = new LinkedList();
      ("1");
      ("2");
      ("3");
      maList = Collections.synchronizedList(maList);
      synchronized(maList) {
          Iterator i = maList.iterator();
          while (i.hasNext())
               .println(i.next());
          }
     }
}
Développons en Java
199

15.8. Les exceptions du framework
L'exception de type UnsupportedOperationException est levée lorsque qu'une opération optionnelle n'est pas supportée
par l'objet qui gère la collection.
L'exception ConcurrentModificationException est levée lors du parcours d'une collection avec un objet Iterator et que
cette collection subi une modification structurelle.
Développons en Java
200

16. Les flux
Un programme a souvent besoin d'échanger des informations pour recevoir des données d'une source ou pour envoyer
des données vers un destinataire.
La source et la destination de ces échanges peuvent être de nature multiple : un fichier, une socket réseau, un autre
programme, etc ...
De la même façon, la nature des données échangées peut être diverse : du texte, des images, du son, etc ...
16.1. Présentation des flux
Les flux (stream en anglais) permettent  d'encapsuler ces processus d'envoie et de réception de données. Les flux traitent
toujours les données de façon séquentielle.
En java, les flux peuvent être divisés en plusieurs catégories :
les flux d'entrée (input stream) et les flux de sortie (output stream)
• 
les flux de traitement de caractères et les flux de traitement d'octets
• 
Java définit des flux pour lire ou écrire des données mais aussi des classes qui permettent de faire des traitements sur les
données du flux. Ces classes doivent être associées à un flux de lecture ou d'écriture et sont considérées comme des
filtres. Par exemple, il existe des filtres qui permettent de mettre les données traitées dans un tampon (buffer) pour les
traiter par lots.
Toutes ces classes sont regroupées dans le package .
16.2. Les classes de gestion des flux
Ce qui déroute dans l'utilisation de ces classes, c'est leur nombre et la difficulté de choisir celle qui convient le mieux en
fonction des besoins. Pour faciliter ce choix, il faut comprendre la dénomination des classes : cela permet de sélectionner
la ou les classes adaptées aux traitements à réaliser.
Le nom des classes se décompose en un préfixe et un suffixe. Il y a quatre suffixes possibles en fonction du type de flux
(flux d'octets ou de caractères) et du sens du flux (entrée ou sortie).
Flux d'octets
Flux de caractères
Flux d'entrée
InputStream
Reader
Flux de sortie
OutputStream
Writer
Il exite donc quatre hiérarchies de classes qui encapsulent des types de flux particuliers. Ces classes peuvent être séparées
en deux séries de deux catégories différentes : les classes de lecture et d'écriture et les classes permettant la lecture de
caractères ou d'octets.
Développons en Java
201

les sous classes de Reader sont des types de flux en lecture sur des ensembles de caractères
• 
les sous classes de Writer sont des types de flux en écriture sur des ensembles de caractères
• 
les sous classes de InputStream sont des types de flux en lecture sur des ensembles d'octets
• 
les sous classes de OutputStream sont des types de flux en écriture sur des ensembles d'octets
• 
Pour le préfixe, il faut distinguer les flux et les filtres. Pour les flux, le préfixe contient la source ou la destination selon le
sens du flux.
Préfixe du flux
source ou destination du flux
ByteArray
tableau d'octets en mémoire
CharArray
tableau de caractères en mémoire
File
fichier
Object
objet
Pipe
pipeline entre deux threads
String
chaîne de caractères
Pour les filtres, le préfixe contient le type de traitement qu'il effectue. Les filtres n'existent pas obligatoirement pour des
flux en entrée et en sortie.
Type de traitement
Préfixe de la classe
En entrée
En sortie
Mise en tampon
Buffered
Oui
Oui
Oui pour flux
Concaténation de flux
Sequence
Non
d'octets
Oui pour flux
Oui pour flux
Conversion de données
Data
d'octets
d'octets
Oui pour les flux de
Numérotation des lignes
LineNumber
Non
caractères
Lecture avec remise dans le flux des données
PushBack
Oui
Non
Impression
Print
Non
Oui
Oui pour flux
Oui pour flux
Sérialisation
Object
d'octets
d'octets
InputStream /
Oui pour flux
Oui pour flux
Conversion octets/caractères
OutputStream
d'octets
d'octets
Buffered : ce type de filtre permet de mettre les données du flux dans un tampon. Il peut être utilisé en entrée et
• 
en sortie
Sequence : ce filtre permet de fusionner plusieurs flux.
• 
Data : ce type de flux permet de traiter les octets sous forme de type de données
• 
LineNumber : ce filtre permet de numéroter les lignes contenues dans le flux
• 
PushBack : ce filtre permet de remettre des données lues dans le flux
• 
Print : ce filtre permet de réaliser des impressions formatées
• 
Object : ce filtre est utilisé par la sérialisation
• 
InputStream / OuputStream : ce filtre permet de convertir des octets en caractères
• 
Développons en Java
202

La package définit ainsi plusieurs classes :
Flux en lecture
Flux en sortie
BufferedReader
BufferedWriter
CharArrayReader
CharArrayWriter
FileReader
FileWriter
InputStreamReader
OutputStreamWriter
Flux de caractères
LineNumberReader
PipedReader
PipedWriter
PushbackReader
StringReader
StringWriter
Flux d'octets
BufferedInputStream
BufferedOutputStream
ByteArrayInputStream
ByteArrayOutputStream
DataInputStream
DataOuputStream
FileInputStream
FileOutputStream
ObjectInputStream
ObjetOutputStream
PipedInputStream
PipedOutputStream
PrintStream
PushbackInputStream
SequenceInputStream
16.3. Les flux de caractères
Ils transportent des données sous forme de caractères : java les gèrent avec le format Unicode qui code les caractères sur
2 octets.
Ce type de flux a été ajouté à partir du JDK 1.1.
Les classes qui gèrent les flux de caractères héritent d'une des deux classes abstraites Reader ou Writer. Il existe de
nombreuses sous classes pour traiter les flux de caractères.
Développons en Java
203

16.3.1. La classe Reader
C'est une classe abstaite qui est la classe mère de toutes les classes qui gèrent des flux de caractères en lecture.
Cette classe définit plusieurs méthodes :
Méthodes
Rôles
boolean markSupported()
indique si le flux supporte la possibilité de marquer des positions
boolean ready()
indique si le flux est prêt à être lu
close()
ferme le flux et libère les ressources qui lui étaient associées
int read()
renvoie le caractère lu ou ?1 si la fin du flux est atteinte.
int read(char[])
lire plusieurs caractères et les mettre dans un tableau de caractères
int read(char[], int, int)
lire plusieurs caractères. Elle attend en paramètre : un tableau de caractères
qui contiendra les caractères lus, l'indice du premier éléments du tableau qui
recevra le premier caractère et le nombre de caractères à lire. Elle renvoie le
nombre de caractères lus ou ?1 si aucun caractère n'a été lu. La tableau de
Développons en Java
204

caractères contient les caractères lus.
saute autant de caractères dans le flux que la valeur fournie en paramètre.
long skip(long)
Elle renvoie le nombre de caractères sautés.
mark()
permet de marquer une position dans le flux
reset()
retourne dans le flux à la dernière position marquée
16.3.2. La classe Writer
C'est une classe abstaite qui est la classe mère de toutes les classes qui gèrent des flux de caractères en écriture.
Cette classe définit plusieurs méthodes :
Méthodes
Rôles
close()
ferme le flux et libère les ressources qui lui étaient associées
write(int)
écrire le caractère en paramètre dans le flux.
write(char[])
écrire le tableau de caractères en paramètre dans le flux.
écrire plusieurs caractères. Elle attend en paramètres : un tableau de
write(char[], int, int)
caractères, l'indice du premier caractère dans le tableau à écrire  et le
nombre de caractères à écrire.
write(String)
écrire la chaîne de caractères en paramètre dans le flux
écrire une portion d'une chaîne de caractères. Elle attend en paramètre : une
write(String, int, int)
chaîne de caractères, l'indice du premier caractère dans la chaîne à écrire  et
le nombre de caractères à écrire.
16.3.3. Les flux de caractères avec un fichier
Les classes FileReader et FileWriter permettent de gérer des flux de caractères avec des fichiers.
16.3.3.1. Les flux de caractères en lecture sur un fichier
Il faut instancier un objet de la classe FileReader. Cette classe hérite de la classe InputStreamReader et possède plusieurs
constructeurs qui peuvent tous lever une exception de type FileNotFoundException:
Constructeur
Rôle
FileInputReader(String)
Créer un flux en lecture vers le fichier dont le nom est précisé en paramètre.
FileInputReader(File)
Idem mais le fichier est précisé avec un objet de type File
Exemple ( code java 1.1 ) :
FileReader fichier = new FileReader(«»);
Développons en Java
205

Il existe plusieurs méthodes de la classe FileReader qui permettent de lire un ou plusieurs caractères dans le flux. Toutes
ces méthodes sont héritées de la classe Reader et peuvent toutes lever l'exception IOException.
Une fois les traitements sur le flux terminés, il faut libérer les ressources qui lui sont allouées en utilisant la méthode
close().
16.3.3.2. Les flux de caractères en écriture sur un fichier
Il faut instancier un objet de la classe FileWriter qui hérite de la classe OuputStreamWriter. Cette classe possède
plusieurs constructeurs :
Constructeur
Rôle
Si le nom du fichier précisé n'existe pas alors le fichier sera créé. Si il existe
FileWriter(String)
et qu'il contient des données celles ci seront écrasées.
FileWriter(File)
Idem mais le fichier est précisé avec un objet de la classe File.
Le booléen permet de préciser si les données seront ajoutées au fichier
FileWriter(String, boolean)
(valeur true) ou écraseront les données existantes (valeur false)
Exemple ( code java 1.1 ) :
FileWriter fichier = new FileWriter («»);
Il existe plusieurs méthodes de la classe FileWriter héritées de la classe Writer qui permettent d'écrire un ou plusieurs
caractères dans le flux.
Une fois les traitements sur le flux terminés, il faut libérer les ressources qui lui sont allouées en utilisant la méthode
close().
16.3.4. Les flux de caractères tamponnés avec un fichier.
Pour améliorer les performances des flux sur un fichier, la mise en tampon des données lues ou écrites  permet de traiter
un ensemble de caractères représentant une ligne  plutôt que de traiter les données caractères par caractères. Le nombre
d'opérations est ainsi réduit.
Les classes BufferedReader et BufferedWriter permettent de gérer des flux de caractères tamponnés avec des fichiers.
16.3.4.1. Les flux de caractères tamponnés en lecture avec un fichier
Il faut instancier un objet de la classe BufferedReader. Cette classe possède plusieurs constructeurs qui peuvent tous
lever une exception de type FileNotFoundException:
Constructeur
Rôle
BufferedReader(Reader)
le paramètre fourni doit correspondre au flux à lire.
BufferedReader(Reader, int)
Développons en Java
206

l'entier en paramètre permet de préciser la taille du buffer. Il doit être positif
sinon une exception de type IllegalArgumentException est levée.
Exemple ( code java 1.1 ) :
BufferedReader fichier  = new BufferedReader(new FileReader(""));
Il existe plusieurs méthodes de la classe BufferedReader héritées de la classe Reader qui permettent de lire un ou
plusieurs caractères dans le flux. Toutes ces méthodes peuvent lever une exception de type IOException. Elle définit une
méthode supplémentaire pour la lecture :
Méthode
Rôle
lire une ligne de caractères dans le flux. Une ligne est une suite de
String readLine()
caractères qui se termine par un retour chariot '\r' ou un saut de ligne '\n' ou
les deux.
La classe BufferedReader possède plusieurs méthodes pour gérer le flux héritées de la classe Reader.
Une fois les traitements sur le flux terminés, il faut libérer les ressources qui lui sont allouées en utilisant la méthode
close().
Exemple ( code java 1.1 ) :
import .*;
public class TestBufferedReader {
  protected String source;
  public TestBufferedReader(String source) {
    this.source = source;
    lecture();
  }
  public static void main(String args[]) {
    new TestBufferedReader("");
  }
  private void lecture() { 
    try {
      String ligne ;
      BufferedReader fichier = new BufferedReader(new FileReader(source));
      while ((ligne = fichier.readLine()) != null) {
          .println(ligne);
      }
      fichier.close();
    } catch (Exception e) {
      e.printStackTrace();
    }     
  }    
}
Développons en Java
207

16.3.4.2. Les flux de caractères tamponnés en écriture avec un fichier
Il faut instancier un objet de la classe BufferedWriter. Cette classe possède plusieurs constructeurs :
Constructeur
Rôle
le paramètre fourni doit correspondre au flux dans lequel les données sont
BufferedWriter(Writer)
écrites.
l'entier en paramètre permet de préciser la taille du buffer. Il doit être positif
BufferedWriter(Writer, int)
sinon une exception IllegalArgumentException est levée.
Exemple ( code java 1.1 ) :
BufferedWriter fichier = new BufferedWriter( new FileWriter(«»));
Il existe plusieurs méthodes de la classe BufferedWriter héritées de la classe Writer qui permettent de lire un ou plusieurs
caractères dans le flux.
La classe BufferedWriter possède plusieurs méthodes pour gérer le flux :
Méthode
Rôle
flush()
vide le tampon en écrivant les données dans le flux.
newLine()
écrire un séparateur de ligne dans le flux
Une fois les traitements sur le flux terminés, il faut libérer les ressources qui lui sont allouées en utilisant la méthode
close().
Exemple ( code java 1.1 ) :
import .*;
import .*;
public class TestBufferedWriter {
  protected String destination;
  public TestBufferedWriter(String destination) {
    this.destination = destination;
    traitement();
  }
  public static void main(String args[]) {
    new TestBufferedWriter("");
  }
  private void traitement() { 
    try {
      String ligne ;
      int nombre = 123;
      BufferedWriter fichier = new BufferedWriter(new FileWriter(destination));
      fichier.write("bonjour tout le monde");
      fichier.newLine();
      fichier.write("Nous sommes le "+ new Date());      
      fichier.write(", le nombre magique est " + nombre);
      fichier.close();
    } catch (Exception e) {
Développons en Java
208

      e.printStackTrace();
    }     
  }    
}
16.3.4.3. La classe PrintWriter
Cette classe permet d'écrire dans un flux des données formatées.
Cette classe possède plusieurs constructeurs :
Constructeur
Rôle
PrintWriter(Writer)
Le paramètre fourni précise le flux. Le tampon est automatiquement vidé.
PrintWriter(Writer, boolean)
Le booléen permet de préciser si le tampon doit être automatiquement vidé
PrintWriter(OutputStream)
Le paramètre fourni précise le flux. Le tampon est automatiquement vidé.
PrintWriter(OutputStream, boolean)
Le booléen permet de préciser si le tampon doit être automatiquement vidé
Exemple ( code java 1.1 ) :
PrintWriter fichier = new PrintWriter( new FileWriter(«»));
Il existe de nombreuses méthodes de la classe PrintWriter qui permettent d'écrire un ou plusieurs caractères dans le flux
en les formatant. Les méthodes write() sont héritées de la classe Writer. Elle définit plusieurs méthodes pour envoyer des
données formatées dans le flux :
print( ... )
• 
Plusieurs méthodes print acceptent des données de différents types pour les convertir en caractères et les écrire
dans le flux
println()
• 
Cette méthode permet de terminer la ligne courante dans le flux en y écrivant un saut de ligne.
println ( ... )
• 
Plusieurs méthodes println acceptent des données de différents types pour les convertir en caractères et les écrire
dans le flux avec une fin de ligne.
La classe PrintWriter possède plusieurs méthodes pour gérer le flux :
Méthode
Rôle
flush()
Vide le tampon en écrivant les données dans le flux.
Développons en Java
209

Exemple ( code java 1.1 ) :
import .*;
import .*;
public class TestPrintWriter {
  protected String destination;
  public TestPrintWriter(String destination) {
    this.destination = destination;
    traitement();
  }
  public static void main(String args[]) {
    new TestPrintWriter("");
  }
  private void traitement() { 
    try {
      String ligne ;
      int nombre = 123;
      PrintWriter fichier = new PrintWriter(new FileWriter(destination));
      fichier.println("bonjour tout le monde");
      fichier.println("Nous sommes le "+ new Date());      
      fichier.println("le nombre magique est " + nombre);
      fichier.close();
    } catch (Exception e) {
      e.printStackTrace();
    }     
  }    
}
16.4. Les flux d'octets
Ils transportent des données sous forme d'octets. Les flux de ce type sont capables de traiter toutes les données.
Les classes qui gèrent les flux d'octets héritent d'une des deux classes abstraites InputStream ou OutputStream. Il existe
de nombreuses sous classes pour traiter les flux d'octets.
Développons en Java
210

16.4.1. Les flux d'octets avec un fichier.
Les classes FileInputStream et FileOutputStream permettent de gérer des flux d'octets avec des fichiers.
16.4.1.1. Les flux d'octets en lecture sur un fichier
Il faut instancier un objet de la classe FileInputStream. Cette classe possède plusieurs constructeurs qui peuvent tous
lever l'exception FileNotFoundException:
Constructeur
Rôle
FileInputStream(String)
Ouvre un flux en lecture sur le fichier dont le nom est donné en paramètre
FileInputStream(File)
Idem mais le fichier est précisé avec un objet de type File
Exemple ( code java 1.1 ) :
FileInputStream fichier = new FileInputStream(«»);
Développons en Java
211

Il existe plusieurs méthodes de la classe FileInputStream qui permettent de lire un ou plusieurs octets dans le flux. Toutes
ces méthodes peuvent lever l'exception IOException.
int read()
• 
Cette méthode envoie la valeur de l'octet lu ou ?1 si la fin du flux est atteinte.
Exemple ( code java 1.1 ) :
int octet = 0;
while (octet != 1 ) {
   octet = ();
}
int read(byte[], int, int)
• 
Cette méthode lit plusieurs octets. Elle attend en paramètre : un tableau d'octets qui contiendra les octets lus,
l'indice du premier éléments du tableau qui recevra le premier octet et le nombre d'octets à lire.
Elle renvoie le nombre d'octets lus ou ?1 si aucun octet n'a été lus. La tableau d'octets contient les octets lus.
La classe FileInputStream possède plusieurs méthodes pour gérer le flux :
Méthode
Rôle
saute autant d'octets dans le flux que la valeur fournie en paramètre.
long skip(long)
Elle renvoie le nombre d'octets sautés.
close()
ferme le flux et libère les ressources qui lui étaient associées
retourne le nombre d'octets qu'il est encore possible de lire dans le
int available()
flux
Une fois les traitements sur le flux terminés, il faut libérer les ressources qui lui sont allouées en utilisant la méthode
close().
16.4.1.2. Les flux d'octets en écriture sur un fichier
Il faut instancier un objet de la classe FileOutputStream. Cette classe possède plusieurs constructeurs :
Constructeur
Rôle
Si le fichier précisé n'existe pas, il sera créé. Si il existe et qu'il contient des
FileOutputStream(String)
données celles ci seront écrasées.
Le booléen permet de préciser si les données seront ajoutées au fichier
FileOutputStream(String, boolean)
(valeur true) ou écraseront les données existantes (valeur false)
Exemple ( code java 1.1 ) :
FileOuputStream fichier = new FileOutputStream(«»);
Développons en Java
212

Il existe plusieurs méthodes de la classe FileOutputStream qui permettent de lire un ou plusieurs octets dans le flux.
write(int)
• 
Cette méthode écrit l'octet en paramètre dans le flux.
write(byte[])
• 
Cette méthode écrit plusieurs octets. Elle attend en paramètre : un tableau d'octets qui contient les octets à
écrire : tous les éléments du tableau sont écrits.
write(byte[], int, int)
• 
Cette méthode écrit plusieurs octets. Elle attend en paramètre : un tableau d'octets qui contient les octets à
écrire, l'indice du premier éléments du tableau d'octets à écrire  et le nombre d'octets à écrire.
Une fois les traitements sur le flux terminés, il faut libérer les ressources qui lui sont allouées en utilisant la méthode
close().
Exemple ( code java 1.1 ) :
import .*;
public class CopieFichier {
  protected String source;
  protected String destination;
  public CopieFichier(String source, String destination) {
    this.source = source;
    this.destination = destination;
    copie();
  }
  public static void main(String args[]) {
    new CopieFichier("","");
  }
  private void copie() { 
    try {
      FileInputStream fis = new FileInputStream(source);
      FileOutputStream fos = new FileOutputStream(destination);
      while(fis.available() > 0) fos.write(());
      fis.close();
      fos.close();
    } catch (Exception e) {
      e.printStackTrace();
    }     
  }    
}
16.4.2. Les flux d'octets tamponnés avec un fichier.
Pour améliorer les performances des flux sur un fichier, la mise en tampon des données lues ou écrites  permet de traiter
un ensemble d'octets plutôt que de traiter les données octets par octets. Le nombre d'opérations est ainsi réduit.
16.5. La classe File
Les fichiers et les répertoires sont encapsulés dans la classe File du package . Il n'existe pas de classe pour traiter
les répertoires car ils sont considérés comme des fichiers. Une instance de la classe File est une représentation logique
d'un fichier ou d'un répertoire qui peut ne pas exister physiquement sur le disque.
Développons en Java
213

Si le fichier ou le répertoire existe, de nombreuses méthodes de la classe File permettent d'obtenir des informations sur le
fichier. Sinon plusieurs méthodes permettent de créer des fichiers ou des répertoires. Voici une liste des principales
méthodes :
Méthode
Rôle
boolean canRead()
indique si le fichier peut être lu
boolean canWrite()
indique si le fichier peut être modifié
boolean createNewFile()
création d'un nouveau fichier vide
création d'un nouveau fichier dans le répertoire par défaut
File createTempFile(String, String)
des fichiers temporaires. Les deux arguments sont le préfixe
et le suffixe du fichier.
File createTempFile(String, String,
création d'un nouveau fichier temporaire. Les trois arguments sont
File)
le préfixe et le suffixe du fichier et le répertoire.
détruire le fichier ou le repertoire. Le booléen indique le succés de
boolean delete()
l'opération
deleteOnExit()
demande la suppression du fichier à l'arrêt de la JVM
boolean exists()
indique si le fichier existe physiquement
String getAbsolutePath()
renvoie le chemin absolu du fichier
String getPath
renvoie le chemin du fichier
boolean isAbsolute()
indique si le chemin est absolu
boolean isDirectory()
indique si le fichier est un répertoire
boolean isFile()
indique si l'objet  représente un fichier
long length()
renvoie la longueur du fichier
String[] list()
renvoie la liste des fichiers et répertoire contenu dans le répertoire
boolean  mkdir()
création du répertoire
création du répertoire avec création des répertoire manquant dans
boolean mkdirs()
l'arborescence du chemin
boolean renameTo()
renommer le fichier
Depuis la version 1.2 du J.D.K., de nombreuses fonctionnalités ont été ajoutées à cette classe :
la création de fichiers temporaires (createNewFile, createTempFile, deleteOnExit)
• 
la gestion des attributs caché et lecture seul (isHidden, isReadOnly)
• 
des méthodes qui renvoient des objets de type File au lieu de type String ( getParentFile, getAbsoluteFile,
• 
getCanonicalFile, listFiles)
une méthode qui renvoie le fichier sous forme d'URL (toURL)
• 
Développons en Java
214

Exemple ( code java 1.1 ) :
import .*;
public class TestFile {
  protected String nomFichier;
  protected File fichier;
  public TestFile(String nomFichier) {
    this.nomFichier = nomFichier;
    fichier = new File(nomFichier);
    traitement();
  }
  public static void main(String args[]) {
    new TestFile(args[0]);
  }
  private void traitement() {
    if (!fichier.exists()) { 
      .println("le fichier "+nomFichier+"n'existe pas");
      (1);
    }      
    .println(" Nom du fichier    : "+fichier.getName());
    .println(" Chemin du fichier : "+fichier.getPath());
    .println(" Chemin absolu     : "+fichier.getAbsolutePath());
    .println(" Droit de lecture  : "+fichier.canRead()); 
    .println(" Droite d'ecriture : "+fichier.canWrite());
    if (fichier.isDirectory() ) {
      .println(" contenu du repertoire ");
      String fichiers[] = ();
      for(int i = 0; i <fichiers.length; i++) .println("  "+fichiers[i]);
    }     
  }                     
}
Exemple ( code java 1.2 ) :
import .*;
public class TestFile_12 {
  protected String nomFichier;
  protected File fichier;
  public TestFile_12(String nomFichier) {
    this.nomFichier = nomFichier;
    fichier = new File(nomFichier);
    traitement();
  }
  public static void main(String args[]) {
    new TestFile_12(args[0]);
  }
  private void traitement() {
    if (!fichier.exists()) { 
      .println("le fichier "+nomFichier+"n'existe pas");
      (1);
    }      
    .println(" Nom du fichier    : "+fichier.getName());
    .println(" Chemin du fichier : "+fichier.getPath());
    .println(" Chemin absolu     : "+fichier.getAbsolutePath());
    .println(" Droit de lecture  : "+fichier.canRead()); 
    .println(" Droite d'ecriture : "+fichier.canWrite());
    if (fichier.isDirectory() ) {
      .println(" contenu du repertoire ");
      File fichiers[] = fichier.listFiles();
Développons en Java
215

      for(int i = 0; i <fichiers.length; i++) {
        if (fichiers[i].isDirectory()) 
          .println("  ["+fichiers[i].getName()+"]");          
        else
          .println("  "+fichiers[i].getName());
      }
    }     
  }                     
}
16.6. Les fichiers à accès direct
Les fichiers à accès direct permettent un accès rapide à un enregistrement contenu dans un fichier. Le plus simple pour
utiliser un tel type de fichier est qu’il contienne des enregistrements de taille fixe mais ce n’est pas obligatoire. Il est
possible dans un tel type de fichier de mettre à jour directement un de ces enregistrements.
La classe RamdonAccessFile encapsule les opérations de lecture/écriture d’un tel fichier. Elle implémente les interfaces
DataInput et DataOutput.
Elle possède deux contructeurs qui attendent en paramètre le fichier à utiliser (sous la forme d’un nom de fichier ou d’un
objet de type File qui encapsule le fichier) et le mode d’accès.
Le mode est une chaine de caractères qui doit être égal à «r» ou «rw» selon que le mode soit lecture seule ou
lecture/écriture.
Ces deux contructeurs peuvent lever les exceptions suivantes :
FileNotFoundException si le fichier n’est pas trouvé
• 
IllegalArgumentException si le mode n’est pas «r» ou «rw»
• 
SecurityException si le gestionnaire de sécurité empèche l’accès aux fichiers dans le mode précisé
• 
La classe RandomAccessFile possède de nombreuses méthodes writeXXX() pour écrire des types primitifs dans le
fichier.
Exemple :
package ;
import .RandomAccessFile;
public class TestRandomAccesFile {
  public static void main(String[] args) {
    try {
      RandomAccessFile monFichier = new RandomAccessFile("", "rw");
      for (int i = 0; i < 10; i++) {
        monFichier.writeInt(i * 100);
      }
      monFichier.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Elle possède aussi de nombreuses classes readXXX() pour lire des données primitives dans le fichier.
Exemple :
package ;
import .RandomAccessFile;
Développons en Java
216

public class TestRandomAccesFile {
  public static void main(String[] args) {
    try {
      RandomAccessFile monFichier = new RandomAccessFile("", "rw");
      for (int i = 0; i < 10; i++) {
         .println(monFichier.readInt());
      }
      monFichier.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Résultat :
 0
  100
  200
  300
  400
  500
  600
  700
  800
  900
Pour naviguer dans le fichier, la classe utilise un pointeur qui indique la position dans le fichier ou les opérations de
lecture ou de mise à jour doivent être effectuées. La méthode getFilePointer() permet de connaître la position de ce
pointeur et la méthode seek() permet de le déplacer.
La méthode seek() attendant en paramètre un entier long qui réprésentent la position, dans le fichier, précisée en octets.
La première position commence à zéro.
Exemple : lecture de la sixème données
package ;
import .RandomAccessFile;
public class TestRandomAccesFile {
  public static void main(String[] args) {
    try {
      RandomAccessFile monFichier = new RandomAccessFile("", "rw");
      // 5 représente le sixième enregistement puisque le premier commence à 0
      // 4 est la taille des données puisqu’elles sont des entiers de type int (codé sur 4octets)
      (5*4);
      .println(monFichier.readInt());
      monFichier.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Résutlat :
500
Développons en Java
217

17. La sérialisation
La sérialisation est un procédé introduit dans le JDK version 1.1 qui permet de rendre un objet persistant. Cet objet est
mis sous une forme sous laquelle il pourra être reconstitué à l'identique. Ainsi il pourra être stocké sur un disque dur ou
transmis au travers d'un réseau pour le créer dans une autre JVM. C'est le procédé qui est utilisé par RMI. LA
serialisation est aussi utilisée par les beans pour sauvegarder leurs états.
Au travers de ce mécanisme, java fourni une façon facile, transparente et standard de réaliser cette opération : ceci
permet de facilement mettre en place un mécanisme de persistance. Il est de ce fait inutile de créer un format particulier
pour sauvegarder et relire un objet. Le format utilisé est indépendant du système d'exploitation. Ainsi, un objet sérialisé
sur un système peut être réutilisé par un autre système pour récréer l'objet.
L'ajout d'un attribut à l'objet est automatiquement pris en compte lors de la sérialisation. Attention toutefois, la
déserialisation de l'objet doit se faire avec la classe qui à été utilisée pour la sérialisation.
La sérialisation peut s'appliquer facilement à tous les objets.
17.1. Les classes et les interfaces de la sérialisation
La sérialisation définie l'interface Serializable et les classes ObjectOutputStream et ObjectInputStream
17.1.1. L'interface Serializable
Cette interface ne définie aucune méthode mais permet simplement de marquer une classe comme pouvant être sérialisée.
Tout objet qui doit être sérialiser doit implémenter cette interface ou une de ses classes mères doit l'implémenter.
Si l'on tente de sérialiser un objet qui n'implémente pas l'interface Serializable, une exception NotSerializableException
est levée.
Exemple ( code java 1.1 ) : une classe serializable possédant trois attributs
public class Personne implements .Serializable {
  private String nom = "";
  private String prenom = "";
  private int taille = 0;
  public Personne(String nom, String prenom, int taille) {
    = nom;
    this.taille = taille;
    this.prenom = prenom;
  }
  public String getNom() {
    return nom;
  }
  public void setNom(String nom) {
Développons en Java
218

    = nom;
  }
  public int getTaille() {
    return taille;
  }
  public void setTaille(int taille) {
    this.taille = taille;
  }
  public String getPrenom() {
    return prenom;
  }
  public void setPrenom(String prenom) {
    this.prenom = prenom;
  }
}
17.1.2. La classe ObjectOuputStream
Cette classe permet de sérialiser un objet.
Exemple ( code java 1.1 ) : sérialisation d'un objet et enregistrement sur le disque dur
import .*;
public class SerializerPersonne {
  public static void main(String argv[]) {
    Personne personne = new Personne("Dupond","Jean",175);
    try {
      FileOutputStream fichier = new FileOutputStream("");
      ObjectOutputStream oos = new ObjectOutputStream(fichier);
      oos.writeObject(personne);
      oos.flush();
      oos.close();
    }
    catch (.IOException e) {
      e.printStackTrace();
    }
  }
}   
On définit un fichier avec la classe FileOutputStream. On instancie un objet de classe ObjectOutputStream en lui
fournissant en paramètre le fichier : ainsi, le résultat de la sérialisation sera envoyé dans le fichier.
On appel la méthode writeObject en lui passant en paramètre l'objet à sérialiser. On appelle la méthode flush() pour vider
le tampon dans le fichier et la méthode close() pour terminer l'opération.
Lors de ces opérations une exception de type IOException peut être levée si un problème intervient avec le fichier.
Après l'exécution de cet exemple, un fichier nommé « » est créé. On peut visualiser sont contenu mais
surtout pas le modifier car sinon il serait corrompu. En effet, les données contenue dans ce fichier ne sont pas toutes au
format caractères.
La classe ObjectOutputStream contient aussi plusieurs méthodes qui permettent de sérialiser des types élémentaires et
non des objets : writeInt, writeDouble, writeFloat ...
Il est possible dans un même flux d'écrire plusieurs objets les uns à la suite des autres. Ainsi plusieurs objets peuvent être
sauvegardés. Dans ce cas, il faut faire attention de relire les objets dans leur ordre d'écriture.
Développons en Java
219

17.1.3. La classe ObjectInputStream
Cette classe permet de déssérialiser un objet.
Exemple ( code java 1.1 ) :
import .*;
public class DeSerializerPersonne {
  public static void main(String argv[]) {
    try {
      FileInputStream fichier = new FileInputStream("");
      ObjectInputStream ois = new ObjectInputStream(fichier);
      Personne personne = (Personne) ois.readObject();
      .println("Personne : ");
      .println("nom : "+personne.getNom());
      .println("prenom : "+personne.getPrenom());
      .println("taille : "+personne.getTaille());
    } 
    catch (.IOException e) {
      e.printStackTrace();
    }
    catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
   }
}
Résultat :
C:\dej>java DeSerializerPersonne
Personne :
nom : Dupond
prenom : Jean
taille : 175
On créer un objet de la classe FileInputStream qui représente le fichier contenant l'objet sérialisé. On créer un objet de
type ObjectInputStream en lui passant le fichier en paramètre. Un appèle à la méthode readObject() retourne l'objet avec
un type Object. Un cast est nécessaire pour obtenir le type de l'objet. La méthode close() permet de terminer l'opération.
Si la classe a changée entre le moment ou elle a été sérialisée et le moment ou elle est déserialisée, une exception est
levée :
Exemple : la classe Personne est modifiée et recompilée
C:\temp>java DeSerializerPersonne
.InvalidClassException: Personne; Local class not compatible: stream class
desc serialVersionUID=?2739669178469387642 local class serialVersionUID=39870587
36962107851
.ObjectStreamClass.validateLocalClass(:4
38)
at .ObjectStreamClass.setClass(:482)
at .ObjectInputStream.inputClassDescriptor(
:785)
at .ObjectInputStream.readObject(:353)
at .ObjectInputStream.readObject(:232)
at .ObjectInputStream.inputObject(:978)
at .ObjectInputStream.readObject(:369)
at .ObjectInputStream.readObject(:232)
at (:9)
Développons en Java
220

Une exception de type StreamCorruptedException peut être levée si le fichier a été corrompu par exemple en le
modifiant avec un éditeur.
Exemple : les 2 premiers octets du fichier ont été modifiés avec un éditeur hexa
C:\temp>java DeSerializerPersonne
.StreamCorruptedException: InputStream does not containa serialized object
at .ObjectInputStream.readStreamHeader(:731)
at .ObjectInputStream.<init>(:165)
at (:8)
Une exception de type ClassNotFoundException peut être levée si l'objet est transtypé vers une classe qui n'existe plus ou
pas au moment de l'exécution.
Exemple ( code java 1.1 ) :
C:\temp>rename Personne.class Personne2.class
C:\temp>java DeSerializerPersonne
.ClassNotFoundException: Personne
at .ObjectInputStream.inputObject(:981)
at .ObjectInputStream.readObject(:369)
at .ObjectInputStream.readObject(:232)
at (:9)
La classe ObjectInputStream possède de la même façon que la classe ObjectOutputStream des méthodes pour lire des
données de type primitives : readInt(), readDouble(), readFloat ...
Lors de la deserialisation, le constructeur de l'objet n'est jamais utilisé.
17.2. Le mot clé transient
Le contenu des attributs sont visibles dans le flux dans lequel est sérialisé l'objet. Il est ainsi possible pour toute personne
ayant accès au flux de voir le contenu de chaque attribut même si ceux si sont private. Ceci peut poser des problèmes de
sécurité surtout si les données sont sensibles.
Java introduit le mot clé transient qui précise que l'attribut qu'il qualifie ne doit pas être inclus dans un processus de
serailisation et donc de deserialisation.
Exemple ( code java 1.1 ) :
...
private transient String codeSecret;
...
Lors de la deserialisation, les champs transient sont initialisé avec la valeur null. Ceci peut poser des problèmes à l'objet
qui doit gérer cette état pour éviter d'avoir des exceptions de type NullPointerException.
Développons en Java
221

17.3. La sérialisation personnalisée
Il est possible de personnaliser la serialisation d'un objet. Dans ce cas, la classe doit implémenter l'interface
Externalizable qui hérite de l'interface Serializable.
17.3.1. L'interface Externalizable
Cette interface définie deux méthode : readExternal() et writeExternal().
Par défaut, la serialisation d'un objet qui implémente cette interface ne prend en compte aucun attribut de l'objet.
Remarque : le mot clé transient est donc inutile avec un classe qui implémente l'interface Externalisable
La suite de cette section sera développée dans une version future de ce document
Développons en Java
222

18. L'interaction avec le réseau
18.1. Introduction
Depuis son origine, Java fournit plusieurs classes et interfaces destinées à faciliter l'utilisation du réseau par
programmation.
Le modèle OSI (Open System Interconnection) propose un découpage en sept couches des différents composants qui
permettent la communication sur un réseau.
Couche
Représentation physique ou logicielle
Application
Netscape ou Internet Explorer ou une application
Présentation
Window, Mac OS ou Unix
Session
WinSock, MacTCP
Transport
TCP / UDP
Réseau
IP
Liaison
PPP, ethernet
Physique
Les cables et les cartes électroniques
Le protocole IP est un protocole de niveau réseau qui permet d'échanger des paquets d'octets appelés datagrammes. Ce
protocole ne garantit pas l'arrivée à bon port des messages. Cette fonctionnalité peut être implémentée par la couche
supérieure, comme par exemple avec TCP. Un datagramme IP est l'unité de transfert à ce niveau. Cette série d'octets
contient les informations du message, un en tête (adresse source de destination, ...). mais aussi des informations de
contrôle. Ces informations permettent aux routeurs de faire transiter les paquets sur l'internet.
La couche de transport est implémentée dans les protocoles UDP ou TCP. Ils permettent la communication entre des
applications sur des machines distantes.
La notion de service permet à une même machine d'assurer plusieurs communications simultanément.
Le système des sockets est le moyen de communication inter?processus développé pour l'Unix Berkeley (BSD). Il est
actuellement implémenté sur tous les systèmes d'exploitation utilisant TCP/IP. Une socket est le point de communication
par lequel un thread peut émettre ou recevoir des informations et ainsi elle permet la communication entre deux
applications à travers le réseau.
La communication se fait sur un port particulier de la machine. Le port est une entité logique qui permet d'associer un
service particulier à une connection. Un port est identifié par un entier de 1 à 65535. Par convention les 1024 premiers
sont réservés pour des services standards (80 : HTTP, 21 : FTP, 25: SMTP, ...)
Java prend en charge deux protocoles : TCP et UDP.
Les classes et interfaces utilent au développement réseau sont regroupés dans le package .
Développons en Java
223

18.2. Les adresses internet
Une adresse internet permer d'identifier de façon unique une machine sur un réseau. Cette adresse pour le protocole I.P.
est sous la forme de quatre octets séparés chacun par un point. Chacun des ces octets appartient à une classe selon
l'étendue du réseau.
Pour faciliter la compression humaine, un serveur particulier appelé DNS (Domaine Name Service) est capable d'associer
un nom à une adresse I.P.
18.2.1. La classe InetAddress
Une adresse internet est composée de quatre octets séparés chacun par un point.
Un objet de la classe InetAddress représente une adresse Internet. Elle contient des méthodes pour lire une adresse, la
comparer avec une autre ou la convertir en chaine de caractères. Elle ne possède pas de constructeur : il faut utiliser
certaines méthodes statiques de la classe pour obtenir une instance de cette classe.
La classe InetAdress encapsule des fonctionnalités pour utiliser les adresses internet. Elle ne possède pas de constructeur
mais propose trois méthodes statiques :
Méthode
Rôle
InetAddress getByName(String)
Renvoie l'adresse internet associée au nom d'hote fourni en paramètre
InetAddress[]
Renvoie un tableau des adresses internet associées au nom d'hote fourni en
getAllByName(String)
paramètre
InetAddress getLocalHost()
Renvoie l'adresse internet de la machine locale
byte[] getAddress()
Renvoie un tableau contenant les 4 octets de l'adresse internet
String getHostAddress()
Renvoie l'adresse internet sous la forme d'une chaine de caractères
String getHostName()
Renvoie le nom du serveur
Exemple :
import .*;
public class TestNet1 {
  public static void main(String[] args) {
        try {
      InetAddress adrLocale = InetAddress.getLocalHost(); 
      .println("Adresse locale = "+adrLocale.getHostAddress());
      InetAddress adrServeur = InetAddress.getByName(""); 
      .println("Adresse Sun = "+adrServeur.getHostAddress());
      InetAddress[] adrServeurs = InetAddress.getAllByName("");
      .println("Adresses Microsoft : ");
      for (int i = 0; i <adrServeurs.length; i++) {
        .println("     "+adrServeurs[i].getHostAddress());
      }
        } catch (Exception e) {
          e.printStackTrace();  
        }
  }
}
Résultat :
Adresse locale = 192.166.23.103
Adresse Sun = 192.18.97.71
Développons en Java
224

Adresses Microsoft : 
     207.46.249.27
     207.46.134.155
     207.46.249.190
     207.46.134.222
     207.46.134.190
18.3. L'accès aux ressources avec une URL
Une URL (Uniform Resource Locator) ou locateur de ressource uniforme est une chaine de caractères qui désigne un
ressource précise accessible par Internet ou Intranet. Une URL est donc une référence à un objet dont le format dépend
du protocol utilisé pour accéder à la ressource.
Dans le cas du protocol http, l'URL est de la forme :
http://<serveur>:<port>/<chemin>?<param1>&<param2>
Elle se compose du protocole (HTTP), d'une adresse IP ou du nom de domaine du serveur de destination, avec
éventuellement un port, un chemin d'accès vers un fichier ou un nom de service et éventuellement des paramètres sous la
forme clé=valeur.
Dans le cas du protocol ftp, l'URL est de la forme :
ftp://<user>:<motdepasse>@<serveur>:<port>/<chemin>
Dans le cas d'un e?mail, l'URL est de la forme
mailto:<email>
Dans le cas d'un fichier local, l'URL est de la forme :
file://<serveur>/<chemin>
Elle se compose de la désignation du serveur (non utilisé dans le cas du système de fichier local) et du chemin absolu de
la ressource.
18.3.1. La classe URL
Un objet de cette classe encapsule une URL : la validité syntaxique de l'URL est assurée mais l'existence de la ressource
représentée part l'URL ne l'est pas.
Exemple d'URL :
http: :80
Dans l'exemple, http represente le protocole, représente le serveur, 80 représente le port,
représente la ressource.
Le nom du protocole indique au navigateur le protocole qui doit être utilisé pour accéder à la ressource. Il existe plusieurs
protocoles sur internet : http, ftp, smtp ...
L'identification du serveur est l'information qui désigne une machine sur le réseau, identifiée par une adresse IP. Cette
adresse s'écrit sous la forme de quatre entiers séparés par un point. Une machine peut se voir affecter un nom logique
(hostname) composé d'un nom de machine (ex : www), d'un nom de sous domaine (ex : toto) et d'un nom de domaine (ex
:fr). Chaque domaine possède un serveur de nom (DNS : Domain Name Server) chargé d'effectuer la correspondanre
entre les noms logiques et les adresses IP.
Développons en Java
225

Le numéro de port désigne le service. En mode client/serveur, un client s'adresse à un programme particulier (le service)
qui s'éxécute sur le serveur. Le numéro de port identifie ce service. Cette information est facultative dans l'URL : par
exemple si aucun numéro n'est précisé dans une url, un browser dirige sa demande vers un port standard : par défaut, le
service http est associé au port 80, le service ftp au port 21, etc ...
L'identification de la ressource indique le chemin d'accès de celle ci sur le serveur.
Le constructeur de la classe lève une exception du type MalformedURLException si la syntaxe de l'URL n'est pas
correcte.
Les objets créés sont constants et ne peuvent plus être modifiés par la suite.
Exemple :
 URL pageURL = null;
  try { 
    pageURL = new URL(getDocumentBase( ), ""); 
  } catch (MalformedURLException mue) {} 
La classe URL possède des getters pour obtenir les différents éléments qui composent l'URL : getProtocole(), getHost(),
getPort(), getFile().
La méthode openStream() ouvre un flux de données en entrée pour lire la ressource et renvoie un objet de type
InputStream.
La méthode openConnection ouvre une connexion vers la ressource et renvoie un objet de type URLConnexion
18.3.2. La classe URLConnection
Cette classe abstraite encapsule une connexion vers une ressource désignée par une URL pour obtenir un flux de données
ou des informations sur la ressource.
Exemple :
import .*;
import .*;
public class TestURLConnection {
        public static void main(String[] args) {
                String donnees;
                try {
                        URL monURL = new URL("");
                        URLConnection connexion = monURL.openConnection();
                        InputStream flux = connexion.getInputStream();
                        int donneesALire = connexion.getContentLength();
                        for(;donneesALire != 0; donneesALire??)
                        .print((char)());
                        // Fermeture de la connexion
                        flux.close();
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
Développons en Java
226

}
Pour cet exemple, le fichier doit être accessible via le serveur web dans le répertoire "fichiers".
18.3.3. La classe URLEncoder
Cette classe est une classe utilitaire qui propose la méthode statique encode() pour encoder une URL. Elle remplace
notamment les espaces par un signe "+" et les caractères spéciaux par un signe "%" suivi du code du caractère.
Exemple :
import .*;
public class TestEncodeURL {
  public static void main(String[] args) {
        String url = " perso/mon ";
        .println(URLEncoder.encode(url));
  }
}
Résultat :

Depuis le JDK 1.4, il existe une version surchargée de la méthode encode() qui nécessite le passage d'un paramètre
supplémentaire : une chaine de caractère qui précise le format d'encodage des caractères. Cette méthode remplace
l'ancienne méthode encode() qui est dépréciée. Elle peut lever une exception du type UnsupportedEncodingException.
Exemple (JDK 1.4) :
import .UnsupportedEncodingException;
import .*;
public class TestEncodeURL {
  public static void main(String[] args) {
        try {
        String url = " perso/mon ";
        .println(URLEncoder.encode(url,"UTF?8"));
        .println(URLEncoder.encode(url,"UTF?16"));
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        }
  }
}
Développons en Java
227

Résultat :


18.3.4. La classe HttpURLConnection
Cette classe qui hérite de URLConnection encapsule une connexion utilisant le protocole HTTP.
Exemple :
import .*;
import .*;
public class TestHttpURLConnection {
  public static void main(String[] args) {
    HttpURLConnection connexion = null;
   try {
    URL url = new URL("");
    .println("Connexion a l'url ...");
    connexion = (HttpURLConnection) url.openConnection();
    connexion.setAllowUserInteraction(true);
    DataInputStream in = new DataInputStream(connexion.getInputStream());
      if (connexion.getResponseCode() != HttpURLConnection.HTTP_OK) {
        .println(connexion.getResponseMessage());
      } else {
        while (true) {
          .print((char) in.readUnsignedByte());
        }
      }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
      connexion.disconnect();
      }
    (0);
  }
}
18.4. Utilisation du protocole TCP
TCP est un protocole qui permet une connection de type point à point entre deux applications. C'est un protocole fiable
qui garantit la réception dans l'ordre d'envoi des données. En contre partie, ce protocole offre de moins bonne
performance mais c'est le prix à payer pour la fiabilité.
TCP utilise la notion de port pour permettre à plusieurs applications d'utiliser TCP.
Dans une liaison entre deux ordinateurs, l'un des deux joue le rôle de serveur et l'autre celui de client.
Développons en Java
228

18.4.1. La classe SocketServer
La classe ServerSocket est utilisée côté serveur : elle attend simplement les appels du ou des clients. C'est un objet du
type Socket qui prend en charge la transmission des données.
Cette classe représente la partie serveur du socket. Un objet de cette classe est associé à un port sur lequel il va attendre
les connexions d'un client. Généralement, à l'arrivée d'une demande de connexion, un thread est lancé pour assurer le
dialogue avec le client sans bloquer les connexions des autres clients.
La classe SocketServer possède plusieurs constructeur dont les principaux sont :
Constructeur
Rôle
ServerSocket()
Constructeur par défaut
ServerSocket(int)
Créer une socket sur le port fourni en paramètre
ServerSocket(int, int)
Créer une socket sur le port avec la taille maximale de la file fourni en paramètre
Tous ces constructeurs peuvent lever une exception de type IOException.
La classe SocketServer possède plusieurs méthodes :
Méthode
Rôle
Socket accept()
Attendre une nouvelle connexion
void close()
Fermer la socket
Si un client tente de communiquer avec le serveur, la méthode accept() renvoie une socket qui encapsule la
communication avec ce client.
Le mise en oeuvre de la classe SocketServer suit toujours la même logique :
créer une instance de la classe SocketServer en précisant le port en paramètre
• 
définir une boucle sans fin contenant les actions ci dessous
• 
appelle de la méthode accept() qui renvoie une socket lors d'une nouvelle connexion
• 
obtenir un flux en entrée et en sortie à partir de la socket
• 
écrire les traitements à réaliser
• 
Exemple (java1.2) :
import .*;
import .*;
public class TestServeurTCP {
  final static int port = 9632;
  public static void main(String[] args) {
    try {
      ServerSocket socketServeur = new ServerSocket(port);
      .println("Lancement du serveur");
      while (true) {
        Socket socketClient = socketServeur.accept();
        String message = "";
        .println("Connexion avec : "+socketClient.getInetAddress());
        // InputStream in = socketClient.getInputStream();
        // OutputStream out = socketClient.getOutputStream();
        BufferedReader in = new BufferedReader(
          new InputStreamReader(socketClient.getInputStream()));
        PrintStream out = new PrintStream(socketClient.getOutputStream());
        message = in.readLine();
        out.println(message);
Développons en Java
229

        socketClient.close();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
L'inconvenient de ce modèle est qu'il ne peut traiter qu'une connection en même temps. Pour pouvoir traiter plusieurs
connexions simultanément, il faut créer un nouveau thread contenant les traitements à réaliser sur la socket.
Exemple (java 1.2) :
import .*;
import .*;
public class TestServeurThreadTCP extends Thread {
  final static int port = 9632;
  private Socket socket;
  public static void main(String[] args) {
    try {
      ServerSocket socketServeur = new ServerSocket(port);
      .println("Lancement du serveur");
      while (true) {
        Socket socketClient = socketServeur.accept();
        TestServeurThreadTCP t = new TestServeurThreadTCP(socketClient);
        t.start();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  public TestServeurThreadTCP(Socket socket) {
    this.socket = socket;
  }
  public void run() {
    traitements();
  }
  public void traitements() {
    try {
      String message = "";
      .println("Connexion avec le client : " + socket.getInetAddress());
      BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      PrintStream out = new PrintStream(socket.getOutputStream());
      message = in.readLine();
      out.println("Bonjour " + message);
      socket.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Développons en Java
230

18.4.2. La classe Socket
Les sockets implémentent le protocole TCP (Transmission Control Protocol). La classe contient les méthodes de création
des flux d'entrée et de sortie correspondants. Les sockets constituent la base des communications par le réseau.
Comme les flux Java sont transformés en format TCP/IP, il est possible de communiquer avec l'ensemble des ordinateurs
qui utilisent ce même protocole. La seule chose importante au niveau du système d'exploitation est qu'il soit capable de
gérer ce protocole.
Cette classe encapsule la connexion à une machine distante via le réseau. Cette classe gère la connexion, l'envoie de
données, la réception de données et la déconnexion.
La classe Socket possède plusieurs constructeur dont les principaux sont :
Constructeur
Rôle
Server()
Constructeur par défaut
ServerSocket(String, int)
Créer une socket sur la machine dont le nom et le port sont fournis en paramètre
ServerSocket(InetAddress, int) Créer une socket sur la machine dont l'adresse IP et le port sont fournis en paramètre
La classe Socket possède de nombreuses méthodes :
Méthode
Rôle
InetAddress getInetAddress()
Renvoie l'adresse I.P. à laquelle la socket est connectée
void close()
Fermer la socket
InputStream getInputStream()
Renvoie un flux en entrée pour recevoir les données de la socket
OutputStream getOutputStream()
Renvoie un flux en sortie pour émettre les données de la socket
int getPort()
Renvoie le port utilisé par la socket
Le mise en oeuvre de la classe Socket suit toujours la même logique :
créer une instance de la classe Socket en précisant la machine et le port en paramètre
• 
obtenir un flux en entrée et en sortie
• 
écrire les traitements à réaliser
• 
Exemple :
import .*;
import .*;
public class TestClientTCP {
  final static int port = 9632;
  public static void main(String[] args) {
    Socket socket;
    DataInputStream userInput;
    PrintStream theOutputStream;
    try {
      InetAddress serveur = InetAddress.getByName(args[0]);
      socket = new Socket(serveur, port);
      BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
      PrintStream out = new PrintStream(socket.getOutputStream());
Développons en Java
231

      out.println(args[1]);
      .println(in.readLine());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
18.5. Utilisation du protocole UDP
UDP est un protocole basé sur IP qui permet une connection de type point à point ou de type multi?point. C'est un
protocole qui ne garantie pas l'envoie dans l'ordre fournie des données. En contre partie, ce protocole offre de bonne
performance car il est très rapide.
C'est un protocole qui ne garantit pas la transmission correcte des données et qui devrait donc être réservé à des taches
peu importantes. Ce protocole est en revanche plus rapide que le protocole TCP.
Pour assurer les échanges, UDP utilise la notion de port, ce qui permet à plusieurs applications d'utiliser UDP sans que
les échanges interfaire les uns avec les autres. Cette notion est similaire à la notion de port utilisé par TCP.
UDP est utilisé dans de nombreux services "standards" tel que echo (port 7), DayTime (13), etc ...
L'échange de données avec UDP se fait avec deux sockets, l'une sur le serveur, l'autre sur le client. Chaque socket est
caractérisée par une adresse internet et un port.
Pour utiliser le protocole UDP, java défini deux classes DatagramSocket et DatagramPacket.
18.5.1. La classe DatagramSocket
Cette classe créé un Socket qui utilise le protocole UDP (Unreliable Datagram Protocol) pour émettre ou recevoir des
données.
Cette classe possède plusieurs constructeurs :
Constructeur
Rôle
Créé une socket attachée à toutes les adresses IP de la machine et un à des port
DatagramSocket()
libre sur la machine
Créé une socket attachée à toutes les adresses IP de la machine et au port précisé
DatagramSocket(int)
en paramètre
DatagramSocket(int, InetAddress)
Créé une socket attachée à adresse IP et au port précisés en paramètre
Tous les constructeurs peuvent lever une exception de type SocketException : en particulier, si le port précisé est déjà
utilisé lors de l'instanciation de l'objet DatagramSocket, une exception de type BindException est levée. Cette exception
hérite de SocketException.
La classe DatagramSocket définit plusieurs méthodes :
Méthode
Rôle
close()
Fermer la Socket et ainsi libérer le port
receive(DatagramPacket)
Recevoir des données
send(DatagramPacket)
Envoyer des données
Développons en Java
232

int getPort()
Renvoie le port associé à la socket
void setSoTimeout(int)
Préciser un timeout d'attente pour la réception d'un message.
Par défaut, un objet DatagramSocket ne possède pas de timeout lors de l'utilisation de la méthode receive(). La méthode
bloque donc l'éxécution de l'application jusqu'à la réception d'un packet de données. La méthode setSoTimeout() permet
de préciser un timeout en millisecondes. Une fois ce délai écoulé sans réception d'un paquet de données, la méthode lève
une exception du type SocketTimeoutException.
18.5.2. La classe DatagramPacket
Cette classe encapsule une adresse internet, un port et les données qui sont échangées grâce à un objet de type
DatagramSocket. Elle possède plusieurs constructeurs pour encapsuler des paquets émis ou reçus.
Constructeur
Rôle
Encapsule des paquets en réception dans un
DatagramPacket(byte tampon[], int taille)
tampon
DatagramPacket(byte port[], int taille, InetAddress adresse, int
Encapsule des paquets en émission à destination
port)
d'une machine
Cette classe propose plusieurs méthodes pour obtenir ou mettre à jour les informations sur le paquet encapsulé.
Méthode
Rôle
InetAddress getAddress ()
Renvoie l'adresse du serveur
byte[] getData()
Renvoie les données contenues dans le paquet
int getPort ()
Renvoie le port
int getLength ()
Renvoie la taille des données contenues dans le paquet
setData(byte[])
Mettre à jour les données contenues dans le paquet
Le format des données échangées est un tableau d'octets, il faut donc correctement initialiser la propriété length qui
représente la taille du tableau pour un paquet émis et utiliser cette propriété pour lire les données dans un paquet reçu.
18.5.3. Un exemple de serveur et de client
L'exemple suivant est très simple : un serveur attend un nom d'utilisateur envoyé sur le port 9632. Dès qu'un message lui
est envoyé, il renvoie à son expéditeur "bonjour" suivi du nom envoyé.
Exmple : le serveur
import .*;
import .*;
public class TestServeurUDP {
  final static int port = 9632;
  final static int taille = 1024;
  static byte buffer[] = new byte[taille];
  public static void main(String argv[]) throws Exception {
    DatagramSocket socket = new DatagramSocket(port);
    String donnees = "";
    String message = "";
Développons en Java
233

    int taille = 0;
    .println("Lancement du serveur");
    while (true) {
      DatagramPacket paquet = new DatagramPacket(buffer, buffer.length);
      DatagramPacket envoi = null;
      socket.receive(paquet);
      .println("\n"+paquet.getAddress());
      taille = paquet.getLength();
      donnees = new String(paquet.getData(),0, taille);
      .println("Donnees reçues = "+donnees);
      message = "Bonjour "+donnees;
      .println("Donnees envoyees = "+message);
      envoi = new DatagramPacket(message.getBytes(), 
        message.length(), paquet.getAddress(), paquet.getPort());
      (envoi);
    }
  }
}
Exemple : le client
import .*;
import .*;
public class TestClientUDP {
  final static int port = 9632;
  final static int taille = 1024;
  static byte buffer[] = new byte[taille];
  public static void main(String argv[]) throws Exception {
    try {
      InetAddress serveur = InetAddress.getByName(argv[0]);
      int length = argv[1].length();
      byte buffer[] = argv[1].getBytes();
      DatagramSocket socket = new DatagramSocket();
      DatagramPacket donneesEmises = new DatagramPacket(buffer, length, serveur, port);
      DatagramPacket donneesRecues = new DatagramPacket(new byte[taille], taille);
      socket.setSoTimeout(30000);
      (donneesEmises);
      socket.receive(donneesRecues);
      .println("Message : " + new String(donneesRecues.getData(), 
        0, donneesRecues.getLength()));
      .println("de : " + donneesRecues.getAddress() + ":" + 
        donneesRecues.getPort());
    } catch (SocketTimeoutException ste) {
      .println("Le delai pour la reponse a expire");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Pour utiliser le client, il faut connaitre l'adresse internet de la machine sur laquelle le serveur. L'appel du client nécessite
de fournir en paramètre l'adresse internet du serveur et le nom de l'utilisateur.
Exécution du client
C:\>java TestClientUDP "Michel"
.UnknownHostException: :
        at .InetAddress.getAllByName0(:948)
        at .InetAddress.getAllByName0(:918)
        at .InetAddress.getAllByName(:912)
Développons en Java
234

        at .InetAddress.getByName(:832)
        at (:12)
C:\>java TestClientUDP 192.168.25.101 "Michel"
Le delai pour la reponse a expire
C:\>java TestClientUDP 192.168.25.101 "Michel"
Message : Bonjour Michel
de : /192.168.25.101:9632
18.6. Les exceptions liées au réseau
Le package définit plusieurs exceptions :
Exception
BindException
Connection au port local impossible : le port est peut être déjà utilisé
ConnectException
Connection à une socket impossible : aucun serveur n'écoute sur le port précisé
MalformedURLException
L'URL n'est pas valide
NoRouteToHostException
Connection à l'hote impossible : un firewall empeche la connexion
ProtocolException
SocketException
SocketTimeoutException
Délai d'attente pour le reception ou l'émission des données écoulé
UnknownHostException
L'adresse IP de l'hote n'a pas pu être trouvée
UnknownServiceException
URISyntaxException
18.7. Les interfaces de connexions au réseau
Le J2SE 1.4 ajoute une nouvelle classe qui encapsule une interface de connexion au réseau et qui permet d'obtenir la liste
des interfaces de connexion au réseau de la machine. Cette classe est la classe NetworkInterface.
Une interface de connexion au réseau se caractérise par un nom court, une désignation et une liste d'adresses IP. La
classe possède des getters sur chacun de ces éléments :
Méthode
Rôle
String getName()
Renvoie le nom de court de l'interface
String getDisplayName()
Renvoie la désignation de l'interface
Enumeration
Renvoie une énumération d'objet InetAddress contenant la liste des adresses IP
getInetAddresses()
associée à l'interface
Cette classe possède une méthode statique getNetwotkInterfaces() qui renvoie une énumeration contenant des objets de
type NetworkInterface encapsulant les différentes interfaces présentes dans la machine.
Développons en Java
235

Exemple :
import .*;
import .*;
public class TestNetworkInterface {
  public static void main(String[] args) {
    try {
      TestNetworkInterface.getLocalNetworkInterface();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  private static void getLocalNetworkInterface() throws SocketException, NoClassDefFoundError {
    Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
    while (interfaces.hasMoreElements()) {
      NetworkInterface ni;
      Enumeration adresses;
      ni = (NetworkInterface) interfaces.nextElement();
      .println("Network interface : ");
      .println("  nom court    = " + ni.getName());
      .println("  désignation  = " + ni.getDisplayName());
      adresses = ni.getInetAddresses();
      while (adresses.hasMoreElements()) {
        InetAddress ia = (InetAddress) adresses.nextElement();
        .println("  adresse I.P. = " + ia);
      }
    }
  }
}
Résultat :
Network interface : 
  nom court    = MS TCP Loopback interface
  désignation  = lo
  adresse I.P. = /127.0.0.1
Network interface : 
  nom court    = Carte Realtek Ethernet à base RTL8029(AS)(Générique)
  désignation  = eth0
  adresse I.P. = /169.254.166.156
Network interface : 
  nom court    = WAN (PPP/SLIP) Interface
  désignation  = ppp0
  adresse I.P. = /193.251.70.245
Développons en Java
236

19. L'accès aux bases de données : JDBC
JDBC est l'acronyme de Java DataBase Connectivity et désigne une API définie par Sun pour permettre un accès aux
bases de données avec Java.
Ce chapitre présente dans plusieurs sections l'utilisation de cette API :
19.1. Les outils nécessaires pour utiliser JDBC
• 
19.2. Les types de pilotes JDBC
• 
19.3. Enregistrer une base de données dans ODBC
• 
19.4. Présentation des classes de l'API JDBC
• 
19.5. La connection à une base de données
• 
19.6. Accéder à la base de données
• 
19.6.1. Execution de requète SQL

19.6.2. La classe ResultSet

19.6.3. Exemple complet de maj à jour et de sélection sur une table

19.7. Obtenir des informations sur la base de données
• 
19.8. L'utilisation d'un objet PreparedStatement
• 
19.9. L'utilisation des transactions
• 
19.10. Les procédures stockées
• 
19.11. Le traitement des erreurs JDBC
• 
19.12. JDBC 2.0
• 
19.12.1. Les fonctionnalités de l'objet ResultSet

19.12.2. Les mises à jour de masse (Batch Updates)

19.12.3. Le package

19.12.4. La classe DataSource

19.12.5. Les pools de connection

19.12.6. Les transactions distribuées

19.12.7. L'API RowSet

19.13. JDBC 3.0
• 
19.14. MySQL et Java
• 
19.14.1. Installation sous windows

19.14.2. Utilisation de MySQL

19.14.3. Utilisation de MySQL avec java via ODBC

19.14.3.1. Déclaration d'une source de données ODBC vers la base de données

19.14.3.2. Utilisation de la source de données

19.14.4. Utilisation de MySQL avec java via un pilote JDBC

19.1. Les outils nécessaires pour utiliser JDBC
Les classes de JDBC version 1.0 sont regroupées dans le package et sont incluses dans le JDK à partir de sa
version 1.1. La version 2.0 de cette API est incluse dans la version 1.2 du JDK.
Pour pouvoir utiliser JDBC, il faut un pilote qui est spécifique à la base à laquelle on veut accéder. Avec le JDK, Sun
fournit un pilote qui permet l'accès aux bases de données via ODBC.
Ce pilote permet de réaliser l'indépendance de JDBC vis à vis des bases de données.
Développons en Java
237

Pour utiliser le pont JDBC?ODBC sous Window 9x, il faut utiliser ODBC en version 32 bits.
19.2. Les types de pilotes JDBC
Il existe quatre types de pilote JDBC :
Type 1 ( JDBC?ODBC bridge ) : le pont JDBC?ODBC qui s'utilise avec ODBC et un pilote ODBC spécifique
1. 
pour la base à accéder. Cette solution fonctionne très bien sous Windows. C'est la solution idéale pour des
développements avec exécution sous Windows d'une application locale. Cette solution « simple » pour le
développement possède plusieurs inconvenients :
la multiplication du nombre de couche rend complexe l'architecture (bien que transparent pour le

développeur) et détériore un peu les performances
lors du deploiement, ODBC et son pilote doivent etre installé sur tous les postes ou l'application va

fonctionner.
la partie native (ODBC et son pilote) rend l'application moins portable et dépendant d'une plateforme.

Type 2 : un driver écrit en java qui appelle l'API native de la base de données
2. 
Ce type de driver convertit les ordres JDBC pour appeler directement les API de la base de données via un
pilote natif sur le client. Ce type de driver nécessite aussi l'utilisation de code natif sur le client.
Type 3 : un driver écrit en Java utilisant le protocole natif de la base de données
3. 
Ce type de driver utilise un protocole réseau propriétaire spécifique à un base de données. Un serveur dédié
reçoit les messages par ce protocole et dialogue directement avec la base de données. Ce type de driver peut être
facilement utilisé par une applet mais dans ce cas le serveur intermédiaire doit obligatoirement etre installé sur
la machine contenant le serveur web.
Type 4 : un driver Java natif
4. 
Ce type de driver, écrit en java, appelle directement le SGBD par le réseau. Ils sont fournis par l'éditeur de la
base de données.
Les drivers se présentent souvent sous forme de fichiers jar dont le chemin doit être ajouté au classpath pour permettre au
programme de l'utiliser.
19.3. Enregistrer une base de données dans ODBC sous Windows 9x
ou XP

Pour utiliser un pilote de type 1 (pont ODBC?JDBC) sous Windows 9x, il est nécessaire d'enregistrer la base de données
dans ODBC avant de pouvoir l'utiliser.
Attention : ODBC n'est pas fourni en standard avec Windows 9x.
Pour enregistrer une nouvelle base de données, il faut utiliser l'administrateur de source de données ODBC.
Pour lancer cet application sous Windows 9x, il faut doubler cliquer sur l'icône "ODBC 32bits" dans le panneau de
configuration.
Développons en Java
238

Sous Windows XP, il faut double cliquer sur l'icône "Source de données (ODBC)" dans le répertoire "Outils
d'administration" du panneau de configuration.
L'outils se compose de plusieurs onglets.
L'onglet "Pilote ODBC" liste l'ensemble des pilotes qui sont installés sur la machine.
L'onglet "Source de données utilisateur" liste l'ensemble des sources de données pour l'utilisateur courament connecté
sous Windows.
L'onglet "Source de données système" liste l'ensemble des sources de données accessible par tous les utilisateurs.
Le plus simple est de créer une telle source de données en cliquant sur le bouton "Ajouter". Une boite de dialogue permet
sélectionner le pilote qui sera utilisé par la source de donées.
Développons en Java
239

Il suffit de sélectionner le pilote et de cliquer sur "Terminer". Dans l'exemple ci dessous, le pilote sélectionné concerne
une base Microsoft Access.
Il suffit de saisir les informations nécessaire notamment le nom de la source de données et de sélectionner la base. Un
clic sur "Ok" créé la source de données qui pourra alors être utilisée.
19.4. Présentation des classes de l'API JDBC
Toutes les classes de JDBC sont dans le package . Il faut donc l'importer dans tous les programmes devant utiliser
JDBC.
Exemple ( code java 1.1 ) :
import .*;
Développons en Java
240

Il y a 4 classes importantes : DriverManager, Connection, Statement ( et PreparedStatement ), et ResultSet, chacunes
correspondant à une étape de l'accès aux données :
Classe
Role
DriverManager
charge et configure le driver de la base de données.
Connection
réalise la connection et l'authentification à la base de données.
Statement ( et PreparedStatement )
contient la requète SQL et la transmet à la base de données.
permet de parcourir les informations retournées par la base de données
ResultSet
dans le cas d'une sélection de données
Chacunes de ces classes dépend de l'instanciation d'un objet de la précédente classe.
19.5. La connection à une base de données
19.5.1. Le chargement du pilote
Pour se connecter à une base de données via ODBC, il faut tout d'abord charger le pilote JDBC?ODBC qui fait le lien
entre les deux.
Exemple ( code java 1.1 ) :
Class.forName(".JdbcOdbcDriver");
Pour se connecter à une base en utilisant un driver spécifique, la documentation du driver fournit le nom de la classe à
utiliser. Par exemple, si le nom de la classe est jdbc.DriverXXX, le chargement du driver se fera avec le code suivant :
Class.forName("jdbc.DriverXXX");
Exemple ( code java 1.1 ) : Chargement du pilote pour un base PostgreSQL sous Linux
Class.forName("postgresql.Driver");
Il n'est pas nécessaire de créer une instance de cette classe et de l'enregistrer avec le DriverManager car l'appel à
Class.forName le fait automatiquement : ce traitement charge le pilote et créer une instance de cette classe.
La méthode static forName() de la classe Class peut lever l'exception .ClassNotFoundException.
19.5.2. L'établissement de la connection
Pour se connecter à une base de données, il faut instancier un objet de la classe Connection en lui précisant sous forme
d'URL la base à accéder.
Exemple ( code java 1.1 ) : Etablir une connexion sur la base testDB via ODBC
String DBurl = "jdbc:odbc:testDB";
Développons en Java
241

con = DriverManager.getConnection(DBurl);
La syntaxe URL peut varier d'un type de base de données à l'autres mais elle est toujours de la forme :
protocole:sous_protocole:nom
« jbdc » désigne le protocole est vaut toujours « jdbc ». « odbc » désigne le sous protocole qui définit le mécanisme de
connection pour un type de bases de données.
Le nom de la base de données doit être celui saisie dans le nom de la source sous ODBC.
La méthode getConnection() peut lever une exception de la classe .SQLException.
Le code suivant décrit la création d'une connection avec un user et un mot de passe :
Exemple ( code java 1.1 ) :
Connection con = DriverManager.getConnection(url, "myLogin", "myPassword");
A la place de " myLogin " ; il faut mettre le nom du user qui se connecte à la base et mettre son mot de passe à la place
de "myPassword "
Exemple ( code java 1.1 ) :
String url = "jdbc:odbc:factures";
Connection con = DriverManager.getConnection(url, "toto", "passwd");
La documentation d'un autre driver indiquera le sous protocole à utiliser ( le protocole à mettre derrière jdbc dans l'URL).
Exemple ( code java 1.1 ) : Connection à la base PostgreSQL nommée test avec le user jumbo et le mot de passe 12345
sur la machine locale
Connection con=DriverManager.getConnection("jdbc:postgresql://localhost/test","jumbo","12345");
19.6. Accéder à la base de données
Une fois la connection établie, il est possible d'éxécuter des ordres SQL. Les objets qui peuvent être utilisés pour obtenir
des informations sur la base de données sont :
Classe
Role
informations à propos de la base de données : nom des tables, index,
DatabaseMetaData
version ...
résultat d'une requète et information sur une table. L'accès se fait
ResultSet
enregistrement par enregistrement.
ResultSetMetaData
informations sur les colonnes (nom et type) d'un ResultSet
Développons en Java
242

19.6.1. L'execution de requètes SQL
Les requètes d'interrogation SQL sont éxécutées avec les méthodes d'un objet Statement que l'on obtient à partir d'un
objet Connection
Exemple ( code java 1.1 ) :
ResultSet résultats = null;
String requète = "SELECT * FROM client";
try {
   Statement stmt = con.createStatement();
   résultats = stmt.éxécuteQuery(requète);
} catch (SQLException e) {
   //traitement de l'exception
}
Un objet de la classe Statement permet d'envoyer des requetes SQL à la base. Le création d'un objet Statement s'effectue
à partir d'une instance de la classe Connection :
Exemple ( code java 1.1 ) :
Statement stmt = con.createStatement();
Pour une requete de type interrogation (SELECT), la méthode à utiliser de la classe Statement est éxécuteQuery. Pour
des traitements de mise à jour, il faut utiliser la méthode éxécuteUpdate. Lors de l'appel à la méthode d'exécution, il est
nécessaire de lui fournir en paramètre la requete SQL sous forme de chaine.
Le résultat d'une requète d'intérrogation est renvoyé dans un objet de la classe ResultSet par la méthode executeQuery().
Exemple ( code java 1.1 ) :
ResultSet rs = stmt.éxécuteQuery("SELECT * FROM employe");
La méthode executeUpdate() retourne le nombre d'enregistrement qui ont été mis à jour
Exemple ( code java 1.1 ) :
...
//insertion d'un enregistrement dans la table client
requète = "INSERT INTO client VALUES (3,'client 3','prenom 3')";
try {
   Statement stmt = con.createStatement();
   int nbMaj = stmt.éxécuteUpdate(requète);
   affiche("nb mise a jour = "+nbMaj);
} catch (SQLException e) {
   e.printStackTrace();
}
...
Lorsque la méthode executeUpdate() est utilisée pour éxécuter un traitement de type DDL ( Data Defiition Langage :
définition de données ) comme la création d'un table, elle retourne 0. Si la méthode retourne 0, cela peut signifier deux
choses : le traitement de mise à jour n'a affecté aucun enregistrement ou le traitement concernait un traitement de type
DDL.
Développons en Java
243

Si l'on utilise éxécuteQuery pour éxécuter une requète SQL ne contenant pas d'ordre SELECT, alors une exception de
type SQLException est levée.
Exemple ( code java 1.1 ) :
...
requète = "INSERT INTO client VALUES (4,'client 4','prenom 4')";
try {
   Statement stmt = con.createStatement();
   ResultSet résultats = stmt.éxécuteQuery(requète);
} catch (SQLException e) {
   e.printStackTrace();
}
...
résultat :
.SQLException: No ResultSet was produced
.Throwable(.String)
.Exception(.String)
.SQLException(.String)
.ResultSet .JdbcOdbcStatement.éxécuteQuery(.String)
void (.String [])
Attention : dans ce cas la requète est quand même effectuée. Dans l'exemple, un nouvel enregistrement est
créé dans la table.
Il n'est pas nécessaire de définir un objet Statement pour chaque ordre SQL : il est possible d'un définir un et de le
réutiliser
19.6.2. La classe ResultSet
C'est une classe qui représente une abstraction d'une table qui se compose de plusieurs enregistrements constitués de
colonnes qui contiennent les données.
Les principales méthodes pour obtenir des données sont :
Méthode
Role
retourne le contenu de la colonne dont le numéro est passé en
getInt(int)
paramètre sous forme d'entier.
retourne le contenu de la colonne dont le nom est passé en paramètre
getInt(String)
sous forme d'entier.
retourne le contenu de la colonne dont le numéro est passé en
getFloat(int)
paramètre sous forme de nombre flottant.
getFloat(String)
retourne le contenu de la colonne dont le numéro est passé en
getDate(int)
paramètre sous forme de date.
getDate(String)
se déplace sur le prochain enregistrement : retourne false si la fin est
next()
atteinte
Close()
ferme le ResultSet
Développons en Java
244

getMetaData()
retourne un objet ResultSetMetaData associé au ResultSet.
La méthode getMetaData() retourne un objet de la classe ResultSetMetaData qui permet d'obtenir des informations sur le
résultat de la requète. Ainsi, le nombre de colonne peut être obtenu grace à la méthode getColumnCount de cet objet.
Exemple ( code java 1.1 ) :
ResultSetMetaData rsmd;
rsmd = results.getMetaData();
nbCols = rsmd.getColumnCount();
La méthode next() déplace le curseur sur le prochain enregistrement. Le curseur pointe initialement juste avant le premier
enregistrement : il est nécessaire de faire un premier appel à la méthode next() pour ce placer sur le premier
enregistrement.
Des appels successifs à next permettent de parcourir l'ensemble des enregistrements.
Elle retourne false lorsqu'il n'y a plus d'enregistrement. Il faut toujours protéger le parcours d'une table dans un bloc de
capture d'exception
Exemple ( code java 1.1 ) :
//parcours des données retournées
try {
   ResultSetMetaData rsmd = résultats.getMetaData();
   int nbCols = rsmd.getColumnCount();
   boolean encore = ré();
   while (encore) {
      for (int i = 1; i <= nbCols; i++)
         .print(résultats.getString(i) + " ");
      .println();
      encore = ré();
   }
   résultats.close();
} catch (SQLException e) {
   //traitement de l'exception
}
Les méthodes getXXX() permettent d'extraire les données selon leur type spécifiée par XXX tel que getString(),
getDouble(), getInteger(), etc ... . Il existe deux formes de ces méthodes : indiquer le numéro la colonne en paramètre (en
commençant par 1) ou indiquer le nom de la colonne en paramètre. La première méthode est plus efficace mais peut
générer plus d'erreurs à l'éxecution notamment si la structure de la table évolue.
Attention : il est important de noter que ce numéro de colonne fourni en paramètre fait référence au numéro
de colonne de l'objet resultSet ( celui correspondant dans l'ordre SELECT )et non au numéro de colonne de
la table.
La méthode getString() permet d'obtenir la valeur d'un champ de n'importe quel type.
19.6.3. Exemple complet de mise à jour et de sélection sur une table
Exemple ( code java 1.1 ) :
Développons en Java
245

import .*;
public class TestJDBC1 {
   private static void affiche(String message) {
      .println(message);
   }
   private static void arret(String message) {
      .println(message);
      (99);
   }
   public static void main(.String[] args) {
      Connection con = null;
      ResultSet résultats = null;
      String requète = "";
      // chargement du pilote
      try {
         Class.forName(".JdbcOdbcDriver");
      } catch (ClassNotFoundException e) {
         arret("Impossible de charger le pilote jdbc:odbc");
      }
      //connection a la base de données
      affiche("connection a la base de données");
      try {
         String DBurl = "jdbc:odbc:testDB";
         con = DriverManager.getConnection(DBurl);
      } catch (SQLException e) {
         arret("Connection à la base de données impossible");
      }
      //insertion d'un enregistrement dans la table client 
      affiche("creation enregistrement");
      requète = "INSERT INTO client VALUES (3,'client 3','client 4')";
      try {
         Statement stmt = con.createStatement();
         int nbMaj = stmt.éxécuteUpdate(requète);
         affiche("nb mise a jour = "+nbMaj);
      } catch (SQLException e) {
          e.printStackTrace();
      }
      //creation et execution de la requète
      affiche("creation et execution de la requète");
      requète = "SELECT * FROM client";
      try {
         Statement stmt = con.createStatement();
         résultats = stmt.éxécuteQuery(requète);
      } catch (SQLException e) {
         arret("Anomalie lors de l'execution de la requète");
      }
      //parcours des données retournées
      affiche("parcours des données retournées");
      try {
         ResultSetMetaData rsmd = résultats.getMetaData();
         int nbCols = rsmd.getColumnCount();
         boolean encore = ré();
         while (encore) {
            for (int i = 1; i <= nbCols; i++)
               .print(résultats.getString(i) + " ");
            .println();
            encore = ré();
         }
Développons en Java
246

         résultats.close();
      } catch (SQLException e) {
         arret(e.getMessage());
      }
      affiche("fin du programme");
      (0);
   }
}
résultat :
connection a la base de données
creation enregistrement
nb mise a jour = 1
creation et execution de la requète
parcours des données retournées
1.0 client 1 prenom 1 
2.0 client 2 prenom 2 
3.0 client 3 client 4 
fin du programme
19.7. Obtenir des informations sur la base de données
19.7.1. La classe ResultSetMetaData
La méthode getMetaData() d'un objet ResultSet retourne un objet de typeResultSetMetaData. Cet objet permet de
connaître le nombre, le nom et le types des colonnes
Méthode
Role
int getColumnCount()
retourne le nombre de colonnes du ResultSet
String getColumnName(int)
retourne le nom de la colonne dont le numéro est donné
String getColumnLabel(int)
retourne le libellé de la colonne donnée
boolean isCurrency(int)
retourne true si la colonne contient un nombre au format monétaire
boolean isReadOnly(int)
retourne true si la colonne est en lecture seule
boolean isAutoIncrement(int)
retourne true si la colonne est auto incrémentée
int getColumnType(int)
retourne le type de données SQL de la colonne
19.7.2. La classe DatabaseMetaData
Un objet de la classe DatabaseMetaData permet d'obtenir des informations sur la base de données dans son ensemble :
nom des tables, nom des colonnes dans une table, méthodes SQL supportées
Méthode
Role
retourne la liste du catalogue d'informations ( Avec le pont
ResultSet getCatalogs()
JDBC?ODBC, on obtient la liste des bases de données
enregistrées dans ODBC).
retourne une description de toutes les tables correspondant
ResultSet getTables(catalog, schema, tableNames,
au TableNames donné et à toutes les colonnes
columnNames)
correspondantes à columnNames).
Développons en Java
247

ResultSet getColumns(catalog, schema, tableNames,
retourne une description de toutes les colonnes
columnNames)
correspondantes au TableNames donné et à toutes les
colonnes correspondantes à columnNames).
String getURL()
retourne l'URL de la base à laquelle on est connecté
String getDriverName()
retourne le nom du driver utilisé
La méthode getTables() de l'objet DataBaseMetaData demande quatre arguments :
getTables(catalog, schema, tablemask, types[]);
catalog : le nom du catalogue dans lequel les tables doivent être recherchées. Pour une base de données
• 
JDBC?ODBC, il peut être mis à null.
schema : le schéma de la base données à inclure pour les bases les supportant. Il est en principe mis à null
• 
tablemask : un masque décrivant les noms des tables à retrouver. Pour les retrouver toutes, il faut l'initialiser
• 
avec la caractères '%'
types[] : tableau de chaines décrivant le type de tables à retrouver. La valeur null permet de retrouver toutes les
• 
tables.
Exemple ( code java 1.1 ) :
con = DriverManager.getConnection(url);
dma =con.getMetaData();
String[] types = new String[1];
types[0] = "TABLES"; //set table type mask
results = dma.getTables(null, null, "%", types);
boolean more = ();
while (more) {
   for (i = 1; i <= numCols; i++)
      .print(results.getString(i)+" ");
   .println();
   more = ();
}
19.8. L'utilisation d'un objet PreparedStatement
L’interface PreparedStatement définie les méthodes pour un objet qui va encapsuler une requête pré?compilée.  Ce type
de requète est particulièrement adaptée pour une exécution répétée d’une même requète avec des paramètres différents.
Cette interface héritent de l’interface Statement.
Lors de l’utilisation d’un objet de type PreparedStatement, la requete est envoyée au moteur de la base de données pour
que celui ci prépare son exécution.
Un  objet qui implémente l’interface PreparedStatement est obtenu en utilisant la méthode preparedStatement() d’un
objet de type Connection. Cette méthode attent en paramètre une chaine de caractères contenant la requète SQL. Dans
cette chaine, chaque paramètre est représenté par un caractère ?.
Un ensemble de méthode setXXX() (ou XXX représente un type primitif ou certains objets tel que String, Date, Object,
...) permet de fournir les valeurs de chaque paramètre défini dans la requête. Le premier paramètre de ces méthodes
précise le numéro du paramètres dont la méthode va fournir la valeur. Le second paramètre précise cette valeur.
Développons en Java
248

La suite de cette section sera développée dans une version future de ce document
19.9. L'utilisation des transactions
Une transaction permet de ne valider un ensemble de traitements sur le base de données que si ils se sont tous effectués
correctement.
Par exemple, une opération bancaire de transfert de fond d'un compte vers un autre oblige à la réalisation de l'opération
de débit sur un compte et de l'opération de crédit sur l'autre compte. La réalisation d'une seule de ces opérations laisserait
la base de données dans un état inconsistant.
Une transaction est un mécanisme qui permet de s'assurer que toutes les opérations qui la compose seront réellement
effectuées.
Une transaction est gérée à partir de l'objet Connection. Par défaut, une connection est en mode auto?commit. Dans ce
mode, chaque opération est validée unitairement pour formé la transaction.
Pour pouvoir rassembler plusieurs traitements dans une transaction, il faut tout d'abord désactiver le mode auto?commit.
La classe Connection possède la méthode setAutoCommit() qui attend un boolean qui précise le mode fonctionnement.
Exemple :
connection.setAutoCommit(false);
Une fois le mode auto?commit désactivé, un appel à la méthode commit() de la classe Connection permet de valider la
transaction courante. L'appel à cette méthode valide la transaction courante et créé implicitement une nouvelle
transaction.
Si une anomalie intervient durant la transaction, il est possible de faire un retour en arrière pour revenir à la situation de
la base de données au début de la transaction en appellant la méthode rollback() de la classe Connection.
19.10. Les procédures stockées
Cette section sera développée dans une version future de ce document
19.11. Le traitement des erreurs JDBC
JDBC permet de voir les avertissements et les exceptions générées par la base de données.
La classe SQLException représente les erreurs émises par la base de données. Elle contient trois attributs qui permettent
de préciser l'erreur :
message : contient une description de l'erreur
• 
SQLState : code définie par la norme ANSI 92
• 
ErrorCode : le code d'erreur du fournisseur du pilote
• 
La classe SQLException possède une méthode getNextException() qui permet d'obtenir les autres exceptions levées
durant la requête. La méthode renvoie null une fois la dernière exception renvoyée.
Développons en Java
249

La suite de cette section sera développée dans une version future de ce document
19.12. JDBC 2.0
La version 2.0 de l'API JDBC a été intégrée au JDK 1.2. Cette nouvelle version apporte plusieurs fonctionnalités très
intéréssantes dont les principales sont :
support du parcours dans les deux sens des résultats
• 
support de la mise à jour des résultats
• 
possibilité de faire des mise à jour de masse (Batch Updates)
• 
prise en compte des champs défini par SQL?3 dont BLOB et CLOB
• 
JDBC 2.0 est séparé en deux parties :
la partie principale (core API) contient les classes et interfaces nécessaires à l'utilisation de bases de données :
• 
elles sont regroupées dans le package
la seconde partie est une extension utilisée dans J2EE qui permet de gérer les transactions distribuées, les pools
• 
de connection, la connection avec un objet DataSource ... Les classes et interfaces sont regroupées dans le
package
19.12.1. Les fonctionnalités de l'objet ResultSet
Les possibilités de l'objet ResultSet dans le version 1.0 de JDBC sont très limitées : parcours séquentiel de chaque
occurence de la table retournée.
La version 2.0 apporte de nombreuses améliorations à cet objet : le parcours des occurences dans les deux sens et la
possibilité de faire des mises à jour sur une occurence.
Concernant le parcours, il est possible de préciser trois mode des fonctionnement :
forward?only : parcours sequentiel de chaque occurence (.ResultSet.TYPE_FORWARD_ONLY)
• 
scroll?insensitive : les occurences ne refletent pas les mises à jour qui peuvent intervenir durant le parcours
• 
(.ResultSet.TYPE_SCROLL_INSENSITIVE)
scroll?sensitive : les occurences refletent les mises à jour qui peiuvent intervenir durant le parcours
• 
(.ResultSet.TYPE_SCROLL_SENSITIVE)
Il est aussi possible de préciser si le ResultSet peut être mise à jour ou non :
.ResultSet.CONCUR_READ_ONLY : lecture seule
• 
.resultSet.CONCUR_UPDATABLE : mise à jour
• 
C'est la création d'un objet de type Statement qu'il faut préciser ces deux modes. Si aucun des deux modes n'est précisé,
ce sont les caractéristiques de la version 1.0 de JDBC qui sont utilisés (TYPE_FORWARD_ONLY et
CONCUR_READ_ONLY).
Exemple ( code jdbc 2.0 ) :
 Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
    ResultSet.CONCUR_READ_ONLY);
  ResultSet resultSet = statement.executeQuery("SELECT nom, prenom FROM employes");
Développons en Java
250

Le suuport de ces fonctionnalités est optionnel pour un pilote. L'objet DatabaseMetadata possède la méthode
supportsResultSetType() qui attend en paramètre u constante sui représente une caractéristique : la méthode renvoie un
booléen qui indique si la caractéristique est supportée ou non.
A la création du ResultSet, le curseur pour son parcours est positionné avant la première occurence à traiter. Pour
sedéplacer dans l'ensemble des occurences, il y a toujours la méthode next() pour se déplacer sur le suivant mais aussi
plusieurs autres méthodes pour permettre le parcours des occurences en fonctions du mode utilisé dont les principales
sont :
Méthode
Rôle
booleen qui indique si la position courante du curseur se trouve avant la
boolean isBeforeFirst()
première ligne
booleen qui indique si la position courante du curseur se trouve après la
boolean isAfterLast()
dernière ligne
boolean isFirst()
booleen qui indique si le curseur est positionné sur la première ligne
boolean isLast()
booleen qui indique si le curseur est positionné sur la dernière ligne
boolean first()
déplacer le curseur sur la première ligne
boolean last()
déplacer le curseur sur la dernière ligne
déplace le curseur sur la ligne dont le numéro est fournie en paramètre à
boolean absolute()
partir du début si il est positif et à partir de la fin si il est négatif. 1 déplace
sur la première ligne, ?1 sur la dernière, ?2 sur l'avant dernière ...
déplacer le curseur du nombre de lignes fourni en paramètre par rapport à la
position courante du curseur. Le paramètre doit être négatif pour se
boolean relative(int)
déplacer vers le début et positif pur se déplacer vers la fin. Avant l'appel de
cette méthode, il faut obligatoirement que le curseur soit positionné sur une
ligne.
déplacer le curseur sur la ligne précédente. Le booleen indique si la
boolean previous()
première occurence est dépassée.
void afterLast()
déplacer le curseur après la dernière ligne
void beforeFirst()
deplacer le curseur avant la première ligne
int getRow()
renvoie le numero de la ligne courante
Exemple ( code jdbc 2.0 ) :
 Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
    ResultSet.CONCUR_READ_ONLY);
  ResultSet resultSet = statement.executeQuery(
    "SELECT nom, prenom FROM employes ORDER BY nom");
  resultSet.afterLast();
  while (resultSet.previous()) {
    .println(resultSet.getString("nom")+
      " "+resultSet.getString("prenom"));
  }
Durant le parcours d'un ResultSet, il est possible d'effectuer des mises à jour sur la ligne courante du curseur. Pour cela, il
faut déclarer l'objet ResultSet comme acceptant les mise à jour. Avec les versions précédentes de JDBC, il fallait utiliser
la méthode executeUpdate() avec une requète SQL.
Développons en Java
251

Maitenant pour réaliser ces mises à jour, JDBC 2.0 propose de les réaliser via des appels de méthodes plutôt que d'utiliser
des requêtes SQL.
Méthode
Rôle
permet de mettre à jour la colonne dont le nom est fourni en paramètre. Le
updateXXX(String, XXX)
type java de cette colonne est XXX
permet de mettre à jour la colonne dont l'index est fourni en paramètre. Le
updateXXX(int, XXX)
type java de cette colonne est XXX
permet d'actualiser les modifications réalisées avec des appels à
updateRow()
updateXXX()
boolean rowsUpdated()
indique si la ligne courante aété modifiée
deleteRow()
Supprimer la ligne courante
rowDeleted()
indique si la ligne courante est supprimée
moveToInsertRow()
permet de créer une nouvelle ligne dans l'ensemble de résultat
inserRow()
permet de valider la création de la ligne
Pour réaliser une mise à jour dans la ligne courante désignée par le curseur, il faut utiliser une des méthodes
updateXXX() sur chacun des champs à modifier. Une fois toutes les modifications faites dans une ligne, il faut appeler la
méthode updateRow() pour reporter ces modifications dans la base de données car les méthodes updateXXX() ne font
des mises à jour que dans le jeu de résultats. Les mises à jour sont perdues si un changement de ligne intervient avant
l'appel à la méthode updateRow().
La méthode cancelRowUpdates() permet d'annuler toutes les modifications faites dans la ligne. L'appel à cette méthode
doit être effectué avant l'appel à la méthode updateRow().
Pour insérer une nouvelle ligne dans le jeu de résultat, il faut tout d'abord appeler la méthode moveToInsertRow(). Cette
méthode déplace le curseur vers un buffer dédié à la création d'une nouvelle ligne. Il faut alimenter chacun des champs
nécessaires dans cette nouvelle ligne. Pour valider la création de cette nouvelle ligne, il faut appeler la méthode
insertRow().
Pour supprimer la ligne courante, il faut appeler la méthode deleteRow(). Cette méthode agit sur le jeu de résultats et sur
la base de données.
19.12.2. Les mises à jour de masse (Batch Updates)
JDBC 2.0 permet de réaliser des mises à jour de masse en regroupant plusieurs traitements pour les envoyer en une seule
fois au SGBD. Ceci permet d'améliorer les performances surtout si le nombre de traitements est important.
Cette fonctionnalité n'est pas obligatoirement supportée par le pilote. La méthode supportsBatchUpdate() de la classe
DatabaseMetaData permet de savoir si elle est utilisable avec le pilote.
Plusieurs méthodes ont été ajoutées à l'interface Statement pour pouvoir utiliser les mises à jour de masse :
Méthode
Rôle
void addBatch(String)
Permet d'ajouter une chaîne contenant une requete SQL
int[] executeBatch()
Cette méthode permet d'éxécuter toutes les requètes. Ell renvoit un
Développons en Java
252

tableau d'entier qui contient pour chaque requète, le nombre de mises
à jour affectuées.
void clearBatch()
Supprimer toutes les requètes stockées
Lors de l'utilisation de batchupdate, il est préférable de positionner l'attribut autocommit à false afin de faciliter la gestion
des transactions et le traitement d'une erreur dans l'execution d'un ou plusieurs traitements.
Exemple ( code jdbc 2.0 ) :
 connection.setAutoCommit(false);
  Statement statement = connection.createStatement();
  for(int i=0; i<10 ; i++) {
     statement.addBatch("INSERT INTO personne VALUES('nom"+i+"','prenom"+i+"')");
  }
  statement.executeBatch();
Une exception particulière peut être levée en plus de l'exception SQLException lors de l'éxécution d'une mise à jour de
masse. L'exception SQLException est levée si une requète SQL d'intérogation doit être éxécutée (requête de type
SELECT). L'exception BatchUpdateException est levée si une des requêtes de mise à jour échoue.
L'exception BatchUpdateException possède une méthode getUpdateCounts() qui renvoie un tableau d'entier qui contient
le nombre d'occurence impacté par chaque requète reussie.
19.12.3. Le package
Ce package est une extension à l'API JDBC qui propose des fonctionnalités pour les développements coté serveur. C'est
pour cette raison, que cette extension est uniquement intégré à J2EE.
Les principales fonctionnalités proposées sont :
une nouvelle interface pour assurer la connection : l'interface DataSource
• 
les pools de connections
• 
les transactions distribuées
• 
l'API Rowset
• 
DataSource et Rowset peuvent être utilisé directement. Les pools de connections et les transactions distribuées sont
utilisés par les serveurs d'applications pour fournir ces services.
19.12.4. La classe DataSource
La classe DataSource propose de fournir une meilleure alternative à la classe DriverManager pour assurer la connection à
une base de données.
Elle représente une connection physique à une base de données. Les fournisseurs de pilotes proposent une
implémentation de l'interface DataSource.
L'utilisation d'un objet DataSource est obligatoire pour pouvoir utiliser un pools de connection et les transactions
distribuées.
Développons en Java
253

La suite de cette section sera développée dans une version future de ce document
19.12.5. Les pools de connection
Un pool de connections permet de maintenir un ensemble de connections établies vers une base de données qui sont
réutilisables. L'établissement d'une connection est très couteux. L'intérêt du pool de connections est de limiter le nombre
de ces créations et ainsi d'améliorer les performances surtout si le nombre de connections est important.
La suite de cette section sera développée dans une version future de ce document
19.12.6. Les transactions distribuées
Les connections obtenues à partir d'un objet DataSource peuvent participer à une transactions distribuées.
La suite de cette section sera développée dans une version future de ce document
19.12.7. L'API RowSet
Cette section sera développée dans une version future de ce document
19.13. JDBC 3.0
La version 3.0 de l'API JDBC a été intégrée au JDK 1.4 SE.
La suite de cette section sera développée dans une version future de ce document
Développons en Java
254

19.14. MySQL et Java
MySQL est une des bases de données open source les plus populaire.
19.14.1. Installation sous windows
dans un repertoire et d'éxécuter le fichier
Il faut ensuite downloader le pilote ODBC, MyODBC?, et l'éxécuter
Développons en Java
255

19.14.2. Utilisation de MySQL
Cette section est une présentation rapide de quelques fonctionnalités de base pour pouvoir utiliser MySQL. Pour un
complément d'information sur toutes les possibilités de MySQL, consulter la documentation de cet excellent outils.
S'assurer que le serveur est lancé sinon executer la command c:\mysql\bin\mysqld?max
Pour executer des commandes SQL, il faut utiliser l'outils c:\mysql\bin\mysql. Cet outils est un interpreteur de
commandes.
Exemple : pour voir les databases existantes
mysql>show databases;
+??????????+
| Database |
+??????????+
| mysql    |
| test     |
+??????????+
2 rows in set (0.00 sec)
Un des premières choses à faire, c'est de créer une base de données qui va recevoir les différentes tables.
Exemple : Pour créer une nouvelle base de données nommée ‘testjava'
mysql> create database testjava;
Query OK, 1 row affected (0.00 sec)
mysql>use testjava;
Database changed
Cette nouvelle, base de données ne contient aucune table. Il faut créer la ou les tables utiles aux développements.
Développons en Java
256

Exemple : Création d'une table nommée personne contenant trois champs : nom, prenom et date de naissance
mysql> show tables;
Empty set (0.06 sec)
mysql> create table personne (nom varchar(30), prenom varchar(30), datenais date
);
Query OK, 0 rows affected (0.00 sec)
mysql>show tables;
+????????????????????+
| Tables_in_testjava |
+????????????????????+
| personne           |
+????????????????????+
1 row in set (0.00 sec)
Pour voir la définition de la table il faut utiliser la commande DESCRIBE :
Exemple : voir la définition de la table
mysql> describe personne;
+??????????+?????????????+??????+?????+?????????+???????+
| Field    | Type        | Null | Key | Default | Extra |
+??????????+?????????????+??????+?????+?????????+???????+
| nom      | varchar(30) | YES  |     | NULL    |       |
| prenom   | varchar(30) | YES  |     | NULL    |       |
| datenais | date        | YES  |     | NULL    |       |
+??????????+?????????????+??????+?????+?????????+???????+
3 rows in set (0.00 sec)
Cette table ne contient aucun enregistrement. Pour ajouter un enregistrement, il faut utiliser la command SQL insert.
Exemple : insertion d'une ligne dans la table
mysql> select * from personne;
Empty set (0.00 sec)
mysql> insert into personne values ('Nom 1','Prenom 1','1970?08?11');
Query OK, 1 row affected (0.05 sec)
mysql> select * from personne;
+???????+??????????+????????????+
| nom   | prenom   | datenais   |
+???????+??????????+????????????+
| Nom 1 | Prenom 1 | 1970?08?11 |
+???????+??????????+????????????+
1 row in set (0.00 sec)
Il est existe des outils graphiques libres ou commerciaux pour faciliter l'administration et l'utilisation de MySQL.
19.14.3. Utilisation de MySQL avec java via ODBC
19.14.3.1. Déclaration d'une source de données ODBC vers la base de données
Dans le panneau de configuration, cliquer sur l'icône « Source de données ODBC ».
Le plus simple est de créer une source de données Systeme qui pourra être utilée par tous les utlisateurs en cliquant sur
l'onglet  DSN systeme
Développons en Java
257

Pour ajouter une nouvelle source de données, il suffit de cliquer sur le bouton "Ajouter". Une boîte de dialogue permet de
sélectionner le type de pilote qui sera utilisé par la source de données.
Il faut sélectionner le pilote mySQL et cliquer sur le bouton "Finish".
Développons en Java
258

Une nouvelle boîte de dialogue permet de renseigner les informations sur la base de données à utiliser notamment le nom
de DSN et le nom de la base de données.
Pour verifier si la connection est possible, il suffit de cliquer sur le bouton « Test Data Source »
Cliquer sur Ok pour fermer la fenetre et cliquer sur Ok pour valider les paramètres et créer la source de données.
Développons en Java
259

La source de données est créée.
19.14.3.2. Utilisation de la source de données
Pour utiliser la source de données, il faut écrire et tester une classe java
Exemple
import .*;
public class TestJDBC10 {
  private static void affiche(String message) {
    .println(message);
  }
  private static void arret(String message) {
    .println(message);
    (99);
  }
  public static void main(.String[] args) {
    Connection con = null;
    ResultSet resultats = null;
    String requete = "";
     // chargement du pilote
    try {
      Class.forName(".JdbcOdbcDriver");
    } catch (ClassNotFoundException e) {
      arret("Impossible de charger le pilote jdbc:odbc");
    }
    //connection a la base de données
    affiche("connection a la base de donnees");
    try {
      String DBurl = "jdbc:odbc:test_java";
      con = DriverManager.getConnection(DBurl);
    } catch (SQLException e) {
      arret("Connection à la base de donnees impossible");
    }
    //creation et execution de la requète
    affiche("creation et execution de la requète");
    requete = "SELECT * FROM personne";
    try {
      Statement stmt = con.createStatement();
      resultats = stmt.executeQuery(requete);
    } catch (SQLException e) {
      arret("Anomalie lors de l'execution de la requète");
    }
    //parcours des données retournees
    affiche("parcours des données retournees");
    try {
      ResultSetMetaData rsmd = resultats.getMetaData();
      int nbCols = rsmd.getColumnCount();
      boolean encore = ();
      while (encore) {
        for (int i = 1; i <= nbCols; i++)
          .print(resultats.getString(i) + "");
        .println();
        encore = ();
      }
      resultats.close();
    } catch (SQLException e) {
Développons en Java
260

      arret(e.getMessage());
    }
    affiche("fin du programme");
    (0);
  }
}
Resultat :
C:\$user>javac
C:\$user>java TestJDBC10
connection a la base de donnees
creation et execution de la requ_te
parcours des donn_es retournees
Nom 1 Prenom 1 1970?08?11
fin du programme
19.14.4. Utilisation de MySQL avec java via un pilote JDBC
mm.mysql est un pilote JDBC de type IV developpé sous licence LGPL par Mark Matthews pour accéder à une base de
données MySQL.
L e   d o w n l o a d   d u   p i l o t e   J D B C   s e   f a i t   s u r   l e   s i t e   h t t p : / / m m m y s q l . s o u r c e f o r g e . n e t /   .   L e   f i c h i e r
mm.mysql?2.0.14?you?must?unjar? contient les sources et les binaires du pilote.
Pour utiliser cette archive, il faut la décompresser, par exemple dans le répertoire d'installation de mysql.
S'assurer que les fichiers jar sont accessibles dans le classpath ou les préciser manuellement lors de la compilation et de
l'execution comme dans l'exemple ci dessous.
Exemple
import .*;
public class TestJDBC11 {
  private static void affiche(String message) {
    .println(message);
  }
  private static void arret(String message) {
    .println(message);
    (99);
  }
  public static void main(.String[] args) {
    Connection con = null;
    ResultSetresultats = null;
    String requete = "";
    // chargement du pilote
    try {
      Class.forName(".mysql.Driver").newInstance();
    } catch (Exception e) {
      arret("Impossible decharger le pilote jdbc pour mySQL");
    }
    //connection a la base de données
    affiche("connection a la base de donnees");
    try {
      String DBurl = "jdbc:mysql://localhost/testjava";
      con = DriverManager.getConnection(DBurl);
    } catch (SQLException e) {
      arret("Connection a la base de donnees impossible");
Développons en Java
261

    }
    //creation et execution de la requète
    affiche("creation et execution dela requète");
    requete = "SELECT * FROM personne";
    try {
      Statement stmt = con.createStatement();
      resultats = stmt.executeQuery(requete);
    } catch (SQLException e) {
      arret("Anomalie lors de l'execution de la requete");
    }
    //parcours des données retournees
    affiche("Parcours des donnees retournees");
    try {
      ResultSetMetaData rsmd = resultats.getMetaData();
      int nbCols = rsmd.getColumnCount();
      boolean encore = ();
      while (encore) {
        for (int i = 1; i <= nbCols; i++)
          .print(resultats.getString(i) + "");
        .println();
        encore = ();
      }
      resultats.close();
    } catch (SQLException e) {
      arret(e.getMessage());
    }
    affiche("fin du programme");
    (0);
  }
}
Le programme est identique au précédent utilisant ODBC sauf :
le nom de la classe du pilote
• 
l'URL de connectionà la base qui dépend du pilote
• 
Resultat :
C:\$user>javac ?classpath c:\j2sdk1.4.0?rc\jre\lib\mm.mysql?2.0.14?
C:\$user>
C:\$user>java ?cp .;c:\j2sdk1.4.0?rc\jre\lib\mm.mysql?2.0.14? TestJDBC11
connection a la base de donnees
creation et execution de la requ_te
Parcours des donnees retournees
Nom 1 Prenom 1 1970?08?11
fin du programme
Développons en Java
262

20. La gestion dynamique des objets et l'introspection
Depuis la version 1.1 de java, il est possible de créer et de gérer dynamiquement des objets.
L'introspection est un mécanisme qui permet de connaître le contenu d'une classe dynamiquement. Il permet notamment
de savoir ce que contient une classe sans en avoir les sources. Ces mécanismes sont largement utilisés dans des outils de
type  IDE (Integrated Development Environnement : environnement de développement intégré).
Pour illustrer ces différents mécanismes, ce chapitre va construire une classe qui proposera un ensemble de méthodes
pour obtenir des informations sur une classe.
Les différentes classes utiles pour l'introspection sont rassemblées dans le package .reflect.
Voici le début de cette classe qui attend dans son constructeur une chaîne de caractères précisant la classe sur laquelle
elle va travailler.
Exemple ( code java 1.1 ) :
import .*;
import .reflect.*;
public class ClasseInspecteur {
  private Class classe;
  private String nomClasse;
  public ClasseInspecteur(String nomClasse) {
    this.nomClasse = nomClasse;
    try {
      classe = Class.forName(nomClasse);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
20.1. La classe Class
Les instances de la classe Class sont des objets représentant les classes du langage. Il y aura une instance représentant
chaque classes utilisées : par exemple la classe String, la classe Frame, la classe Class, etc ... . Ces instances sont crées
automatiquement par la machine virtuelle lors du chargement de la classe. Il est ainsi possible de connaître les
caractéristiques d'une classe de façon dynamique en utilisant les méthodes de la classe Class. Les applications telles que
les debuggers, les inspecteurs d'objets et les environnement de développement doivent faire une analyse des objets qu'ils
manipulent en utilisant ces mécanismes.
La classe Class est définie dans le package .
La classe Class permet :
de décrire une classe ou une interface par introspection : obtenir son nom, sa classe mère, la liste de ces
• 
méthodes, de ses variables de classe, de ses constructeurs et variables d'instances, etc ...
Développons en Java
263

d'agir sur une classe en envoyant, à un objet Class des messages comme à tout autre objet. Par exemple, créer
• 
dynamiquement à partir d'un objet Class une nouvelle instance de la classe représentée
20.1.1. Obtenir un objet de la classe Class
La classe Class ne possède pas de constructeur public mais il existe plusieurs façons d'obtenir un objet de la classe Class.
20.1.1.1. Connaître la classe d'un objet
La méthode getClass() définit dans la classe Object renvoie une instance de la classe Class. Par héritage, tout objet java
dispose de cette méthode.
Exemple ( code java 1.1 ) :
package introspection;
public class TestGetClass {
   public static void main(.String[] args) {
      String chaine = "test";
      Class classe = chaine.getClass();
      .println("classe de l'objet chaine = "+classe.getName());
   }
}
Résultat :
classe de l'objet chaine = .String
20.1.1.2. Obtenir un objet Class à partir d'un nom de classe
La classe Class possède une méthode statique forName() qui permet à partir d'une chaîne de caractères désignant une
classe d'instancier un objet de cette classe et de renvoyer un objet de la classe Class pour cette classe.
Cette méthode peut lever l'exception ClassNotFoundException.
Exemple ( code java 1.1 ) :
public class TestForName {
   public static void main(.String[] args) {
      try {
         Class classe = Class.forName(".String");
         .println("classe de l'objet chaine = "+classe.getName());
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   }
}
Résultat :
classe de l'objet chaîne = .String
Développons en Java
264

20.1.1.3. Une troisième façon d'obtenir un objet Class
Il est possible d'avoir un objet de la classe Class en écrivant type.class ou type est le nom d'une classe.
Exemple ( code java 1.1 ) :
package introspection;
public class TestClass {
   public static void main(.String[] args) {
      Class c = Object.class;
      .println("classe de Object  = "+c.getName());
   }
}
Résultat :
classe de Object  = .Object
20.1.2. Les méthodes de la classe Class
La classe Class fournie de nombreuses méthodes pour obtenir des informations sur la classe qu'elle représente. Voici les
principales méthodes :
Méthodes
Rôle
Instancie un objet de la classe dont le nom est fourni en paramètre et renvoie
static Class forName(String)
un objet Class la représentant
Class[] getClasses()
Renvoie les classes et interfaces publiques qui sont membres de la classe
Constructor[] getConstructors()
Renvoie les constructeurs publics de la classe
Class[] getDeclaredClasses()
Renvoie un tableau des classes définies comme membre dans la classe
Constructor[] getDeclaredConstructors() Renvoie tous les constructeurs de la classe
Field[] getDeclaredFields()
Renvoie un tableau de tous les attributs définis dans la classe
Method getDeclaredMethods()
Renvoie un tableau de toutes les méthodes
Field getFields()
Renvoie un tableau des attributs publics
Class[] getInterfaces()
Renvoie un tableau des interfaces implémentées par la classe
Renvoie un tableau des methodes publiques de la classe incluant celles
Method getMethod()
héritées
Renvoie un entier qu'il faut décoder pour connaître les modificateurs de la
int getModifiers()
classe
Package getPackage()
Renvoie le package de la classe
Classe getSuperClass()
Renvoie la classe mère de la classe
boolean isArray()
Indique si la classe est un tableau
boolean IsInterface()
Indique si la classe est une interface
Object newInstance()
Permet de créer une nouvelle instance de la classe
Développons en Java
265

20.2. Rechercher des informations sur une classe
En utilisant les méthodes de la classe Class, il est possible d'obtenir quasiment toutes les informations sur une classe.
20.2.1. Rechercher la classe mère d'une classe
La classe Class  possède une méthode getSuperClass() qui retourne un objet de la classe Class représentant la classe mère
si elle existe sinon elle retourne null.
Pour obtenir toute la hiérarchie d'une classe il suffit d'appeler successivement cette méthode sur l'objet qu'elle a retourné.
Exemple ( code java 1.1 ) : méthode qui retourne un vecteur contenant les classes mères
  public Vector getClassesParentes() {
    Vector cp = new Vector();
    Class sousClasse = classe;
    Class superClasse;
    (sousClasse.getName());
    superClasse = sousClasse.getSuperclass();
    while (superClasse != null) {
      (0,superClasse.getName());
      sousClasse = superClasse;
      superClasse = sousClasse.getSuperclass();
    }
    return cp;
  }
20.2.2. Rechercher les modificateurs d'une classe
La classe Class possède une méthode getModifiers() qui retourne un entier représentant les modificateurs de la classe.
Pour décoder cette valeur, la classe Modifier possède plusieurs méthodes qui attendent cet entier en paramètre et qui
retourne un booléen selon leur fonction : isPublic, isAbstract, isFinal ...
La classe Modifier ne contient que des constantes et des méthodes statiques qui permettent de déterminer les
modificateurs d'accès :
Méthode
Rôle
boolean isAbstract(int)
Renvoie true si le paramètre contient le modificateur abstract
boolean isFinal(int)
Renvoie true si le paramètre contient le modificateur  final
boolean isInterface(int)
Renvoie true si le paramètre contient le modificateur interface
boolean isNative(int)
Renvoie true si le paramètre contient le modificateur native
boolean isPrivate(int)
Renvoie true si le paramètre contient le modificateur private
boolean isProtected(int)
Renvoie true si le paramètre contient le modificateur protected
boolean isPublic(int)
Renvoie true si le paramètre contient le modificateur public
boolean isStatic(int)
Renvoie true si le paramètre contient le modificateur static
boolean isSynchronized(int) Renvoie true si le paramètre contient le modificateur synchronized
boolean isTransient(int)
Renvoie true si le paramètre contient le modificateur transient
boolean isVolatile(int)
Renvoie true si le paramètre contient le modificateur volatile
Développons en Java
266

Ces méthodes étant static il est inutile d'instancier un objet de type Modifier pour utiliser ces méthodes.
Exemple ( code java 1.1 ) :
  public Vector getModificateurs() { 
    Vector cp = new Vector(); 
    int m = classe.getModifiers(); 
    if (Modifier.isPublic(m)) 
      ("public"); 
    if (Modifier.isAbstract(m)) 
      ("abstract"); 
    if (Modifier.isFinal(m)) 
      ("final"); 
    return cp; 
  }
20.2.3. Rechercher les interfaces implémentées par une classe
La classe Class  possède une méthode getInterfaces() qui retourne un tableau d'objet de type Class contenant les
interfaces implémentées par la classe.
Exemple ( code java 1.1 ) :
  public Vector getInterfaces() { 
    Vector cp = new Vector(); 
    Class[] interfaces = classe.getInterfaces(); 
    for (int i = 0; i < interfaces.length; i++) { 
      (interfaces[i].getName()); 
    } 
    return cp; 
  } 
20.2.4. Rechercher les champs publics
La classe Class possède une méthode getFields() qui retourne les attributs public de la classe. Cette méthode retourne un
tableau d'objet de type Field.
La classe Class possède aussi une méthode getField() qui attend en paramètre un nom d'attribut et retourne un objet de
type Field si celui ci est défini dans la classe ou dans une de ses classes mères. Si la classe ne contient pas d'attribut dont
le nom correspond au paramètre fourni, la méthode getField() lève une exception de la classe NoSuchFieldException.
La classe Field représente un attribut d'une classe ou d'une interface et permet d'obtenir des informations cet attribut. Elle
possède plusieurs méthodes :
Méthode
Rôle
String getName()
Retourne le nom de l'attribut
Class getType()
Retourne un objet de type Class qui représente le type de l'attribut
Class getDeclaringClass()
Retourne un objet de type Class qui représente la classe qui définie l'attribut
Retourne un entier qui décrit les modificateurs d'accès. Pour les connaître précisément il
int getModifiers()
faut utiliser les méthodes static de la classe Modifier.
Object get(Object)
Retourne la valeur de l'attribut pour l'instance de l'objet fourni en parameter. Il existe
aussi plusieurs méthodes getXXX() ou XXX représente un type primitf et qui la renvoie
Développons en Java
267

la valeur dans ce type.
Exemple ( code java 1.1 ) :
  public Vector getChampsPublics() { 
    Vector cp = new Vector(); 
    Field[] champs = classe.getFields(); 
    for (int i = 0; i < champs.length; i++) 
      (champs[i].getType().getName()+" "+champs[i].getName()); 
    return cp; 
  } 
20.2.5. Rechercher les paramètres d'une méthode ou d'un constructeurs
L'exemple ci dessous présente une méthode qui permet de formatter sous forme de chaîne de caractères les paramètres
d'une méthode fourni sous la forme d'un tableau d'objets Class.
Exemple ( code java 1.1 ) :
  private String rechercheParametres(Class[] classes) { 
    StringBuffer param = new StringBuffer("("); 
    for (int i = 0; i < classes.length; i ++) { 
      param.append(formatParametre(classes[i].getName())); 
      if (i < classes.length ? 1)  
        param.append(", "); 
    } 
    param.append(")"); 
    return param.toString(); 
  } 
La méthode getName() de la classe Class renvoie une chaîne de caractères formatées qui précise le type de la classe.
Si le type de la classe est un tableau alors la chaîne commence par un nombre de caractère '[' correspondant à la
dimension du tableau.
Ensuite la chaîne contient un caractère qui précise un type primitif ou un objet. Dans le cas d'un objet, le nom de la classe
de l'objet avec son package complet est contenu dans la chaîne suivi d'un caractère ';'.
Caractère
Type
B
byte
C
char
D
double
F
float
I
int
J
long
Lclassname;
classe ou interface
Développons en Java
268

S
short
Z
boolean
Exemple :
La méthode getName() de la classe Class représentant un objet de type float[10][5] renvoie « [[F »
Pour simplifier les traitements, la méthode formatParametre() ci dessous retourne une chaîne de caractères qui décode le
contenu de la chaîne retournée par la méthode getName() de la classe Class.
Exemple ( code java 1.1 ) :
  private String formatParametre(String s) { 
    if (s.charAt(0) == '[') { 
      StringBuffer param = new StringBuffer(""); 
      int dimension = 0; 
      while (s.charAt(dimension) == '[') dimension++; 
      switch(s.charAt(dimension)) { 
        case 'B' : param.append("byte");break; 
        case 'C' : param.append("char");break; 
        case 'D' : param.append("double");break; 
        case 'F' : param.append("float");break; 
        case 'I' : param.append("int");break; 
        case 'J' : param.append("long");break; 
        case 'S' : param.append("short");break; 
        case 'Z' : param.append("boolean");break; 
        case 'L' : param.append(s.substring(dimension+1,s.indexOf(";"))); 
      } 
      for (int i =0; i < dimension; i++) 
        param.append("[]"); 
      return param.toString();  
    }           
    else return s; 
  } 
20.2.6. Rechercher les constructeurs de la classe
La classe Class  possède une méthode getConstructors() qui retourne un tableau d'objet de type Constructor contenant les
constructeurs de la classe.
La classe Constructor représente un constructeur d'une classe. Elle possède plusieurs méthodes :
Méthode
Rôle
String getName()
Retourne le nom du constructeur
Class[]
Retourne un tableau de type Class qui représente les exceptions qui peuvent être
getExceptionTypes()
propagées par le constructeur
Class[]
Retourne un tableau de type Class qui représente les paramètres du constructeur
getParametersType()
Retourne un entier qui décrit les modificateurs d'accès. Pour les connaître précisément il
int getModifiers()
faut utiliser les méthodes static de la classe Modifier.
Développons en Java
269

Object
Instancie un objet en utilisant le constructeur avec les paramètres fournis à la méthode
newInstance(Object[])
Exemple ( code java 1.1 ) :
  public Vector getConstructeurs() { 
    Vector cp = new Vector(); 
    Constructor[] constructeurs = classe.getConstructors(); 
    for (int i = 0; i < constructeurs.length; i++) { 
      (rechercheParametres(constructeurs[i].getParameterTypes())); 
    }
    return cp; 
  } 
L'exemple ci dessus utilise la méthode rechercherParamètres() définie précédemment pour simplifier les traitements.
20.2.7. Rechercher les méthodes publiques
Pour consulter les méthodes d'un objet, il faut obtenir sa classe et lui envoyer le message getMethod(), qui renvoie les
méthodes publique qui sont déclarées dans la classe et qui sont héritées des classes mères.
Elle renvoie un tableau d'instances de la classe Method du package .reflect.
Une méthode est caractérisée par un nom, une valeur de retour, une liste de paramètres, une liste d'exceptions et une
classe d'appartenance.
La classe Method contient plusieurs méthodes :
Méthode
Rôle
Class[] getParameterTypes
Renvoie un tableau de classes représentant les paramètres.
Class getReturnType
Renvoie le type de la valeur de retour de la méthode.
String getName()
Renvoie le nom de la méthode
int getModifiers()
Renvoie un entier qui représentent les modificateur d'accès
Class[] getExceptionTypes
Renvoie un tableau de classes contenant les exceptions propagées par la méthode
Class getDeclaringClass[]
Renvoie la classe qui définie la méthode
Exemple ( code java 1.1 ) :
  public Vector getMethodesPubliques() { 
    Vector cp = new Vector(); 
    Method[] methodes = classe.getMethods(); 
    for (int i = 0; i < methodes.length; i++) { 
      StringBuffer methode = new StringBuffer(); 
      methode.append(formatParametre(methodes[i].getReturnType().getName())); 
      methode.append(" "); 
      methode.append(methodes[i].getName()); 
      methode.append(rechercheParametres(methodes[i].getParameterTypes())); 
      (methode.toString()); 
Développons en Java
270

    } 
    return cp; 
  } 
L'exemple ci dessus utilise les méthodes formatParametre() et rechercherParamètres() définies précédemment pour
simplifier les traitements.
20.2.8. Rechercher toutes les méthodes
Pour consulter toutes les méthodes d'un objet, il faut obtenir sa classe et lui envoyer le message getDeclareMethods(), qui
renvoie toutes les méthodes qui sont déclarées dans la classe et qui sont héritées des classes mères quelque soit leur
accessibilité.
Elle renvoie un tableau d'instances de la classe Method du package .reflect.
Exemple ( code java 1.1 ) :
  public Vector getMethodes() { 
    Vector cp = new Vector(); 
    Method[] methodes = classe.getDeclareMethods(); 
    for (int i = 0; i < methodes.length; i++) { 
      StringBuffer methode = new StringBuffer(); 
      methode.append(formatParametre(methodes[i].getReturnType().getName())); 
      methode.append(" "); 
      methode.append(methodes[i].getName()); 
      methode.append(rechercheParametres(methodes[i].getParameterTypes())); 
      (methode.toString()); 
    } 
    return cp; 
  } 
L'exemple ci dessus utilise les méthodes formatParametre() et rechercherParamètres() définies précédemment pour
simplifier les traitements.
20.3. Définir dynamiquement des objets
20.3.1. Définir des objets grâce à la classe Class
Cette section sera développée dans une version future de ce document
Développons en Java
271

20.3.2. Exécuter dynamiquement une méthode
Cette section sera développée dans une version future de ce document
Développons en Java
272

21. L'appel de méthodes distantes : RMI
RMI (Remote Method Invocation) est une technologie développée et fournie par Sun à partir du JDK 1.1 pour permettre
de mettre en oeuvre facilement des objets distribuées.
Ce chapitre contient plusieurs sections :
Présentation et architecture de RMI
• 
Les différentes étapes pour créer un objet distant et l'appeler avec RMI
• 
Le développement coté serveur
• 
Le développement coté client
• 
La génération des classes stub et skeleton
• 
La mise en oeuvre des objets RMI
• 
21.1. Présentation et architecture de RMI
Le but de RMI est de permettre l'appel, l'éxécution et le renvoi du résultat d'une méthode éxécuté dans une machine
virtuelle différente de celle de l'objet l'appelant. Cette machine virtuelle peut être sur une machine différente pourvu
qu'elle soit accessible par le réseau.
La machine sur laquelle s'éxécute la méthode distante est appelée serveur.
L'appel coté client d'une telle méthode est un peu plus compliqué que l'appel d'une méthode d'un objet local mais il reste
simple. Il consiste à obtenir une référence sur l'objet distant puis à simplement appeler la méthode à partir de cette
référence.
La technologie RMI se charge de rendre transparente la localisation de l'objet distant, son appel et le renvoi du résultat.
En fait, elle utilise deux classes particulières, le stub et le skeleton, qui doivent être générées avec l'outils rmic fourni
avec le JDK.
Le stub est une classe qui se situe côté client et le skeleton est son homologue coté serveur. Ces deux classes se chargent
d'assurer tous les mécanismes d'appel, de communication, d'execution, de renvoie et de réception du résultat.
21.2. Les différentes étapes pour créer un objet distant et l'appeler
avec RMI

Le développement coté serveur se compose de :
La définition d'une interface qui contient les méthodes qui peuvent être appelées à distance
• 
L'écriture d'une classe qui implémente cette interface
• 
L'écriture d'une classe qui instanciera l'objet et l'enregistrera en lui affectant un nom dans le registre de nom
• 
RMI (RMI Registry)
Le développement côté client se compose de :
Développons en Java
273

L'obtention d'une référence sur l'objet distant à partir de son nom
• 
L'appel à la méthode à partir de cette référence
• 
Enfin, il faut générer les classes stub et skeleton en exécutant le programme rmic avec le fichier source de l'objet distant
21.3. Le développement coté serveur
21.3.1. La définition d'une interface qui contient les méthodes de l'objet distant
L'interface à définir doit hériter de l'interface .Remote. Cette interface ne contient aucune méthode mais indique
simplement que l'interface peut être appelée à distance.
L'interface doit contenir toutes les méthodes qui seront succeptibles d'être appelées à distance.
La communication entre le client et le serveur lors de l'invocation de la méthode distante peut échouer pour diverses
raisons tel qu'un crash du serveur, une rupture de la liaison, etc ...
A i n s i   c h a q u e   m é t h o d e   a p p e l é e   à   d i s t a n c e   d o i t   d é c l a r e r   q u ' e l l e   e s t   e n   m e s u r e   d e   l e v e r   l ' e x c e p t i o n
.RemoteException.
Exemple ( code java 1.1 ) :
package test_rmi;
import .*;
public interface Information extends Remote {
   public String getInformation() throws RemoteException;
}
21.3.2. L'écriture d'une classe qui implémente cette interface
Cette classe correspond à l'objet distant. Elle doit donc implémenter l'interface définie et contenir le code nécessaire.
Cette classe doit obligatoirement hériter de la classe UnicastRemoteObject qui contient les differents traitements
élémentaires pour un objet distant dont l'appel par le stub du client est unique. Le stub ne peut obtenir qu'une seule
référence sur un objet distant héritant de UnicastRemoteObject. On peut supposer qu'une future version de RMI sera
capable de faire du MultiCast, permettant à RMI de choisir parmis plusieurs objets distants identiques la référence à
fournir au client.
La hiérarchie de la classe UnicastRemoteObject est :
.Object
.Server.RemoteObject
.Server.RemoteServer
.Server.UnicastRemoteObject
Comme indiqué dans l'interface, toutes les méthodes distantes doivent indiquer qu'elles peuvent lever l'exception
RemoteException mais aussi le constructeur de la classe. Ainsi, même si le constructeur ne contient pas de code il doit
être redéfini pour inhiber la génération du constructeur par défaut qui ne lève pas cette exception.
Développons en Java
274

Exemple ( code java 1.1 ) :
package test_rmi;
import .*;
import .server.*;
public class TestRMIServer extends UnicastRemoteObject implements Information {
   protected TestRMIServer() throws RemoteException {
      super();
   }
   public String getInformation()throws RemoteException {
      return "bonjour";
   }
}
21.3.3. L'écriture d'une classe pour instancier l'objet et l'enregistrer dans le registre
Ces opérations peuvent être effectuées dans la méthode main d'une classe dédiée ou dans la méthode main de la classe de
l'objet distant. L'intérêt d'une classe dédié et qu'elle permet de regrouper toutes ces opérations pour un ensemble d'objets
distants.
La marche a suivre contient trois étapes :
la mise en place d'un security manager dédié qui est facultative
• 
l'instanciation d'un objet de la classe distante
• 
l'enregistrement de la classe dans le registre de nom RMI en lui donnant un nom
• 
21.3.3.1. La mise en place d'un security manager
Cette opération n'est pas obligatoire mais elle est recommandée en particulier si le serveur doit charger des classes qui ne
sont pas sur le serveur. Sans sécurity mananger, il faut obligatoirement mettre à la disposition du serveur toutes les
classes dont il aura besoin (Elles doivent être dans le CLASSPATH du serveur). Avec un security manager, le serveur
peut charger dynamiquement certaines classes.
Cependant, le chargement dynamique de ces classes peut poser des problèmes de sécurité car le serveur va éxécuter du
code d'une autre machine. Cet aspect peut conduire à ne pas utiliser de sécurity manager.
Exemple ( code java 1.1 ) :
public static void main(String[] args) {
   try {
      .println("Mise en place du Security Manager ...");
      System.setSecurityManager(new .RMISecurityManager());
   } catch (Exception e) {
      .println("Exception capturée: " + e.getMessage());
   }
}
21.3.3.2. L'instanciation d'un objet de la classe distante
Cette opération est très simple puisqu'elle consiste simplement en la création d'un objet de la classe de l'objet distant
Exemple ( code java 1.1 ) :
Développons en Java
275

public static void main(String[] args) {
   try {
      .println("Mise en place du Security Manager ...");
      System.setSecurityManager(new .RMISecurityManager());
      TestRMIServer testRMIServer = new TestRMIServer();
   } catch (Exception e) {
      .println("Exception capturée: " + e.getMessage());
   }
}
21.3.3.3. L'enregistrement dans le registre de nom RMI en lui donnant un nom
La dernière opération consiste à enregistrer l'objet créé dans le registre de nom en lui affectant un nom. Ce nom est fourni
au registre sous forme d'une URL constitué du préfix rmi://, du nom du seveur (hostname) et du nom associé à l'objet
précédé d'un slash.
Le nom du serveur peut être fourni « en dur » sous forme d'une constante chaine de caractères ou peut être
dynamiquement obtenu en utilisant la classe InetAddress pour une utilisation en locale.
C'est ce nom qui sera utilisé dans une URL par le client pour obtenir une référence sur l'objet distant.
L'enregistrement se fait en utilisant la méthode rebind de la classe Naming. Elle attend en paramètre l'URL du nom de
l'objet et l'objet lui même.
Exemple ( code java 1.1 ) :
public static void main(String[] args) {
   try {
      .println("Mise en place du Security Manager ...");
      System.setSecurityManager(new .RMISecurityManager());
      TestRMIServer testRMIServer = new TestRMIServer();
      .println("Enregistrement du serveur");
      Naming.rebind("rmi://".InetAddress.getLocalHost()+
         "/TestRMI",testRMIServer);
      // Naming.rebind(";rmi://localhost/TestRMI", testRMIServer);
      .println("Serveur lancé");
   } catch (Exception e) {
      .println("Exception capturée: " + e.getMessage());
   }
}
21.3.3.4. Lancement dynamique du registre de nom RMI
Sur le serveur, le registre de nom RMI doit s'éxécuter avant de pouvoir enregistrer un objet ou obtenir une référence.
Ce registre peut être lancé en tant qu'application fournie par sun dans le JDK (rmiregistry) comme indiqué dans un
chapitre suivant ou être lancé dynamiquement dans la classe qui enregistre l'objet. Ce lancement ne doit avoir lieu qu'une
seule et unique fois. Il peut être intéressant d'utiliser ce code si l'on créé une classe dédié à l'enregistrement des objets
Développons en Java
276

distants.
Le code pour éxécuter le registre est la méthode createRegistry de la classe .registry.LocateRegistry. Cette
méthode attend en paramètre un numéro de port.
Exemple ( code java 1.1 ) :
public static void main(String[] args) {
   try {
      .registry.LocateRegistry.createRegistry(1099);
      .println("Mise en place du Security Manager ...");
      System.setSecurityManager(new .RMISecurityManager());
      ...
   }
}
21.4. Le développement coté client
L'appel d'une méthode distante peut se faire dans une application ou dans une applet.
21.4.1. La mise en place d'un security manager
Comme pour le coté serveur, cette opération est facultative.
Le choix de la mise en place d'un sécurity manager côté client suit des règles identiques à celui du côté serveur. Sans son
utilisation, il est nécessaire de mettre dans le CLASSPATH du client toutes les classes nécessaires dont la classe stub.
Exemple ( code java 1.1 ) :
public static void main(String[] args) {
   System.setSecurityManager(new RMISecurityManager());
}
21.4.2. L'obtension d'une référence sur l'objet distant à partir de son nom
Pour obtenir une référence sur l'objet distant à partir de son nom, il faut utiliser la méthode statique lookup() de la classe
Naming.
Cette méthode attend en paramètre une URL indiquant le nom qui référence l'objet distant. Cette URL est composé de
préfix rmi://, le nom du serveur (hostname) et le nom de l'objet tel qu'il a été enregistré dans le registre précédé d'un
slash.
Il est préférable de prévoir le nom du serveur sous forme de paramètres de l'application ou de l'applet pour plus de
souplesse.
La méthode lookup() va rechercher dans le registre du serveur l'objet et retourner un objet stub. L'objet retourné est de la
classe Remote (cette classe est la classe mère de tous les objets distants).
Si le nom fourni dans l'URL n'est pas référencé dans le registre, la méthode lève l'exception NotBoundException.
Développons en Java
277

Exemple ( code java 1.1 ) :
public static void main(String[] args) {
   System.setSecurityManager(new RMISecurityManager());
   try {
      Remote r = Naming.lookup("rmi://vaio/127.0.0.1/TestRMI");
   } catch (Exception e) {
   }
}
21.4.3. L'appel à la méthode à partir de la référence sur l'objet distant
L'objet retourné étant de type Remote, il faut réaliser un cast vers l'interface qui définit les méthodes de l'objet distant.
Pour plus de sécurité, on vérifie que l'objet retourné est bien une instance de cette interface.
Un fois le cast réalisé, il suffit simplement d'appeler la méthode.
Exemple ( code java 1.1 ) :
public static void main(String[] args) {
   System.setSecurityManager(new RMISecurityManager());
   try {
      Remote r = Naming.lookup("rmi://vaio/127.0.0.1/TestRMI");
      if (r instanceof Information) {
         String s = ((Information) r).getInformation();
         .println("chaine renvoyée = " + s);
      }
   } catch (Exception e) {
   }
}
21.4.4. L'appel d'une méthode distante dans une applet
L'appel d'une méthode distante est la même dans une application et dans une applet.
Seul la mise en place d'un security manager dédié dans les applets est inutile car elles utilisent déjà un sécurity manager
(AppletSecurityManager) qui autorise le chargement de classes distantes.
Exemple ( code java 1.1 ) :
package test_rmi;
import java.applet.*;
import .*;
import .*;
public class AppletTestRMI extends Applet {
   private String s;
   public void init() {
      try { 
         Remote r = Naming.lookup("rmi://vaio/127.0.0.1/TestRMI");
Développons en Java
278

         if (r instanceof Information) {
            s = ((Information) r).getInformation();
         }
      } catch (Exception e) {
      }
   }
   public void paint(Graphics g) {
      super.paint(g);
      g.drawString("chaine retournée = "+s,20,20);
   }
}
21.5. La génération des classes stub et skeleton
Pour générer ces classes, il suffit d'utiliser l'outils rmic fourni avec le JDK en lui donnant en paramètre le nom de la
classe.
Attention la classe doit avoir été compilée : rmic à besoin du fichier .class.
Exemple ( code java 1.1 ) :
rmic test_rmi.TestRMIServer
rmic va générer et compiler les classes stub et skeleton respectivement sous le nom TestRMIServer_Stub.class et
TestRMIServer_Skel.class
21.6. La mise en oeuvre des objets RMI
La mise en oeuvre et l'utilisation d'objet distant avec RMI nécessite plusieurs étapes :
Démarrer le registre RMI sur le serveur soit en utilisant le programme rmiregistry livré avec le JDK soit en
1. 
exécutant une classe qui éffectue le lancement.
éxécuter la classe qui instancie l'objet distant et l'enregistre dans le serveur de nom RMI
2. 
Lancer l'application ou l'applet pour tester.
3. 
21.6.1. Le lancement du registre RMI
La commande rmiregistry est fournie avec le JDK.
Il faut la lancer en tache de fond :
Sous Unix : rmiregistry&
Sous Windows : start rmiregistry
Ce registre permet de faire correspondre un objet à un nom et inversement. C'est lui qui est sollicité lors d'un appelle aux
méthodes () et Naming.lookup()
Développons en Java
279

21.6.2. L'instanciation et l'enregistrement de l'objet distant
Il faut éxécuter la classe qui va instancier l'objet distant et l'enregistrer sous son nom dans le registre précédemment
lancé.
Pour ne pas avoir de problème, il faut s'assurer que toutes les classes utiles (la classe de l'objet distant, l'interface qui
définit les méthodes, le skeleton) sont présentes dans un répertoire défini dans la variable CLASSPATH.
21.6.3. Le lancement de l'application cliente
La suite de cette section sera développée dans une version future de ce document
Développons en Java
280

22. L'internationalisation
La localisation consiste à adapter un logiciel pour s'adapter aux caractéristiques locales de l'environnement d'execution
telles que la langue. Le plus gros du travail consiste à traduire toutes les phrases et les mots. Les classes nécessaires sont
incluses dans le packetage .
Ce chapitre contient plusieurs sections :
Les objets de type locale
• 
La classe ResourceBundle
• 
Chemins guidés pour réaliser la localisation
• 
Cette section propose plusieurs solutions pour réalisation l'internationalisation.
22.1. Les objets de type Locale
Un objet de type Locale identifie une langue et un pays donné.
22.1.1. Création d'un objet Locale
Exemple ( code java 1.1 ) :
locale_US = new
Locale("en","US") ; 
locale_FR = new Locale("fr","FR");
Le premier paramètre est le code langue (deux caractères minuscules conformes à la norme ISO?639 : exemple "de"
pour l'allemand, "en" pour l'anglais,  "fr" pour le français, etc ...)
Le deuxième paramètre est le code pays (deux caractères majuscules conformes à la norme ISO?3166 : exemple : "DE"
pour l'Allemagne, "FR" pour la France,"US" pour les Etats Unis, etc ...). Ce paramètre est obligatoire : si le pays n'a pas
besoin d'être précisé, il faut fournir une chaine vide.
Exemple ( code java 1.1 ) :
Locale locale = new Locale("fr", "");
Un troisième paramètre peut permettre de préciser d'avantage la localisation par exemple la plateforme d'execution (il ne
respecte aucun standard car il ne sera défini que dans l'application qui l'utilise) :
Développons en Java
281

Exemple ( code java 1.1 ) :
Locale locale_unix = new Locale("fr","FR", "UNIX"); 
Locale locale_windows = new Locale("fr","FR", "WINDOWS");
Ce troisième paramètre est optionnel.
La classe Locale définit des constantes pour certaines langues et pays :
Exemple ( code java 1.1 ) : ces deux lignes sont equivalentes
Locale locale_1 = Locale.JAPAN; 
Locale locale_2 = new Locale("ja", "JP");
Lorsque l'on précise une constante représentant une langue alors le code pays n'est pas défini.
Exemple ( code java 1.1 ) : ces deux lignes sont equivalentes
Locale locale_3 = Locale.JAPANESE; 
Locale locale_2 = new Locale("ja", "");
Il est possible de rendre la création d'un objet Locale dynamique :
Exemple ( code java 1.1 ) :
static public void main(String[] args) {
   String langue = new String(args[0]);
   String pays = new String(args[1]);
   locale = new Locale(langue, pays);
}
Cet objet ne sert que d'identifiant qu'il faut passer à des objets de type ResourceBundle par exemple qui eux possèdent le
nécessaire pour réaliser la localisation. En fait, le création d'un objet Locale pour un pays donné ne signifie pas que l'on
va pouvoir l'utiliser.
22.1.2. Obtenir la liste des Locales disponibles
La méthode getAvailableLocales() permet de connaître la liste des Locales reconnues par une classe sensible à
l'internationalisation
Exemple ( code java 1.1 ) : avec la classe DateFormat
import .*;
import .*;
public class Available {
   static public void main(String[] args) {
      Locale liste[] =
      DateFormat.getAvailableLocales();
      for (int i = 0; i < liste.length; i++)
      {
         .println(liste[i].toString());
         // toString retourne le code langue et le code pays séparé d'un souligné
      }
   }
Développons en Java
282

}
La méthode Locale.getDisplayName() peut être utilisée à la place de toString pour obtenir le nom du code langue et du
code pays.
22.1.3. L'utilisation d'un objet Locale
Il n'est pas obligatoire de se servir du même objet Locale avec les classes sensibles à l'internationnalisation.
Cependant la plupart des applications utilise l'objet Locale par défaut initialisé par la machine virtuelle avec les
paramètres de la machine hote. La méthode Locale.getDefault() permet de connaître l'objet Locale par défaut.
22.2. La classe ResourceBundle
Il est préférable de définir un ResourceBundle pour chaque catégorie d'objet (exemple un par fénêtre) : ceci rend le code
plus clair et plus facile à maintenir, évite d'avoir des ResourceBundle trop importants et réduit l'espace mémoire utilisé
car chaque ressource n'est chargée que lorsque l'on en a besoin.
22.2.1. La création d'un objet ResourceBundle
Conceptuellement, chaque ResourceBundle est un ensemble de sous classes qui partage la même racine de nom.
Exemple ( code java 1.1 ) :
TitreBouton
TitreBouton_de
TitreBouton_en_GB
TitreBouton_fr_FR_UNIX
Pour sélectionner le ResourceBundle approprié il faut utiliser la méthode ResourceBundle.getBundle().
Exemple ( code java 1.1 ) :
Locale locale = new Locale("fr", "FR");
ResourceBundle messages = ResourceBundle.getBundle("TitreBouton", locale);
Le premier argument contient le type d'objet à utiliser (la racine du nom de cet objet).
Le second argument de type Locale permet de déterminer quel fichier sera utilisé : il ajoute le code pays et le code langue
séparé par un souligné à la racine du nom.
Si la classe désignée par l'objet Locale n'existe par, alors getBundle recherche celle qui se rapproche le plus. L'ordre de
recherche sera le suivant :
Exemple ( code java 1.1 ) :
TitreBouton_fr_CA_UNIX
TitreBouton_fr_FR
TitreBouton_fr
TitreBouton_en_US
Développons en Java
283

TitreBouton_en
TitreBouton
Si aucune n'est trouvée alors getBundle lève une exception de type MissingResourceException.
22.2.2. Les sous classes de ResourceBundle
La classe abstraite ResourceBundle possède deux sous classes : PropertyResourceBundle et ListResourceBundle.
La classe ResourceBundle est une classe fléxible : le changement de l'utilisation d'un PropertyResourceBundle en
ListResourceBundle se fait sans impact sur le code. La méthode getBundle() recherche le ResourceBundle désiré qu'il
soit dans un fichier .class ou propriétés
22.2.2.1. L'utilisation de PropertyResourceBundle
Un PropertyResourceBundle est rattaché à un fichier propriétés. Ces fichiers propriétés ne font pas partie du code source
java. Ils ne peuvent contenir que des chaines de caractères. Pour stocker d'autres objets, il faut utiliser des objets
ListResourceBundle.
La création d'un fichier propriétés est simple : c'est un fichier texte qui contient des paires clé?valeur. La clé et la valeur
sont séparées par un signe =. Chaque paire doit être sur une ligne séparée.
Exemple ( code java 1.1 ) :
texte_suivant = suivant
texte_precedent = precedent
Le nom du fichier propriétés par défaut se compose de la racine du nom suivi de l'extension .properties.
Exemple : TitreBouton.properties.
Dans une autre langue, anglais par exemple, le fichier s'appelerait : TitreBouton_en.properties
Exemple ( code java 1.1 ) :
texte_suivant = next
texte_precedent = previous
Les clés sont les mêmes, seule la traduction change.
Le nom de fichier TitreBouton_fr_FR.properties contient la racine (Titrebouton), le code langue (fr) et le code pays (FR).
22.2.2.2. L'utilisation de ListResourceBundle
La classe ListResourceBundle gère les ressources sous forme de liste encapsulée dans un objet. Chaque
ListResourceBundle est donc rattaché à un fichier .class. On peut y stocker n'importe quel objet spécifique à la
localisation.
Les objets ListResourceBundle contiennent des paires clé?valeur. La clé doit être une chaine qui caractérise l'objet. La
valeur est un objet de n'importe quelle classe.
Développons en Java
284

Exemple ( code java 1.1 ) :
class TitreBouton_fr extends ListResourceBundle {
   public Object[][] getContents() {
      return contents;
   }
   static final Object[][] contents = {
      {"texte_suivant", "Suivant"},
      {"texte_precedent", "Precedent"},
   };
}
22.2.3. Obtenir un texte d'un objet ResourceBundle
La méthode getString() retourne la valeur de la clé précisée en paramètre.
Exemple ( code java 1.1 ) :
String message_1 = messages.getString("texte_suivant");
String message_2 = TitreBouton.getString("texte_suivant");
22.3. Chemins guidés pour réaliser la localisation
22.3.1. L'utilisation d'un ResourceBundle avec un fichier propriétés
Il faut toujours créer le fichier propriété par défaut. Le nom de ce fichier commence avec le nom de base du
ResourceBundle et se termine avec le suffix .properties
Exemple ( code java 1.1 ) :
#Exemple de fichier propriété par défaut (TitreBouton.properties)
texte1 = suivant
texte2 = precedent
texte3 = quitter
Les lignes de commentaires commencent par un #. Les autres lignes contiennent les paires clé?valeur. Une fois le fichier
défini, il ne faut plus modifier la valeur de la clé qui pourrait être appellée dans un programme.
Pour ajouter le support d'autre langue, il faut créer des fichier propriétés supplementaires qui contiendront les traductions.
Le fichier est le même, seul le texte contenu dans la valeur change (la valeur de la clé doit être identique).
Exemple ( code java 1.1 ) :
#Exemple de fichier propriété en anglais (TitreBouton_en.properties)
texte1 = next
texte2 = previous
texte3 = quit
Lors de la programmation, il faut créer un objet Locale. Il est possible de créer un tableau qui contient la liste des Locale
disponibles en fonction des fichiers propriétés créés.
Exemple ( code java 1.1 ) :
Développons en Java
285

Locale[] locales = { Locale.GERMAN, Locale.ENGLISH };
Dans cet exemple, l'objet Locale.ENGLISH correspond au fichier TitreBouton_en.properties. L'objet Locale.GERMAN
ne possédant pas de fichier propriétés défini, le fichier par défaut sera utilisé.
Il faut créer l'objet ResourceBundle en invoquant la méthode getBundle de l'objet Locale.
Exemple ( code java 1.1 ) :
ResourceBundle titres =ResourceBundle.getBundle("TitreBouton", locales[1]);
La méthode getBundle() recherche en premier une classe qui correspond au nom de base, si elle n'existe pas alors elle
recherche un fichier de propriétés. Lorsque le fichier est trouvé, elle retourne un objet PropertyResourceBundle qui
contient les paires clé?valeur du fichier
Pour retrouver la traduction d'un texte, il faut utiliser la méthode getString() d'un objet ResourceBundle
Exemple ( code java 1.1 ) :
String valeur = titres.getString(key);
Lors du deboggage, il peut être utile d'obtenir la liste de paire d'un objet ResourceBundle. La méthode getKeys() retourne
un objet Enumeration qui contient toutes les clés de l'objet.
Exemple ( code java 1.1 ) :
ResourceBundle titres =ResourceBundle.getBundle("TitreBouton", locales[1});
Enumeration cles = titres.getKeys();
while (bundleKeys.hasMoreElements()) {
   String cle = (String)cles.nextElement();
   String valeur = titres.getString(cle);
   .println("cle = " + valeur +
      ", " +   "valeur = " + valeur);
}
22.3.2. Exemples de classes utilisant PropertiesResourceBundle
Exemple ( code java 1.1 ) : Sources de la classe I18nProperties
/* 
Test d'utilisation de la classe PropertiesResourceBundle
pour internationaliser une application 
13/02/99 
*/ 
import .*; 
/** 
 * Description de la classe I18nProperties 
 * 
 * @version       0.10 13 fevrier 1999 
 * @author        Jean Michel DOUDOUX 
 */ 
public class I18nProperties { 
  /** 
   * Constructeur de la classe 
   */ 
Développons en Java
286

  public I18nProperties() { 
    String texte; 
    Locale locale; 
    ResourceBundle res; 
    .println("Locale par defaut : "); 
    locale = Locale.getDefault(); 
    res = ResourceBundle.getBundle("I18nPropertiesRessources", locale); 
    texte = (String)res.getObject("texte_suivant"); 
    .println("texte_suivant = "+texte); 
    texte = (String)res.getObject("texte_precedent"); 
    .println("texte_precedent = "+texte); 
    .println("\nLocale anglaise : "); 
    locale = new Locale("en",""); 
    res = ResourceBundle.getBundle("I18nPropertiesRessources", locale); 
    texte = (String)res.getObject("texte_suivant"); 
    .println("texte_suivant = "+texte); 
    texte = (String)res.getObject("texte_precedent"); 
    .println("texte_precedent = "+texte); 
    .println("\nLocale allemande : "+
       "non définie donc utilisation locale par defaut "); 
    locale = Locale.GERMAN; 
    res = ResourceBundle.getBundle("I18nPropertiesRessources", locale); 
    texte = (String)res.getObject("texte_suivant"); 
    .println("texte_suivant = "+texte); 
    texte = (String)res.getObject("texte_precedent"); 
    .println("texte_precedent = "+texte); 
  } 
 /** 
   * Pour tester la classe 
   * 
   * @param      args[]         arguments passes au programme 
   */ 
  public static void main(String[] args) { 
    I18nProperties i18nProperties = new I18nProperties(); 
  } 

Exemple ( code java 1.1 ) : Contenu du fichier I18nPropertiesRessources.properties
texte_suivant=suivant 
texte_precedent=Precedent 
Exemple ( code java 1.1 ) : Contenu du fichier I18nPropertiesRessources_en.properties
texte_suivant=next 
texte_precedent=previous 
Exemple ( code java 1.1 ) : Contenu du fichier I18nPropertiesRessources_en_US.properties
texte_suivant=next 
texte_precedent=previous 
22.3.3. L'utilisation de la classe ListResourceBundle
Il faut créer autant de sous classes de ListResourceBundle que de langues désirées : ceci va générer un fichier .class pour
chacune des langues .
Exemple ( code java 1.1 ) :
TitreBouton_fr_FR.class
TitreBouton_en_EN.class
Développons en Java
287

Le nom de la classe doit contenir le nom de base plus le code langue et le code pays séparés par un souligné. A l'intérieur
de la classe, un tableau à deux dimensions est initialisé avec les paires clé?valeur. Les clés sont des chaines qui doivent
être identiques dans toutes les classes des différentes langues. Les valeurs peuvent être des objets de n'importe quel type.
Exemple ( code java 1.1 ) :
import .*;
public class TitreBouton_fr_FR extends ListResourceBundle {
   public Object[][] getContents() {
      return contents;
   }
   private Object[][] contents = {
      { "texte_suivant", new String(" suivant ")},
      { "Numero", new Integer(4) }
   };
}
Il faut définir un objet de type Locale
Il faut créer un objet de type ResourceBundle en appelant la méthode getBundle() de la classe Locale
Exemple ( code java 1.1 ) :
ResourceBundle titres=ResourceBundle.getBundle("TitreBouton", locale);
La méthode getBundle() recherche une classe qui commence par TitreBouton et qui est suivi par le code langue et le
code pays précisé dans l'objet Locale passé en paramètre
La méthode getObject permet d'obtenir la valeur de la clé passée en paramètres. Dans ce cas une conversion est
nécessaire.
Exemple ( code java 1.1 ) :
Integer valeur = (Integer)titres.getObject("Numero");
22.3.4. Exemples de classes utilisant ListResourceBundle
Exemple ( code java 1.1 ) : Sources de la classe I18nList
/* 
Test d'utilisation de la classe ListResourceBundle
pour internationaliser une application 
13/02/99 
*/ 
import .*; 
/** 
 * Description de la classe I18nList 
 * 
 * @version       0.10 13 fevrier 1999 
 * @author        Jean Michel DOUDOUX 
 */ 
public class I18nList { 
  /** 
   * Constructeur de la classe 
Développons en Java
288

   */ 
  public I18nList() { 
    String texte; 
    Locale locale; 
    ResourceBundle res; 
    .println("Locale par defaut : "); 
    locale = Locale.getDefault(); 
    res = ResourceBundle.getBundle("I18nListRessources", locale); 
    texte = (String)res.getObject("texte_suivant"); 
    .println("texte_suivant = "+texte); 
    texte = (String)res.getObject("texte_precedent"); 
    .println("texte_precedent = "+texte); 
    .println("\nLocale anglaise : "); 
    locale = new Locale("en",""); 
    res = ResourceBundle.getBundle("I18nListRessources", locale); 
    texte = (String)res.getObject("texte_suivant"); 
    .println("texte_suivant = "+texte); 
    texte = (String)res.getObject("texte_precedent"); 
    .println("texte_precedent = "+texte); 
    .println("\nLocale allemande : "+
       "non définie donc utilisation locale par defaut "); 
    locale = Locale.GERMAN; 
    res = ResourceBundle.getBundle("I18nListRessources", locale); 
    texte = (String)res.getObject("texte_suivant"); 
    .println("texte_suivant = "+texte); 
    texte = (String)res.getObject("texte_precedent"); 
    .println("texte_precedent = "+texte); 
  } 
 /** 
   * Pour tester la classe 
   * 
   * @param      args[]         arguments passes au programme 
   */ 
  public static void main(String[] args) { 
    I18nList i18nList = new I18nList(); 
  } 

Exemple ( code java 1.1 ) : Sources de la classe I18nListRessources
/* 
test d'utilisation de la classe ListResourceBundle pour 
internationaliser une application 
13/02/99 
*/ 
import .*; 
/** 
 * Ressource contenant les traductions françaises 
 * langue par defaut de l'application 
 * 
 * @version       0.10 13 fevrier 1999 
 * @author        Jean Michel DOUDOUX 
 * 
 */ 
public class I18nListRessources extends ListResourceBundle { 
  public Object[][] getContents() { 
    return contents; 
  } 
   //tableau des mots clés et des valeurs 
   static final Object[][] contents = { 
   {"texte_suivant", "Suivant"}, 
   {"texte_precedent", "Precedent"}, 
Développons en Java
289

  }; 

Exemple ( code java 1.1 ) : Sources de la classe I18nListRessources_en
/* 
test d'utilisation de la classe ListResourceBundle pour 
internationaliser une application 
13/02/99 
*/ 
import .*; 
/** 
 * Ressource contenant les traductions anglaises 
 * 
 * @version       0.10 13 fevrier 1999 
 * @author        Jean Michel DOUDOUX 
 * 
 */ 
public class I18nListRessources_en extends ListResourceBundle { 
  public Object[][] getContents() { 
    return contents; 
  } 
   //tableau des mots clés et des valeurs 
   static final Object[][] contents = { 
   {"texte_suivant", "Next"}, 
   {"texte_precedent", "Previous"}, 
  }; 
}
Exemple ( code java 1.1 ) : Sources de la classe I18nListRessources_en_US
/* 
test d'utilisation de la classe ListResourceBundle pour 
internationaliser une application 
13/02/99 
*/ 
import .*; 
/** 
* Ressource contenant les traductions américaines 

* @version 0.10 13 fevrier 1999 
* @author Jean Michel DOUDOUX 

*/ 
public class I18nListRessources_en_US extends ListResourceBundle { 
public Object[][] getContents() { 
return contents; 

//tableau des mots clés et des valeurs 
static final Object[][] contents = { 
{"texte_suivant", "Next"}, 
{"texte_precedent", "Previous"}, 
}; 
}
22.3.5. La création de sa propre classe fille de ResourceBundle
La troisième solution consiste à créer sa propre sous classe de ResourceBundle et à surcharger la méthode
handleGetObject().
Exemple ( code java 1.1 ) :
Développons en Java
290

abstract class MesRessources extends ResourceBundle {
   public Object handleGetObject(String cle)  {
      if(cle.equals(" texte_suivant "))
         return " Suivant " ;
      if(cle.equals(" texte_precedent "))
         return "Precedent " ;
         return null ;
   }
}
Attention : la classe ResourceBundle contient deux méthodes abstraites : handleGetObjects() et getKeys(). Si
l'une des deux n'est pas définie alors il faut définir la sous classe avec le mot clé abstract.
Il faut créer autant de sous classes que de Locale désiré : il suffit simplement d'ajouter dans le nom de la classe le code
langue et le code pays avec eventuellement le code variant.
22.3.6. Exemple de classes utilisant une classe fille de ResourceBundle
Exemple ( code java 1.1 ) : Sources de la classe I18nResource
/* 
Test d'utilisation d'un sous classement 
de la classe ResourceBundle pour 
internationaliser une application 
13/02/99 
*/ 
import .*; 
/** 
 * Description de la classe I18nResource 
 * 
 * @version       0.10 13 fevrier 1999 
 * @author        Jean Michel DOUDOUX 
 */ 
public class I18nResource { 
  /** 
   * Constructeur de la classe 
   */ 
  public I18nResource() { 
    String texte; 
    Locale locale; 
    ResourceBundle res; 
    .println("Locale par defaut : "); 
    res = ResourceBundle.getBundle("I18nResourceBundle"); 
    texte = (String)res.getObject("texte_suivant"); 
    .println("texte_suivant = "+texte); 
    texte = (String)res.getObject("texte_precedent"); 
    .println("texte_precedent = "+texte); 
    .println("\nLocale anglaise : "); 
    locale = new Locale("en",""); 
    res = ResourceBundle.getBundle("I18nResourceBundle", locale); 
    texte = (String)res.getObject("texte_suivant"); 
    .println("texte_suivant = "+texte); 
    texte = (String)res.getObject("texte_precedent"); 
    .println("texte_precedent = "+texte); 
    .println("\nLocale allemande : "+
       "non définie donc utilisation locale par defaut "); 
    locale = Locale.GERMAN; 
    res = ResourceBundle.getBundle("I18nResourceBundle", locale); 
Développons en Java
291

    texte = (String)res.getObject("texte_suivant"); 
    .println("texte_suivant = "+texte); 
    texte = (String)res.getObject("texte_precedent"); 
    .println("texte_precedent = "+texte); 
  } 
 /** 
   * Pour tester la classe 
   * 
   * @param      args[]         arguments passes au programme 
   */ 
  public static void main(String[] args) { 
    I18nResource i18nResource = new I18nResource(); 
  } 

Exemple ( code java 1.1 ) : Sources de la classe I18nResourceBundle
/* 
Test d'utilisation de la derivation de la classe ResourceBundle pour 
internationaliser une application 
13/02/99 
*/ 
import .*; 
/** 
 * Description de la classe I18nResourceBundle 
 * C'est la classe contenant la locale par defaut 
 * Contient les traductions de la locale francaise (langue par defaut) 
 * Elle herite de ResourceBundle 
 * 
 * @version       0.10 13 fevrier 1999 
 * @author        Jean Michel DOUDOUX 
 */ 
public class I18nResourceBundle extends ResourceBundle { 
   protected Vector table; 
   public I18nResourceBundle() { 
      super(); 
      table = new Vector(); 
      table.addElement("texte_suivant"); 
      table.addElement("texte_precedent"); 
   } 
   public Object handleGetObject(String cle)  { 
      if(cle.equals(table.elementAt(0))) return "Suivant" ; 
      if(cle.equals(table.elementAt(1))) return "Precedent" ; 
      return null ; 
   } 
   public Enumeration getKeys()  { 
      return table.elements(); 
   } 

Exemple ( code java 1.1 ) : Sources de la classe I18nResourceBundle_en
/* 
Test d'utilisation de la derivation de la classe ResourceBundle pour 
internationaliser une application 
13/02/99 
*/ 
import .*; 
/** 
 * Description de la classe I18nResourceBundle_en 
Développons en Java
292

 * Contient les traductions de la locale anglaise 
 * Elle herite de la classe contenant la locale par defaut 
 * 
 * @version       0.10 13 fevrier 1999 
 * @author        Jean Michel DOUDOUX 
 */ 
public class I18nResourceBundle_en extends I18nResourceBundle { 
   public Object handleGetObject(String cle)  { 
      if(cle.equals(table.elementAt(0))) return "Next" ; 
      if(cle.equals(table.elementAt(1))) return "Previous" ; 
      return null ; 
   } 
}
Exemple ( code java 1.1 ) : Sources de la classe I18nResourceBundle_fr_FR
/* 
Test d'utilisation de la derivation de la classe ResourceBundle pour 
internationaliser une application 
13/02/99 
*/ 
import .*; 
/** 
 * Description de la classe I18nResourceBundle_fr_FR 
 * Contient les traductions de la locale francaise 
 * Elle herite de la classe contenant la locale par defaut 
 * 
 * @version       0.10 13 fevrier 1999 
 * @author        Jean Michel DOUDOUX 
 */ 
public class I18nResourceBundle_fr_FR extends I18nResourceBundle { 
   /** 
    * 
    * Retourne toujours null car la locale francaise correspond 
    * a la locale par defaut 
    * 
    */ 
   public Object handleGetObject(String cle)  { 
      return null ; 
   } 

Développons en Java
293

23. Les composants java beans
Les java beans sont des composants réutilisables introduits par le JDK 1.1. De nombreuses fonctionnalités de ce JDK lui
ont été ajoutées pour développer des caractéristiques de ces composants. Les java beans sont couramment appelés
simplement beans.
Les beans sont prévues pour pouvoir inter?agir avec d'autres beans au point de pouvoir développer une application
simplement en assemblant des beans avec un outil graphique dédié. Sun fournit gratuitement un tel outils : le B.D.K.
(Bean Development Kit).
23.1. Présentations des java beans
Des composants réutilisables sont des objets autonomes qui doivent pouvoir être facilement assemblés entres eux pour
créer un programme.
Microsoft propose la technologie ActiveX pour définir des composants mais celle ci est spécifiquement destinée aux
plate?formes Windows.
Les java beans proposé par Sun reposent bien sûre sur java et de fait en possède toutes les caractéristiques : indépendance
de la plate?forme, taille réduite du composant, ...
La technologie java beans propose de simplifier et faciliter la création et l'utilisation de composants.
Les java beans possèdent plusieurs caractéristiques :
la persistance : elle permet grâce au mécanisme de sérialisation de sauvegarder l'état d'un bean pour le restaurer
• 
ainsi si on assemble plusieurs beans pour former une application, on peut la sauvegarder.
la communication grâce à des événements qui utilise le modèle des écouteurs introduit par java 1.1
• 
l'introspection : ce mécanisme permet de découvrir de façon dynamique l'ensemble des éléments qui compose le
• 
bean (attributs, méthodes et événements) sans avoir le source.
la possibilité de paramétrer le composant : les données du paramétrage sont conservées dans des propriétés.
• 
Ainsi, les beans sont des classes java qui doivent respecter un certains nombre de règles :
ils doivent posséder un constructeur sans paramètre. Celui ci devra initialiser l'état du bean avec des valeurs par
• 
défauts.
ils peuvent définir des propriétés : celles ci sont identifiées par des méthodes dont le nom et la signature sont
• 
normalisés
ils devraient implémenter l'interface serialisable : ceci est obligatoire pour les beans qui possèdent une partie
• 
graphique pour permettre la sauvegarde de leur état
ils définissent des méthodes utilisables par les composants extérieures : elles doivent être public et prévoir une
• 
gestion des accès concurrents
ils peuvent émettent des événements en gérant une liste d'écouteurs qui s'y abonnent via des méthodes dont les
• 
noms sont normalisés
Le type de composants le plus adapté est le composant visuel. D'ailleurs, les composants des classes A.W.T. et Swing
pour la création d'interfaces graphiques sont tous des beans. Mais les beans peuvent aussi être des composants non
Développons en Java
294

visuels pour prendre en charge les traitements.
23.2. Les propriétés.
Les propriétés contiennent des données qui gèrent l'état du composant : ils peuvent être de type primitif ou être un objet.
Il existe quatres types de propriétés :
les propriétés simples
• 
les propriétés indexées (indexed properties)
• 
les propriétés liées (bound properties)
• 
les propriétés liées avec contraintes (Constrained properties)
• 
23.2.1. Les propriétés simples
Les propriétés sont des variables d'instance du bean qui possèdent des méthodes particulières pour lire et modifier leur
valeur. La normalisation de ces méthodes permet à des outils de déterminer de façon dynamique quels sont les propriétés
du bean. L'accès à ces propriétés doit se faire via ces méthodes. Ainsi la variable qui stocke la valeur de la une propriété
ne doit pas être déclarée public mais les méthodes d'accès doivent bien sûre l'être.
Le nom de la méthode de lecture d'une propriété doit obligatoirement commencer par « get » suivi par le nom de la
propriété dont la première lettre doit être une majuscule. Une telle méthode est souvent appelée « getter » ou « accesseur
» de la propriété. La valeur retournée par cette méthode doit être du type de la propriété.
Exemple ( code java 1.1 ) :
private int longueur;
public int getLongueur () {
  return longueur;
}
Pour les propriétés booléennes, une autre convention peut être utilisée : la méthode peut commencer par «is» au lieu de «
get ». Dans ce cas, la valeur de retour est obligatoirement de type boolean.
Le nom de la méthode permettant la modification d'une propriété doit obligatoirement commencer par « set » suivi par le
nom de la propriété dont la première lettre doit être une majuscule. Une telle méthode est souvent appelée « setter ». Elle
ne retourne aucune valeur et doit avoir en paramètre une variable du type de la propriété qui contiendra sa nouvelle
valeur. Elle devra assurer la mise à jour de la valeur de la propriété en effectuant éventuellement des contrôles et/ou des
traitements (par exemple le rafraîchissement pour un bean visuel dont la propriété affecte l'affichage).
Exemple ( code java 1.1 ) :
private int longueur ;
public void setLongueur (int longueur) {
  this.longueur = longueur;
}
Une propriété peut n'avoir qu'un getter et pas de setter : dans ce cas, la propriété n'est utilisable qu'en lecture seule.
Le nom de la variable d'instance qui contient la valeur de la propriété n'est pas obligatoirement le même que le nom de la
propriété
Il est préférable d'assurer une gestion des accès concurrents dans ces méthodes de lecture et de mise à jour des propriétés
par exemple en déclarant ces méthodes synchronized.
Développons en Java
295

Les méthodes du beans peuvent directement manipuler en lecture et écriture la variable d'instance qui stocke la valeur de
la propriété, mais il est préférable d'utiliser le getter et le setter.
23.2.2. les propriétés indexées (indexed properties)
Ce sont des propriétés qui possèdent plusieurs valeurs stockées dans un tableau.
Pour ces propriétés, il faut aussi définir des méthodes « get » et « set » dont il convient d'ajouter un paramètre de type int
représentant l'index de l'élément du tableau.
Exemple ( code java 1.1 ) :
private float[] notes = new float[5];
public float getNotes (int i ) {
  return notes[i];
}
public void setNotes (int i ; float notes) {
  this.notes[i] = notes;
}
Il est aussi possible de définir des méthodes « get » et « set » permettant de mettre à jour tout le tableau.
Exemple ( code java 1.1 ) :
private float[] notes = new float[5] ;
public float[] getNotes () {
  return notes;
}
public void setNotes (float[] notes) {
  this.notes = notes;
}
23.2.3. Les propriétés liées (Bound properties)
Il est possible d'informer d'autre composant du changement de la valeur d'une propriété d'un bean. Les java beans
peuvent mettre en place un mécanisme qui permet pour une propriété d'enregistrer des composants qui seront informés
du changement de la valeur de la propriété.
Ce mécanisme peut être mis en place grâce à un objet de la classe PropertyChangeSupport qui permet de simplifier la
gestion de la liste des écouteurs et de les informer des changements de valeur d'une propriété. Cette classe définie les
méthodes addPropertyChangeListener() pour enregistrer un composant désirant être informé du changement de la valeur
de la propriété et removePropertyChangeListener()  pour supprimer un composant de la liste.
La méthode firePropertyChange() permet d'informer tous les composants enregistrés du changement de la valeur de la
propriété.
Le plus simple est que le bean hérite de cette classe si possible car les méthodes addPropertyChangeListener() et
removePropertyChangeListener() seront directement héritées.
S i   c e   n ' e s t   p a s   p o s s i b l e ,   i l   e s t   o b l i g a t o i r e   d e   d é f i n i r   l e s   m é t h o d e s   a d d P r o p e r t y C h a n g e L i s t e n e r ( )   e t
removePropertyChangeListener() dans le bean qui appelleront les méthodes correspondantes de l'objet
PropertyChangeSupport.
Exemple ( code java 1.1 ) :
import .Serializable;
import java.beans.*;
public class MonBean03 implements Serializable {
Développons en Java
296

  protected int valeur;
  PropertyChangeSupport changeSupport;
  public MonBean03(){ 
    valeur = 0; 
    changeSupport = new PropertyChangeSupport(this);
  }
  public synchronized void setValeur(int val) {
    int oldValeur = valeur;
    valeur = val;
    changeSupport.firePropertyChange("valeur",oldValeur,valeur);
  }
  public synchronized int getValeur() {
    return valeur;
  }
  public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
    changeSupport.addPropertyChangeListener(listener);
  }
  public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
    changeSupport.removePropertyChangeListener(listener);
  }
}
Les composants qui désirent être enregistrés doivent obligatoirement implémenter l'interface PropertyChangeListener et
définir la méthode propertyChange() déclarée par cette interface.
La méthode propertyChange() reçoit en paramètre un objet de type PropertyChangeEvent qui représente l'événement.
Cette méthode de tous les objets enregistrés est appelée. Le paramètre de type PropertyChangeEvent contient plusieurs
informations :
l'objet source : le bean dont la valeur d'une propriété a changé
• 
le nom de la propriété sous forme de chaîne de caractères
• 
l'ancienne valeur sous forme d'un objet de type Object
• 
la nouvelle valeur sous forme d'un objet de type Object
• 
Pour les traitements, il est souvent nécessaire d'utiliser un cast pour transmettre ou utiliser les objets qui représentent
l'ancienne et la nouvelle valeur.
Méthode
Rôle
public Object getSource()
retourne l'objet source
public Object getNewValue()
retourne la nouvelle valeur de la propriété
public Object getOldValue()
retourne l'ancienne valeur de la propriété
public String getPropertyName
retourne le nom de la propriété modifiée
Exemple ( code java 1.1 ) : un programme qui créé le bean et lui associe un écouteur
import java.beans.*;
import .*;
public class TestMonBean03 {
  public static void main(String[] args) {
    new TestMonBean03();
  }
  public TestMonBean03() {
Développons en Java
297

    MonBean03 monBean = new MonBean03();
    monBean.addPropertyChangeListener( new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent event) {
        .println("propertyChange : valeur = "+ event.getNewValue());
      }
    } );
    .println("valeur = " + monBean.getValeur());
    monBean.setValeur(10);
    .println("valeur = " + monBean.getValeur());
  }
}
Résultat :
C:\tutorial\sources exemples>java TestMonBean03
valeur = 0
propertyChange : valeur = 10
valeur = 10
Pour supprimer un écouteur de la liste du bean, il suffit d'appeler la méthode removePropertyChangeListener() en lui
passant en paramètre un référence sur l'écouteur.
23.2.4. Les propriétés liées avec contraintes (Constrained properties)
Ces propriétés permettent à un ou plusieurs composants de mettre un veto sur la modification de la valeur de la propriété.
Comme pour les propriétés liées, le bean doit gérer un liste de composants « écouteurs » qui souhaitent être informé d'un
changement possible de la valeur de la propriété. Si un composant désire s'opposer à ce changement de valeur, il lève une
exception pour en informer le bean.
Les écouteurs doivent implémenter l'interface VetoableChangeListener qui définie la méthode vetoableChange().
Avant le changement de la valeur, le bean appelle cette méthode vetoableChange() de tous les écouteurs enregistrés. Elle
possède en paramètre un objet de type PropertyChangeEvent qui contient : le bean, le nom de la propriété, l'ancienne
valeur et la nouvelle valeur.
S i   u n   é c o u t e u r   v e u t   s ' o p p o s e r   à   l a   m i s e   à   j o u r   d e   l a   v a l e u r ,   i l   l è v e   u n e   e x c e p t i o n   d e   t y p e
java.beans.PropertyVetoException. Dans ce cas, le bean ne change pas la valeur de la propriété : ces traitements sont à la
charge du programmeur avec notamment la gestion de la capture et du traitement de l'exception dans un bloc try/catch.
La classe  VetoableChangeSupport permet de simplifier la gestion de la liste des écouteurs et de les informer du futur
changement de valeur d'une propriété. Son utilisation est similaire à celle de la classe PropertyChangeSupport.
Pour ces propriétés, pour que les traitements soient complets il faut implémenter le code pour gérer et traiter les
écouteurs qui souhaitent connaître les changements de valeur effectifs de la propriété (voir les propriétés liées).
Exemple ( code java 1.1 ) :
import .Serializable;
import java.beans.*;
public class MonBean04 implements Serializable {
  protected int oldValeur;
  protected int valeur;
  PropertyChangeSupport changeSupport;
  VetoableChangeSupport vetoableSupport;
  public MonBean04(){ 
    valeur = 0; 
    oldValeur = 0;
Développons en Java
298

    changeSupport = new PropertyChangeSupport(this);
    vetoableSupport = new VetoableChangeSupport(this);     
  }
  public synchronized void setValeur(int val) {
    oldValeur = valeur;
    valeur = val;
    try {  
      vetoableSupport.fireVetoableChange("valeur",new Integer(oldValeur),new Integer(valeur));    
    } catch(PropertyVetoException e) {     
      .println("MonBean, un veto est emis :  "+e.getMessage());
      valeur = oldValeur;
    }
    if ( valeur != oldValeur ) {   
      changeSupport.firePropertyChange("valeur",oldValeur,valeur);
    }
  }
  public synchronized int getValeur() {
    return valeur;
  }
  public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
    changeSupport.addPropertyChangeListener(listener);
  }
  public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
    changeSupport.removePropertyChangeListener(listener);
  }
  public synchronized void addVetoableChangeListener(VetoableChangeListener listener) {
    vetoableSupport.addVetoableChangeListener(listener);
  }
  public synchronized void removeVetoableChangeListener(VetoableChangeListener listener) {
    vetoableSupport.removeVetoableChangeListener(listener);
  } 
}
Exemple ( code java 1.1 ) : un programme qui teste le bean. Il émet un veto si la nouvelle valeur de la propriété est
supérieure à 100.
import java.beans.*;
import .*;
public class TestMonBean04 {
  public static void main(String[] args) {
    new TestMonBean04();
  }
  public TestMonBean04() {
    MonBean04 monBean = new MonBean04();
    monBean.addPropertyChangeListener( new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent event) {
        .println("propertyChange : valeur = "+ event.getNewValue());
      }
    } );
    monBean.addVetoableChangeListener( new VetoableChangeListener() {
      public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException {
        .println("vetoableChange : valeur = " + event.getNewValue());
        if( ((Integer)event.getNewValue()).intValue() > 100 )
          throw new PropertyVetoException("valeur superieur a 100",event);
      }
    } );    
    .println("valeur = " + monBean.getValeur());
    monBean.setValeur(10);
Développons en Java
299

    .println("valeur = " + monBean.getValeur());
    monBean.setValeur(200);                       
    .println("valeur = " + monBean.getValeur());
  }
}
Résultat :
C:\tutorial\sources exemples>java TestMonBean04
valeur = 0
vetoableChange : valeur = 10
propertyChange : valeur = 10
valeur = 10
vetoableChange : valeur = 200
vetoableChange : valeur = 10
MonBean, un veto est emis :  valeur superieur a 100
valeur = 10
23.3. Les méthodes
Toutes les méthodes publiques sont visibles de l'extérieures et peuvent donc être appelées.
23.4. Les événements
Les beans utilisent les événements définis dans le modèle par délégation introduit par le J.D.K. 1.1 pour dialoguer. Par
respect de ce modèle, le bean est la source et les autres composants qui souhaitent être informé sont nommé « Listeners »
ou « écouteurs » et doivent s'enregistrer auprès du bean qui maintient la liste des composants enregistrés.
Il est nécessaire de définir les méthodes qui vont permettre de gérer la liste des écouteurs désirant recevoir l'événement. Il
faut définir deux méthodes :
public void addXXXListener( XXXListener li) pour enregistrer l'écouteur li
• 
public void removeXXXListener (XXXListener li) pour enlever l'écouteur li de la liste
• 
L'objet de type XXXListener doit obligatoirement implémenter l'interface .EventListener et son nom doit
terminer par « Listener ».
Les événements peuvent être mono ou multi écouteurs.
Pour les évenements mono écouteurs, la méthode addXXXListener() doit indiquer dans sa signature qu'elle est
succeptible de lever l'exception .TooManyListenersException si un écouteurs tente de s'enregistrer et qu'il y en a
déjà un présent.
23.5. L'introspection
L'introspection est un mécanisme qui permet de déterminer de façon dynamique les caractéristiques d'une classe et donc
d'un bean. Les caractéristiques les plus importantes sont les propriétés, les méthodes et les événements. Le principe de
l'introspection permet à Sun d'éviter de rajouter des éléments au langage pour définir ces caractéristiques.
L'API JavaBean définie la classe java.beans.Introspector qui facilite et standardise la recherche des propriétés, méthodes
et événements du bean. Cette classe possède des méthodes pour analyser le bean et retourner un objet de type BeanInfo
contenant les informations trouvées.
La classe Introspector utilise deux techniques pour retrouver ces informations :
un objet de type BeanInfo, si il y en a un défini par les développeurs du bean
1. 
Développons en Java
300

les mécanismes fournis par l'API reflexion pour extraire les entités qui respectent leur modèle (design pattern)
2. 
respectif.
Il est donc possible de définir un objet BeanInfo qui sera directement utilisé par la classe Introspector. Cette définition est
utile si le bean ne respecte pas certains modèles (designs patterns) ou si certaines entités héritées ne doivent pas être
utilisables. Dans ce cas, le nom de cette classe doit obligatoirement respecter le modèle XXXBeanInfo ou XXX est le
nom du bean correspondant. La classe Introspector recherche une classe respectant ce modèle.
Si une classe BeanInfo pour un bean est définie, une classe qui hérite du bean n'est pas obligée de définir un classe
BeanInfo. Dans ce cas, la classe Introspector utilise les informations du BeanInfo de la classe mère et ajoute les
informations retournée par l'API reflection sur le bean.
Sans classe BeanInfo associée au bean, les méthodes de la classe Introspector utilisent les techniques d'introspection pour
analyser le bean.
23.5.1. Les modèles (designs patterns)
Si la classe Introspector utilise l'API reflection pour déterminer les informations sur le bean et utilise en même temps un
ensembles de modèles sur chacunes des entités propriétés, méthodes et événements.
Pour déterminer les propriétés, la classe Introspector recherche les méthodes getXxx, setXxx et isXxx ou Xxx représente
le nom de la propriété dont la première lettre est en majuscule. La première lettre du nom de la propriété est remise en
minuscule sauf si les deux premières lettres de la propriété sont en majuscules.
Pour déterminer les méthodes, la classe Introspector rechercher toutes les méthodes publiques.
P o u r   d é t e r m i n e r   l e s   é v é n e m e n t s ,   l a   c l a s s e   I n t r o s p e c t o r   r e c h e r c h e   l e s   m é t h o d e s   a d d X x x L i s t e n e r ( )   e t
removeXxxListener(). Si les deux sont présentes, elle en déduit que l'événement xxx est défini dans le bean. Comme pour
les propriétés, la première lettre du nom de l'événement est mis en minuscule.
23.5.2. La classe BeanInfo
La classe BeanInfo contient des informations sur un bean et possède plusieurs méthodes pour les obtenir.       
La méthode getBeanInfo() prend en paramètre un objet de type Class qui représente la classe du bean et elle renvoie des
informations sur la classe et toutes ses classes mères.
Une version surchargée de la méthode accepte deux objets de type Class : le premier représente le bean et le deuxième
représente une classe appartenant à la hiérarchie du bean. Dans ce cas, la recherche d'informations d'arrêtera juste avant
d'arriver à la classe précisée en deuxième argument.
Exemple : obtenir des informations sur le bean uniquement (sans informations sur ces super classes)
Exemple ( code java 1.1 ) :
Class monBeanClasse = Class.forName("monBean");
BeanInfo bi = Introspector.getBeanInfo(monBeanClasse, monBeanClasse.getSuperclass());
La méthode getBeanDescriptor() permet d'obtenir des informations générales sur le bean en renvoyant un objet de type
BeanDescriptor()
La méthode getPropertyDescriptors() permet d'obtenir un tableau d'objets de type PropertyDescriptor qui contient les
caractéristiques d'une propriété. Plusieurs méthodes permettent d'obtenir ces informations.
Exemple ( code java 1.1 ) :
Développons en Java
301

    PropertyDescriptor[] propertyDescriptor = bi.getPropertyDescriptors();
    for (int i=0; i<propertyDescriptor.length; i++) {
      .println(" Nom propriete    : " + 
                          propertyDescriptor[i].getName());
      .println(" Type propriete   : " 
                + propertyDescriptor[i].getPropertyType());
      .println(" Getter propriete : " 
                  + propertyDescriptor[i].getReadMethod());
      .println(" Setter propriete : " 
                 + propertyDescriptor[i].getWriteMethod());
    }
La méthode getMethodDescriptors() permet d'obtenir un tableau d'objets de type MethodDescriptor qui contient les
caractéristiques d'une méthode. Plusieurs méthodes permettent d'obtenir ces informations.
Exemple ( code java 1.1 ) :
   MethodDescriptor[] methodDescriptor;
    unMethodDescriptor = bi.getMethodDescriptors();
    for (int i=0; i < unMethodDescriptor.length; i++) {
      .println(" Methode : "+unMethodDescriptor[i].getName());
    }
La méthode getEventSetDescriptors() permet d'obtenir un tableau d'objets de type EventSetDescriptor qui contient les
caractéristiques d'un événement. Plusieurs méthodes permettent d'obtenir ces informations.
Exemple ( code java 1.1 ) :
    EventSetDescriptor[] unEventSetDescriptor = bi.getEventSetDescriptors();
    for (int i = 0; i < unEventSetDescriptor.length; i++) {
      .println(" Nom evt             : " 
                        + unEventSetDescriptor[i].getName());
      .println(" Methode add evt     : " +
             unEventSetDescriptor[i].getAddListenerMethod());
      .println(" Methode remove evt  : " +
          unEventSetDescriptor[i].getRemoveListenerMethod());
      unMethodDescriptor = unEventSetDescriptor[i].getListenerMethodDescriptors();
      for (int j = 0; j < unMethodDescriptor.length; j++) {
          .println(" Event Type: " + unMethodDescriptor[j].getName());
      }
    }
Exemple complet ( code java 1.1 ) :
import .*;
import java.beans.*;
import .reflect.*;
public class BeanIntrospection {
  static String nomBean; 
  public static void main(String args[]) throws Exception {
    nomBean = args[0];
    new BeanIntrospection();
  }
  public BeanIntrospection() throws Exception {
    Class monBeanClasse = Class.forName(nomBean);
    MethodDescriptor[] unMethodDescriptor;
    BeanInfo bi = Introspector.getBeanInfo(monBeanClasse, monBeanClasse.getSuperclass());
    BeanDescriptor unBeanDescriptor = bi.getBeanDescriptor();
    .println("Nom du bean    : " + unBeanDescriptor.getName());
    .println("Classe du bean : " + unBeanDescriptor.getBeanClass());
    .println("");
Développons en Java
302

    PropertyDescriptor[] propertyDescriptor = bi.getPropertyDescriptors();
    for (int i=0; i<propertyDescriptor.length; i++) {
      .println(" Nom propriete    : " + 
                          propertyDescriptor[i].getName());
      .println(" Type propriete   : " 
                + propertyDescriptor[i].getPropertyType());
      .println(" Getter propriete : " 
                  + propertyDescriptor[i].getReadMethod());
      .println(" Setter propriete : " 
                 + propertyDescriptor[i].getWriteMethod());
    }
    .println("");
    unMethodDescriptor = bi.getMethodDescriptors();
    for (int i=0; i < unMethodDescriptor.length; i++) {
      .println(" Methode : "+unMethodDescriptor[i].getName());
    }
    .println("");
    EventSetDescriptor[] unEventSetDescriptor = bi.getEventSetDescriptors();
    for (int i = 0; i < unEventSetDescriptor.length; i++) {
      .println(" Nom evt             : " 
                        + unEventSetDescriptor[i].getName());
      .println(" Methode add evt     : " +
             unEventSetDescriptor[i].getAddListenerMethod());
      .println(" Methode remove evt  : " +
          unEventSetDescriptor[i].getRemoveListenerMethod());
      unMethodDescriptor = unEventSetDescriptor[i].getListenerMethodDescriptors();
      for (int j = 0; j < unMethodDescriptor.length; j++) {
          .println(" Event Type: " + unMethodDescriptor[j].getName());
      }
    }
    .println("");
  }
}
23.6. Paramétrage du bean ( Customization )
Il est possible de développer un éditeur de propriétés spécifique pour permettre de personnaliser la modification des
paramètres du bean.
La suite de cette section sera développée dans une version future de ce document
23.7. La persistance
Les propriétés du bean doivent pouvoir être sauvés pour être restitués ultérieurement. Le mécanisme utilisé est la
sérialisation. Pour permettre d'utiliser ce mécanisme, le bean doit implémenter l'interface Serializable
23.8. La diffusion sous forme de jar
Pour diffuser un bean sous forme de jar, il faut définir un fichier manifest.
Ce fichier doit obligatoirement contenir un attribut Name: qui contient le nom complet de la classe (incluant le package)
et un attribut Java?Bean: valorisé à True.
Développons en Java
303

Exemple de fichier manifest pour un bean :
   Name: MonBean.class
    Java?Bean: True
La suite de cette section sera développée dans une version future de ce document
23.9. Le B.D.K.
L'outils principal du B.D.K. est la BeanBox. Cet outils écrit en java permet d'assembler des beans.
Pour utiliser un bean dans la BeanBox, il faut qu'il soit utilisé sous forme d'archive jar.
La suite de cette section sera développée dans une version future de ce document
Développons en Java
304

24. Logging
Le logging est important dans toutes les applications pour permettre de faciliter le debuggage lors du développement et
de conserver une trace de son exécution lors de l'exploitation en production.
Une API très répandue est celle développée par le projet open source log4j développé par le groupe Jakarta.
Concient de l'importance du logging, Sun a développé et intégré au JDK 1.4 une API dédiée. Cette API est plus simple à
utiliser et elle offre moins de fonctionnalités que log4j mais elle a l'avantage d'être fournie directement avec le JDK.
24.1. Log4j
Log4j est un projet open source distribué sous la licence Apache Software.
La dernière version de log4j est téléchargeable à l'url
les sources complètes et la documentation. Log4j est compatible avec le JDK
1.1.
Cette API permet aux développeurs d'utiliser et de paramétrer les traitements de logs. Il est possible de fournir les
paramètres de l'outils dans un fichier de configuration. Log4j est thread?safe.
Log4j utilise trois composants principaux :
Categories : ils premettent de gérer les logs
• 
Appenders : ils représentent les flux qui vont recevoir les messages de log
• 
Layouts : ils permettent de formatter le contenu des messages de la log
• 
24.1.1. Les catégories
Les catégories déterminent si un message doit être envoyé dans la ou les logs. Elles sont représentées par la classe
org.apache.log4j.Category
Chaque catégorie possède un nom qui est sensible à la casse. Pour créer une categorie, il suffit d'instancier un objet
Category. Pour réaliser cette instanciation, la classe Category fournie une méthode statique getInstance() qui attend en
paramètre le nom de la categorie. Si une catégorie existe déjà avec le nom fournie, alors la méthode getInstance() renvoie
une instance sur cette catégorie.
Il est pratique de fournir le nom complet de la classe comme nom de la catégorie dans laquelle elle est instanciée mais ce
n'est pas obligation. Il est ainsi possible de créer une hiérarchie spécifique différente de celle de l'application, par
exemple basée sur des aspects fonctionnels. L'inconvénient d'associer le nom de la classe au nom de la catégorie est qu'il
faut instancier un objet Category dans chaque classe. Le plus pratique est de déclarer cette objet static.
Développons en Java
305

Exemple :
public class Classe1 {
  static Category category = Category.getInstance(Classe1.class.getName());
  ...
}
La méthode log(Priority, Object) permet de demander l'envoie dans la log du message avec la priorité fournie.
Il existe en plus une méthode qui permet de demander l'envoie d'un message dans la log pour chaque priorité :
debug(Object), info(Object), warn(Object), error(Object), fatal(Object).
La demande est traitée en fonction de la hiérarchie de la catégorie et de la priorité du message et de cette de la catégorie.
Pour éviter d'éventuels traitements pour créer le message, il est possible d'utiliser la méthode isEnabledFor(Priority) pour
savoir si la catégorie traite la priorité ou non
Exemple :
import org.apache.log4j.*;
public class TestIsEnabledFor {
  static Category cat1 = Category.getInstance(TestIsEnabledFor.class.getName());
  public static void main(String[] args) {
    int i=1;
    int[] occurence={10,20,30};
    BasicConfigurator.configure();
    cat1.setPriority() ; 
    ("message de test");
    if(cat1.isEnabledFor()) {
      .println("traitement du message de priorité INFO");     
      ("La valeur de l'occurence "+i+" = " + String.valueOf(occurence[i]));
    }
    if(cat1.isEnabledFor()) {
      .println("traitement du message de priorité WARN");     
      ("La valeur de l'occurence "+i+" = " + String.valueOf(occurence[i]));
    }
  }
}
Résultat :
0 [main] WARN TestIsEnabledFor  ? message de test
traitement du message de priorit_ WARN
50 [main] WARN TestIsEnabledFor  ? La valeur de l'occurence 1 = 20
24.1.1.1. La hiérarchie dans les catégories
Le nom de la categorie permet de la placer dans une hierarchie dont la racine est une catégorie spéciale nommée root qui
est créée par défaut sans nom.
La classe Category possède une classe statique getRoot() pour obtenir la catégorie racine.
La hiérarchie des noms est établie grace à la notation par point comme pour les packages.
Développons en Java
306

Exemple : soit trois catégories
categorie1 nommée "org"
categorie2 nommée ""
categorie3 nommée ".projet"
Categorie3 est fille de categorie2, elle même fille de categorie1.
Cette relation hiérarchique est importante car la configuration établie pour une catagorie est automatiquement propagée
par défaut aux categories enfants.
L'ordre de la création des catégories de la hiérarchie ne doit pas obligatoirement respecter l'ordre de la hiérarchie. Celle ci
est constituée au fur et à mesure de la création des catégories.
24.1.1.2. Les priorités
Log4j gére des priorités pour permettre à la categorie de déterminer si le message sera envoyé dans la log. Il existe cinq
priorités qui possèdent un ordre hiérarchique croissant :
DEBUG
• 
INFO
• 
WARN
• 
ERROR
• 
FATAL
• 
La classe org.apache.log4j.Priority encapsule ces priorités.
Chaque catégorie est associé à une priorité qui peut être changée dynamiquement. La catégorie détermine si un message
doit être envoyé dans la log en comparant sa priorité avec la priorité du message. Si celle est supérieure ou égale à la
priorité de la catégorie, alors le message est envoyé dans la log.
La méthode setPropriety() de la classe Category permet de préciser la priorité de la categorie.
Si aucune priorité n'est donnée à une catégorie, elle "hérite" de la priorité de la première catégorie en remontant dans la
hiérarchie dont la priorité est renseignée.
Exemple : soit trois catégories
root associée à la priorité INFO
categorie1 nommée "org" sans priorité particulière
categorie2 nommée "" associée à la priorité ERROR
categorie3 nommée ".projet" sans priorité particulière
Une demande avec la priorité DEBUG sur categorie2 n'est pas traitée car la priorité INFO héritée est supérieure à
DEBUG.
Une demande avec la priorité WARN sur categorie2 est traitée car la priorité INFO héritée est inférieure à WARN .
Une demande avec la priorité DEBUG sur categorie3 n'est pas traitée car la priorité ERROR héritée est supérieure à
DEBUG.
Une demande avec la priorité FATAL sur categorie3 est traitée car la priorité ERROR héritée est inférieure à FATAL.
En fait dans l'exemple, aucune demande avec la priorité DEBUG ne sera traitée.
Au niveau applicatif, il est possible d'interdire le traitement d'une priorité et de celle inférieure en utilisant le code suivant
: Category.getDefaultHierarchy().disable(). Il faut fournir la priorité à la méthode disable().
Il est possible d'annuler ce traitement dynamiquement en positionnement la propriété système : log4j.disableOverride.
24.1.2. Les Appenders
L'interface org.apache.log4j.Appender désigne un flux qui représente la log et se charge de l'envoie de message formatté
ce flux. Le formattage proprement dit est réalisé par un objet de type Layout. Ce layout peut être fourni dans le
Développons en Java
307

constructeur adapté ou par la méthode setLayout().
Une catégorie peut posséder plusieurs appenders. Si la catégorie décide de traiter la demande de message, le message est
envoyés à chacun des appenders. Pour ajouter un appender à un catégorie, il suffit d'utiliser la méthode addAppender()
qui attend en paramètre un objet de type Appender.
L'interface Appender est directement implémentée par la classe abstraite AppenderSkeleton. Cette classe est la classe
mère de toutes les classes fournies avec log4j pour représenter un type de log :
AsyncAppender
• 
JMSAppender
• 
NTEventLogAppender : log envoyée dans la log des évenements sur un système Windows NT
• 
NullAppender
• 
SMTPAppender
• 
SocketAppender : log envoyées dans une socket
• 
SyslogAppender : log envoyée dans le demon syslog d'un système Unix
• 
WriterAppender : cette classe possède deux classes filles : ConsoleAppender et FileAppender. La classe
• 
FileAppender possède deux classes filles : DailyRollingAppender, RollingFileAppender
Pour créer un appender, il suffit d'instancier un objet d'une de ces classes.
Tout comme les priorités, les appenders d'une categorie mère sont héritées par les categories filles. Pour éviter cette
héritage par défaut, il faut mettre le champ additivity à false en utilisant la méthode setAdditivity() de la classe Category.
24.1.3. Les layouts
Ces composants représenté par la classe org.apache.log4j.Layout permettent de définir le format de la log. Un layout est
associé à un appender lors de son instanciation.
Il existe plusieurs layouts définis par log4j :
DateLayout
• 
HTMLLayout
• 
PatternLayout
• 
SimpleLayout
• 
XMLLayout
• 
Le PatternLayout permet de préciser le format de la log grâce à des motifs qui sont dynamiquement remplacés par leur
valeur à l'éxécution. Les motifs commencent par un caractère % suivi d'une lettre :
Motif
Role
%c
le nom de la catégorie qui a émis le message
%C
le nom de la classe qui a émis le message
%d
le timestamp de l'émission du message
%m
le message
%n
un retour chariot
%p
la priorité du message
%r
le nombre de milliseconde écoulé entre le lancement de l'application et l'émission du message
%t
le nom du thread
%x
NDC du thread
%%
le caractère %
Développons en Java
308

Il est possible de préciser le formattage de chaque motif grâce à un alignement et/ou une le tableau ci
dessous, la caractère # représente une des lettres du tableau ci dessus, n représente un nombre de caractères.
Motif
Role
%#
aucun formattage (par défaut)
%n#
alignement à droite, des blancs sont ajoutés si la taille du motif est inférieure à n caractères
%?n#
alignement à gauche, des blanc sont ajoutés si la taille du motif est inférieure à n caractères
%.n
tronque le motif si il est supérieur à n caractères
alignement à gauche, taille du motif obligatoirement de n caractères (troncature ou complément avec
%?n.n#
des blancs)
24.1.4. La configuration
Pour faciliter la configuration de log4j, l'API fournie plusieurs classes qui implémentent l'interface Configurator. La
classe BasicConfgurator est le classe mère des classes PropertyConfigurator (pour la configuration via un fichier de
propriétés) et DOMConfigurator (pour la configuration via un fichier XML).
La classe BasicConfigurator permet de configurer la catégorie root avec des valeurs par défaut. L'appel à la méthode
configure() ajoute à la catégorie root la priorité DEBUG et un ConsoleAppender vers la sortie standard ()
associé à un PatternLayout (TTCC_CONVERSION_PATTERN qui est une constante défnie dans la classe
PatternLayout).
Exemple :
import org.apache.log4j.*;
public class TestBasicConfigurator {
  static Category cat = Category.getInstance(TestBasicConfigurator.class.getName()) ;
  public static void main(String[] args) {
    BasicConfigurator.configure();
    ("Mon message");
  }
}
Résultat :
0 [main] INFO TestBasicConfigurator  ? Mon message
La classe PropertyConfigurator permet de configurer log4j à partir d'un fichier de propriétés ce qui évite la recompilation
de classes pour modifier la configuration. La méthode configure() qui attend un nom de fichier permet de charger la
configuration.
Exemple :
import org.apache.log4j.*;
public class TestLogging6 {
   static Category cat = Category.getInstance(TestLogging6.class.getName());
   public static void main(String[] args) {
      PropertyConfigurator.configure("logging6.properties");
      ("Mon message");
   }
Développons en Java
309

}
Exemple : le fichier loggin6.properties de configuration de log4j
# Affecte a la categorie root la priorité DEBUG et un appender nommé CONSOLE_APP
log4j.rootCategory=DEBUG, CONSOLE_APP
# le appender CONSOL_APP est associé à la console
log4j.appender.CONSOLE_APP=org.apache.log4j.ConsoleAppender
# CONSOLE_APP utilise un PatternLayout qui affiche : le nom du thread, la priorité, 
# le nom de la categorie et le message
log4j.appender.CONSOLE_APP.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE_APP.layout.ConversionPattern= [%t] %p %c ? %m%n
Résultat :
C:\>java TestLogging6
[main] INFO TestLogging6 ? Mon message
La classe DOMConfigurator permet de configurer log4j à partir d'un fichier XML ce qui évite aussi la recompilation de
classes pour modifier la configuration. L méthode configure() qui attend un nom de fichier permet de charger la
configuration. Cette méthode nécessite un parser XML de type DOM compatible avec l'API JAXP.
Exemple :
import org.apache.log4j.*;
import .*;
public class TestLogging7 {
   static Category cat = Category.getInstance(TestLogging7.class.getName());
   public static void main(String[] args) {
      try {
         DOMConfigurator.configure("");
      } catch (Exception e) {
         e.printStackTrace();
      }
      ("Mon message");
   }
}
Exemple : le fichier de configuration de log4j
<?xml version="1.0" encoding="UTF?8" ?>
<!DOCTYPE log4j:configuration SYSTEM "">
<log4j:configuration xmlns:log4j=";>
  <appender name="CONSOLE_APP" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="[%t] %p %c ? %m%n"/>
    </layout>
  </appender>
  <root>
    <priority value ="DEBUG" />
    <appender?ref ref="CONSOLE_APP" />
  </root>
</log4j:configuration>
Résultat :
C:\j2sdk1.4.0?rc\bin>java TestLogging7
[main] INFO TestLogging7 ? Mon message
Développons en Java
310

24.2. L'API logging
L'usage de fonctionnalités de logging dans les applications est tellement répendu que SUN a décidé de développer sa
propre API et de l'intégrer au JDK à partir de la version 1.4.
Cette API a été proposée à la communauté sous la Java Specification Request numéro 047 (JSR?047).
Le but est de proposé un système qui puisse être exploitée facilement par toutes les applications.
L'API repose sur cinq classes principales et une interface:
Logger : cette classe permet d'envoyer des messages sans le système de log
• 
LogRecord : cette classe encapsule le message
• 
Handler : cette classe représente la destination qui va recevoir les messages
• 
Formatter : cette classe permet de formatter le message avant son envoie vers la destination
• 
Filter : cette interface doit être implémentée par les classes dont le but est de déterminer si le message doit être
• 
envoyé vers une destination
Level : cette représente le niveau de gravité du message
• 
Un logger possède un ou plusieurs Handlers qui sont des entités qui vont recevoir les messages. Chaque handler peut
avoir un filtre associé en plus du filtre associé au Logger.
Chaque message possède un niveau de sévérité représenté par la classe Level.
24.2.1. La classe LogManager
Cette classe est un singleton qui propose la méthode getLogManager() pour obtenir l'unique référence sur un objet de ce
type.
Cette objet permet :
de maintenir une liste de Logger désigné par un nom unique.
• 
de maintenir une liste de Handlers globaux
• 
de modifier le niveau de sévérité pris en compte pour un ou plusieurs Logger dont le début du nom est précisé
• 
Pour réaliser ces actions, la classe LogManager possède plusieurs méthodes dont les principales sont :
Méthode
Rôle
void addGlobalHandler(Handler)
Ajoute un handler à la liste des handler globaux
Permet d'ajouter un nouveau Logger dont le nom fourni en
Logger getLogger(String)
paramère lui sera attribué si il n'existe pas encore sinon la
référence sur le Logger qui possède déjà ce nom est renvoyé.
void removeAllGlobalHandlers()
Supprime tous les Handler de la listede handler globaux
void removeGlobalHandler(Handler)
Supprime le Handler de la liste de Handler globaux
Permet de préciser le niveau de tout les Logger dont le nom
void setLevel(String, Level)
commence par la chaine fournie en paramètre
LogManager getLogManager()
Renvoie l'instance unique de cette classe
Par défaut, la liste des Loggers contient toujours un Logger nommé global qui peut être facilement utilisé.
Développons en Java
311

24.2.2. La classe Logger
La classe Logger est la classe qui se charge d'envoyer les messages dans la log. Un Logger est identifié par un nom qui
est habituellement le nom qualifié de la classe dans laquelle le Logger est utilisé. Ce nom permet de gérer une hiérarchie
de Logger. Cette gestion est assurée par le LogManager. Cette hiérarchie permet d'appliquer des modifications sur un
Logger ainsi qu'à toute sa "descendance".
Il est aussi de possible de créer des Logger anonymes.
La méthode getLogger() de la classe LogManager permet d'instancier un nouvel objet Logger si aucun Logger possédant
le nom passé en paramètre a déjà été défini sinon il renvoie l'instance existante.
La classe Logger se charge d'envoyer les messages aux Handlers enregistrés sous la forme d'un objet de type LogRecord.
Par défaut, ces Handlers sont ceux enregistrés dans le LogManager. L'envoie des messages est conditionnés par la
comparaison du niveau de sévérité de message avec celui associé au Logger.
La classe Logger possède de nombreuses méthodes pour générer des messages : plusieurs méthodes sont définis pour
chaque niveau de sécurité. Plutôt que d'utiliser la méthode log() en précisant le niveau de sévérité, il est possible d'utiliser
la méthode correspondante au niveau de sécurité.
Ces méthodes sont surchargées pour accepter plusieurs paramètres :
le nom de la classe, le nom de la méthode et le message : les deux premières données sont très utiles pour
• 
faciliter le debuggage
le message: dans ce cas, le framework tente de déterminer dynamiquement le nom de la classe et de la méthode
• 
24.2.3. La classe Level
Chaque message est associé à un niveau de sévérité représenté par un objet de type Level. Cette classe définie7 niveaux
de sévérité :
Level.SEVERE
• 
Level.WARNING
• 

• 
Level.CONFIG
• 

• 
Level.FINER
• 
Level.FINEST
• 
24.2.4. La classe LogRecord
24.2.5. La classe Handler
Le framework propose plusieurs classe filles qui représentent différents moyens pour émettre les messages :
StreamHandler : envoie des messages dans un flux de sortie
• 
ConsoleHandler : envoie des messages sur la sortie standard d'erreur
• 
FileHandler : envoie des messages sur un fichier
• 
SocketHandler : envoie des messages dans une socket réseau
• 
MemoryHandler : envoie des messages dans un tampon en mémoire
• 
Développons en Java
312

24.2.6. La classe Filter
24.2.7. La classe Formatter
Le framework propose deux implémentations :
SimpleFormatter : pour formatter l'enregistrement sous forme de chaine de caractères
• 
XMLFormatter : pour formatter l'enregistrement au format XML
• 
XMLFormatter utilise un DTD particulière. Le tag racine est <log>. Chaque enregistrement est inclus dans un tag
<record>.
24.2.8. Le fichier de configuration
Un fichier particulier au format Properties permet de préciser des paramètres de configuration pour le système de log tel
que le niveau de sévérité géré par un Logger particulier et sa descendance, les paramètres de configuration des Handlers
...
Il est possible de préciser le niveau de sévérité pris en compte par tous les Logger :
.level = niveau
Il est possible de définir les handlers par défaut :
handlers = .logging.FileHandler
Pour préciser d'autre handler, il faut les séparer par des virgules.
Pour préciser le niveau de sévérité d'un Handler, il suffit de le lui préciser :
.logging.FileHandler.level = niveau
Un fichier par défaut est défini avec les autres fichiers de configuration dans le répertoire lib du JRE. Ce fichier ce
nomme logging.properties.
Il est possible de préciser un fichier particulier précisant son nom dans la propriété système
exemple : java ?=monLogging.properties
24.2.9. Exemples d'utilisation
Cette section sera développée dans une version future de ce document
24.3. D'autres API de logging
Il existe d'autres API de logging dont voici une liste non exhaustive :
Développons en Java
313

Produit
URL
Lumberjack

Javalog

Jlogger de Javelin Software

Développons en Java
314

25. La sécurité
La suite de ce chapitre sera développée dans une version future de ce document
25.1. Introduction
Depuis sa conception, la sécurité dans le langage Java toujours a été une grande préoccupation pour Sun.
Avec Java, la sécurité revert de nombreux aspects :
les spécifications du langage dispose de fonctionnalité pour renforcer la sécurité du code
• 
la plate?forme définit un modèle pour gérer les droits d’une application
• 
l’API JCE permet d’utiliser des technologies de cryptographie
• 
l’API JSSE permet d’utiliser le réseau au travers des protocoles sécurisés SSL ou TLS
• 
l’API JAAS propose un service pour gérer l’authentification et les autorisations d’un utilisateur
• 
Ces deux premiers aspects ont été intégrés à java dès sa première version.
25.2. La sécurité dans les spécifications du langage
Les spécifications du langage apportent de nombreuses fonctionnalités pour renforcer la sécurité du code aussi bien lors
de la phase de compilation que lors de la phase d'exécution :
typage fort (toutes les variables doivent posséder un type)
• 
initialisation des variables d'instances avec des valeurs par défaut
• 
modificateur d'accès pour gérer l'encapsulation et donc l'accessibilité aux membres d'un objet
• 
les membres final
• 
...
• 
25.2.1. Les contrôles lors de la compilation
Développons en Java
315

25.2.2. Les contrôles lors de l'exécution
La JVM exécute un certain nombre de contrôle au moment de l'exécution :
vérificatin des accès en dehors des limites des tableaux
• 
contrôle de l'utilisation des casts
• 
vérification par le classloader de l'intégrité des classes utilisées
• 
...
• 
25.3. Le contrôle des droits d’une application
Un système de contrôle des droits des applications a été intégré à Java dès sa première version notamment pour permettre
de sécuriser l'exécution des applets. Ces applications téléchargées sur le réseau et exécutées sur le poste client doivent
impérativement assurer aux personnes qui les utilisent que celles?ci ne risquent pas de réaliser des actions malveillantes
sur le système dans lequel elles s'exécutent.
Le modèle de sécurité relatif aux droits des applications développées en Java a évolué au fur et à mesure des différentes
versions de Java.
25.3.1. Le modèle de sécurité de Java 1.0
Le modèle proposé par Java 1.0 est très sommaire puisqu'il ne distingue que deux catégories d'applications :
les applications locales
• 
les applications téléchargées sur le réseau
• 
Le modèle est basé sur le "tout ou rien". Les applications locales ont tous les droits et les applications téléchargées ont
des droits très limités. Les restictions de ces dernières sont nombreuses :
impossibilité d'écrire sur le disque local
• 
impossibilité d'obtenir des informations sur le système local
• 
impossibilité de se connecter à un autre serveur que celui d'ou l'application a été téléchargée
• 
...
• 
La mise en oeuvre de ce modèle est assuré par le "bac à sable" (sand box en anglais) dans lequel s'exécute les
applications téléchargées.
25.3.2. Le modèle de sécurité de Java 1.1
Le modèle proposé par la version 1.0 est très efficace mais beaucoup trop restrictif surtout dans le cadre d'utilisation
personnelle tel que des applications pour un intranet par exemple.
Le modèle de la version 1.1 propose la possibilité de signer les applications packagées dans un fichier .jar. Une
application ainsi signée possède les mêmes droits qu'une application locale.
25.3.3. Le modèle Java 1.2
Le modèle proposé par la version 1.1 a apporté de début de solution pour attribuer des droits sensibles à certaines
applications. Mais ce modèle manque cruellement de souplesse puisqu'il s'appuit toujours sur le modèle "tout au rien".
Le modèle de la version 1.2 apporte enfin une solution très souple mais plus compliquée à mettre en oeuvre.
Développons en Java
316

Les droits accordés à une application sont rassemblés dans un fichier externe au code qui se nomme politique de sécurité.
Ces fichiers se situe dans le répertoire lib/security du répertoire ou est installé le JRE. Par convention, ces fichiers ont
pour extension .policy.
25.4. JCE (Java Cryptography Extension)
JCE est une API qui propose de standardiser l'utilisation de la cryptographie en restant indépendant des algorithmes
utilisés. Elle prend en compte le cryptage/décryptage de données, la génération de clés, et l'utilisation de la technolgoie
MAC (Message Authentication Code) pour garantir l'intégrité d'un message.
JCE a été intégré au JDK 1.4. Auparavant, cette API était disponible en tant qu'extension pour les JDK 1.2 et 1.3.
Pour pouvoir utiliser cette API, il faut obligatoirement utiliser une implémentation développée par un fournisseur
(provider). Avec le JDK 1.4, Sun fournit une implémentation de référence nommée SunJCE.
Les classes et interfaces de l'API sont regroupées dans le package javax.crypto
25.4.1. La classe Cipher
Cette classe encapsule le cryptage et le décyptage de données.
La méthode statique getInstance() permet d'obtenir une instance particulière d'un algorithme fourni par un fournisseur. Le
nom de l'algorithme est fourni en paramètre de la méthode sous la forme d'une chaine de caractères.
Avant la première utilisation de l'instance obtenue, il faut initialiser l'objet en utilisant une des nombreuses surcharges de
la méthode init().
25.5. JSSE (Java Secure Sockets Extension)
Les classes et interfaces de cette API sont regroupées dans les packages et .
25.6. JAAS (Java Authentication and Authorization Service)
Les classes et interfaces de cette API sont regroupées dans le package
Cette API a été intégrée au J.D.K. 1.4.
Développons en Java
317

Partie 4 : Développement d'applications d'entreprises
Cette quatrième partie traite d'une utilisation de java en forte expansion : le développement côté serveur. Ce type de
développement est poussée par l'utilisation d'internet notamment.
Ces développements sont tellements important que Sun propose une véritable plate?forme, basée sur le J2SE et orienté
entreprise dont les API assurent le développement côté serveur : J2EE (Java 2 Entreprise Edition).
Cette partie regroupe plusieurs chapitres :
J2EE : introduit la plate?forme Java 2 Entreprise Edition
• 
les servlets : plonge au coeur de l'API servlet qui est un des composants de base pour le développement
• 
d'applications Web
les JSP : poursuit la discusion avec les servlets en explorant un mécanisme basé sur celles ci pour réaliser
• 
facilement des pages web dynamiques
XML : présente XML qui est un technologie tendant à s'imposer pour les échanges de données et explore les
• 
API java pour utiliser XML
JNDI : introduit l'API capable d'acceder aux services de nommage et d'annuaires
• 
JMS : indique comment utiliser cette API qui permet l'utilisation de système de messages pour l'échange de
• 
données entre applications
Java Mail : traite de l'API qui permet l'envoie et la réception d'e mail
• 
EJB : propose une présentation del'API et les spécifications pour des objets chargés de contenir les règles
• 
métiers
les services web :
• 
Développons en Java
318

26. J2EE
J2EE est l'acronyme de Java 2 Entreprise Edition. Cette édition est dédiée à la réalisation d'applications pour entreprises.
J2EE est basée sur J2SE (Java 2 Standard Edition) qui contient les API de bases de java.
J2EE est une plate?forme fortement orientée serveur pour le développement et l'éxécution d'applications distribuées. Elle
est composée de deux parties essentielles :
un ensemble de spécifications pour une infrastructure dans laquelle s'éxécute les composants écrits en java : un
• 
tel environnement se nomme serveur d'application.
un ensemble d'API qui peuvent être obtenues et utilisées séparement. Pour être utilisées, certaines nécessitent
• 
une implémentation de la part d'un fournisseur tiers.
Sun propose une implémentation minimale des spécifications de J2EE : le J2EE SDK. Cette implémentation permet de
développer des applications respectant les spécifications mais n'est pas prévue pour être utilisée dans un environnement
de production. Ces spécifications doivent être respectées par les outils développés par des éditeurs tiers.
L'utilisation de J2EE pour développer et éxécuter une application propose plusieurs avantages :
une architecture d'application basée sur les composants qui permet un découpage de l'application et donc une
• 
séparation des rôles lors du développement
la possibilité de s'interfacer avec le système d'information existant grace à de nombreuses API : JDBC, JNDI,
• 
JMS ...
la possibilité de choisisir les outils de développement et le ou les serveurs d'application utilisés qu'ils soient
• 
commercials ou libres
J2EE permet une grande fléxibilité dans le choix de l'architecture de l'application en combinant les differents
composants. Ce choix dépend des besoins auxquels doit répondre l'application mais aussi des compétences dans les
différentes API de J2EE. L'architecture d'une application se découpe en au moins trois tiers :
la partie cliente : c'est la partie qui permet le dialogue avec l'utilisateur. Elle peut être composé d'une application
• 
standalone, d'une application web ou d'applets
la partie métier :
• 
la partie données :
• 
La suite de ce chapitre sera développée dans une version future de ce document
Développons en Java
319

26.1. Les API de J2EE
J2EE regroupe un ensemble d'API pour le développement d'applications d'entreprise.
version de
version de
API
Rôle
l'API dans
l'API dans
J2EE 1.2
J2EE 1.3
Entreprise java bean (EJB)
Composants serveurs contenant la logique métier
1.1
2.0
RMI permet d'utilisation d'objet java distribué.
Remote Méthod Invocation RMI?IIOP est une extension de RMI pour utiliser avec
1.0
(RMI) et RMI?IIOP
CORBA.
Java Naming and Directory Accès aux services de nommage et aux annuaires
1.2
1.2
Interface (JNDI)
d'entreprises
Java Database
Accès aux bases de données. J2EE intègre une extension
2.0
2.0
Connectivity (JDBC)
de cette API
Java Transaction API
(JTA)
Support des transactions
1.0
1.0
Java Transaction Service
(JTS)
Java Messaging service
Support de messages via des MOM (Messages Oriented
1.0
1.0
(JMS)
Middleware)
Composants basé sur le concept C/S pour ajouter des
Servlets
fonctionnalités à un serveur. Pour le moment,
2.2
2.3
principalement utilisé pour étendre un serveur web
JSP
1.1
1.2
Java IDL
Utilisation de CORBA
JavaMail
Envoie et réception d'email
1.1
1.2
J2EE Connector
Connecteurs pour accéder à des ressources de
1.0
Architecture (JCA)
l'entreprises tel que CICS, TUXEDO, SAP ...
Java API for XML Parsing
Analyse et exploitation de données au format XML
1.1
(JAXP)
Java Authentication and
Authorization Service
Echange sécurisé de données
1.0
(JAAS)
JavaBeans Activation
Utilisé par JavaMail : permet de déterminer le type mime
1.2
Framework
Connection au système d'information de l'entreprise
J2EE Connector
grace à des adaptateurs fournis par des éditeurs tiers
Architecture (JCA)
(ERP, mainframe ...)
Ces API peuvent être regroupées en trois grandes catégories :
les composants : Servlet, JSP, EJB
• 
les services : JDBC, JTA/JTS, JNDI, JCA, JAAS
• 
la communication : RMI?IIOP, JMS, Java Mail
• 
Développons en Java
320

26.2. L'environnement d'éxécution des applications J2EE
J2EE propose des spécifications pour une infrastructure dans laquelle s'éxécute les composants. Ces spécifications
décrivent les rôles de chaque éléments et précisent un ensemble d'interfaces pour permettre à chacun de ces éléments de
communiquer.
Ceci permet de séparer les applications et l'environnement dans lequel il s'éxécute. Les spécifications précisent à l'aide
des API un certain nombre de fonctionnalités que doivent implémenter l'environnement d'exécution. Ces fonctionnalités
sont de bas niveau ce qui permet aux développeurs de se concentrer sur la logique métier.
Pour éxecuter ces composants de natures différentes, J2EE défini des conteneurs pour chacun de ces composants. Il
définit pour chaque composants des interfaces qui leur permettront de dialoguer avec les composants lors de leur
execution. Les conteneurs permettent aux applications d'accéder aux ressources et aux services en utilisant les API.
Les appels aux applications se font par des clients via les conteneurs. Les clients n'accèdent pas directement aux
applications mais sollicite le conteneur.
26.2.1. Les conteneurs
Les conteneurs assurent la gestion du cycle de vie des composants qui s'éxécutent en eux.
Les conteneurs fournissent des services qui peuvent être utilisés par les applications lors de leur éxécution.
Pour déployer une application dans un conteneur, il faut lui fournir deux éléments :
l'application avec tous les composants (classes compilées, ressources ...) regroupée dans une archive ou module.
• 
Chaque conteneur possède son propre format d'archive.
un fichier descripteur de déploiement contenu dans le module qui précise au conteneur des options pour
• 
éxécuter l'application
Il existe trois types d'archive :
Archive /
Descripteur de
Contenu
Extension
module
déploiement
java
Regroupe des classes
jar
application?
Regroupe les servlets et les JSP ainsi que les ressources necessaires
web
war

à leur execution (classes, bibliothèques de balises, images, ...)
EJB
Regroupe les EJB et leur composants (classes)
jar
ejb?
Une application est un regroupement d'une ou plusieurs modules dans un fichier EAR (Entreprise ARchive).
L'application est décrite dans un fichier lui même contenu dans le fichier EAR
Il existe autant de conteneurs que de type d'applications :
conteneur web : pour éxécuter les servlets et les JSP
• 
conteneur d'EJB : pour éxécuter les EJB
• 
Développons en Java
321

Les serveurs d'application peuvent fournir un seul type de conteneur ou les deux.
26.2.2. Le conteneur web
L'implémentation de référence pour ce type de conteneur est le projet open source Tomcat du groupe Apache.
26.2.3. Le conteneur d'EJB
26.2.4. Les services proposés par la plateforme J2EE
Une plateforme d'execution J2EE complète implementé dans un serveur d'application propose les services suivants :
service de nommage (naming service)
• 
service de déploiement (deployment service)
• 
service de gestion des transactions (transaction service)
• 
service de sécurité (security service)
• 
Ces services sont utilisés directement ou indirectement par les conteneurs mais aussi par les composants qui s'éxécutent
dans les conteneurs grace à leurs API respectives.
26.3. L'assemblage et le déploiement d'applications J2EE
J2EE propose une spécification pour décrire le mode d'assemblage et de déploiement d'une application J2EE.
Une application J2EE peut regrouper différents modules : modules web, modules EJB ... Chacun de ces modules possède
son propre mode de packaging. J2EE propose de regrouper ces différents modules dans un module unique sous la forme
d'un fichier EAR (Entreprise ARchive).
Le format de cet archive est très semblable à celui des autres archives :
un contenu : les différents modules qui composent l'application (module web, EJB, fichier RAR ... )
• 
un fichier descripteur de déploiement
• 
Les serveurs d'application extraient chaque modules du fichier EAR et les déploient séparément un par un.
26.3.1. Le contenu et l'organisation d'un fichier EAR
Le fichier EAR est composé au minimum :
d'un ou plusieurs modules
• 
un répertoire META?INF contenant un fichier descripteur de déploiement nommé
• 
Développons en Java
322

Les modules ne doivent pas obligatoirement être insérés à la racine du fichier EAR : ils peuvent être mis dans un des
sous répertoires pour organiser le contenu de l'application. Il est par exemple pratique de créer un répertoire lib qui
contient les fichier .jar des bibliothèques communes aux différents modules.
26.3.2. La création d'un fichier EAR
Pour créer un fichier EAR, il est possible d'utiliser un outils graphique fourni par le vendeur du serveur d'application ou
de créer le fichier manuellement en suivant les étapes suivantes :
créer l'arboresence des répertoires qui vont contenir les modules
1. 
insérer dans cette arboresence les différents modules à inclure dans le fichier EAR
2. 
créer le répertoire META?INF (en respectant la casse)
3. 
créer le fichier dans ce répertoire
4. 
utiliser l'outils jar pour créer le fichier le fichier EAR en précisant les options cvf, le nom du fichier ear avec son
5. 
extension et les différents éléments qui compose le fichier (modules, répertoire dont le répertoire META?INF).
26.3.3. Les limitations des fichiers EAR
Actullement les fichiers EAR ne servent à regrouper différents modules pour former une seule entité. Rien n'est
actuellement prévu pour prendre en compte la configuration des objets permettant l'accès aux ressources par l'application
tel qu'une base de données (JDBC pour DataSource, pool de connexion ...), un système de message (JMS), etc ...
Pour lever une partie de ces limites, les serveurs d'applications commerciaux proposent souvent des mécanismes
propriétaires supplémentaires pour palier à ces manques en attendant une évolution des spécifications.
Développons en Java
323

27. Les servlets
Les serveurs web sont de base uniquement capable de renvoyer des fichiers présents sur le serveur en réponse à une
requète d'un client. Cependant, pour permettre l'envoie d'une page HTML contenant par exemple une liste d'articles
répondant à différents critères, il faut créer dynamiquement ces pages HTML. Plusieurs solutions existent pour ces
traitements. Les servlets java sont une des ces solutions.
Mais les servlets peuvent aussi servir à d'autres usages.
Sun fourni des informations sur les servlets sur son site :
27.1. Présentation des servlets
Une servlet est un programme qui s'éxécute côté serveur en tant qu'extension du serveur. Elle reçoit une requète du
client, elle effectue des traitements et renvoie le résultat. La liaison entre la servlet et le client peut être directe ou passer
par un intermédiaire comme par exemple un serveur http.
Même si pour le moment la principale utilisation des servlets est la génération de pages html dynamiques utilisant le
protocole http et donc un serveur web, n'importe quel protocole reposant sur le principe de requète/réponse peut faire
usage d'une servlet.
Ecrite en java, une servlet en retire ses avantages : la portabilité, l'accès à toutes les API de java dont JDBC pour l'accès
aux bases de données, ...
Une servlet peut être invoquée plusieurs fois en même temps pour répondre à plusieurs requètes simultanées.
La servlet se positionne dans une architecture Client/Serveur trois tiers dans le tiers du milieu entre le client léger chargé
de l'affichage et la source de données.
Il existe plusieurs versions des spécifications Servlets :
Version
2.0
Novembre 1998, partage d'informations grace au Servletcontext
La classe GenericServlet implémente l'interface ServletConfig
2.1
une méthode log() standard pour envoyer des informations dans le journal du conteneur
objet RequestDispatcher pour le transfert du traitement de la requète vers une autre ressource ou inclure le
résultat d'une autre ressource
Aout 1999, format war pour un déploiement standard des applications web
2.2
mise en buffer de la réponse
Octobre 2000, JSR 053 : nécessite le JDK 1.2 minimum
2.3
ajout d'un mécanisme de filtre
ajout de méthodes pour la gestion d'évenements liés à la création et la destruction du context et de la session
2.4
JSR 154 en cours de développement
Développons en Java
324

27.1.1. Le fonctionnement d'une servlet (cas d'utilisation de http)
Un serveur d'application permet de charger et d'éxécuter les servlets dans une JVM. C'est une extension du serveur web.
Ce serveur d'application contient entre autre un moteur de servlets qui se charge de manager les servlets qu'il contient.
Pour éxécuter une servlet, il suffit de saisir une URL qui désigne la servlet dans un navigateur.
Le serveur reçoit la requète http qui necessite une servlet de la part du navigateur
1. 
Si c'est la premiere sollicitation de la servlet, le serveur l'instancie. Les servlets sont stockées (sous forme de
2. 
fichier .class) dans un répertoire particulier du serveur. Ce répertoire dépend du serveur d'application utilisé. La
servlet reste en mémoire jusqu'à l'arret du serveur. Certains serveurs d'application permettent aussi d'instancier
des servlets dès le lancement du serveur.
La servlet en mémoire, peut être appelée par plusieurs threads lancés par le serveur pour chaque requète. Ce
principe de fonctionnement évite d'instancier un objet de type servlet à chaque requète et permet de maintenir un
ensemble de ressources actives tel qu'une connection à une base de données.
le serveur crée un objet qui représente la requète http et objet qui contiendra la réponse et les envoie à la servlet
3. 
la servlet créé dynamiquement la reponse sous forme de page html transmise via un flux dans l'objet contenant
4. 
la réponse. La création de cette réponse utilise bien sûre la requète du client mais aussi un ensemble de
ressources incluses sur le serveur tels de que des fichiers ou des bases de données.
le serveur récupère l'objet réponse et envoie la page html au client.
5. 
27.1.2. Les outils nécessaires pour développer des servlets
Pour développer des servlets avec le JDK standard édition, il faut utiliser le Java Server Development Kit (JSDK) qui est
une extension du JDK.
Pour réaliser les tests, le JSDK fournit, dans sa version 2.0 un outils nommé servletrunner et depuis sa version 2.1, il
fournit un serveur http allégé.
Pour une utilisation plus poussée ou une mise en exploitation des servlets, il faut utiliser un serveur d'application : il
existe de nombreuses versions commerciales tel que IBM Webpshere ou BEA WebLogic mais aussi des versions libres
tel que Tomcat du projet GNU Jacarta.
Ce serveur d'application doit utiliser ou inclure un serveur http dont le plus utilisé est apache.
Le choix d'un serveur d'application doit tenir compte de la version du JSDK qu'il supporte pour être compatible avec
celle utilisée pour le développement des servlets. Le choix entre un serveur commercial et un libre doit tenir compte
principalement du support technique, des produits annexes fournis et des outils d'installation et de configuration.
Pour simplement développer des servlets, le choix d'un serveur libre se justifie pleinenement de part leur gratuité et leur
« légèreté ».
27.1.3. Le role du serveur d'application
Dans le serveur d'application tourne un moteur de servlet qui prend en charge et gère les servlets : chargement de la
servlet, gestion de son cycle de vie, passage des requètes et des réponses ...
Le chargement et l'instanciation d'une servlet se font selon le paramétrage soit au lancement du serveur soit à la première
invocation de la servlet. Dès l'instanciation, la servlet est initialisée une seul et unique fois avant de pouvoir répondre aux
requètes. Cette initialisation peut permettre de mettre en place l'accès à des ressources tel qu'une base de données.
Développons en Java
325

27.1.4. Les différences entre les servlets et les CGI
Les programmes ou script CGI ( Common Gateway Interface) sont aussi utilisés pour générer des pages HTML
dynamiques. Ils représentent la plus ancienne solution pour réaliser cette tache.
Un CGI peut être écrit dans de nombreux langages.
Il existe plusieurs avantages à utiliser des servlets plutôt que des CGI :
la portabilité offerte par Java bien que certain langage de script tel que PERL tourne sur plusieurs plateformes.
• 
la servlet reste en mémoire une fois instanciée ce qui permet de garder des ressources systèmes et gagner le
• 
temps de l'initialisation. Un CGI est chargé en mémoire à chaque requète, ce qui réduit les performances.
les servlets possède les avantages de toutes les classes écrites en java : accès aux API, aux java beans, le garbage
• 
collector ...
27.2. L'API servlet
Les servlets sont conçues pour agir selon un modele de requète/reponse. Tous les protocoles utilisant ce modèle peuvent
être utilisé tel que http, ftp, etc ...
L'API servlets est une extension du jdk de base, et en tant que tel elle est regroupée dans des packages préfixés par javax
L'API servlet regroupe un ensemble de classes dans deux packages :
javax.servlet : contient les classes pour développer des serlvets génériques indépendantes d'un protocole
• 
: contient les clases pour développer des servlets qui repose sur le protocole http utilisé par les
• 
serveurs web.
Le package javax.servlet définit plusieurs interfaces, méthodes et exceptions :
javax.servlet
Nom
Role
Définition d'un objet qui permet le renvoie d'une requète vers une autre
Les interfaces
RequestDispatcher
ressource du serveur (une autre servlet, une JSP ...)
Servlet
Définition de base d'une servlet
ServletConfig
Définition d'un objet pour configurer la servlet
Définition d'un objet pour obtenir des informations sur le contexte
ServletContext
d'execution de la servlet
ServletRequest
Définition d'un objet contenant la requète du client
ServletResponse
Définition d'un objet qui contient la reponse renvoyée par la servlet
SingleThreadModel
Permet de définir une servlet qui ne répondra qu'à une seule requète à la fois
Les classes
GenericServlet
Classe définissant une servlet indépendante de tout protocole
ServletInputStream
Flux permet la lecteur des donnes de la requète cliente
ServletOutPutStream
Flux permettant l'envoie de la reponse de la servlet
Les exceptions
SevletException
Exception generale en cas de problème de la servlet
UnavailableException Exception levée si la servlet n'est pas disponible
Développons en Java
326

Le package définit plusieurs interfaces et méthodes :
Javax.servlet
Nom
Role
Hérite de ServletRequest : définie un objet contenant une requète selon le
Les interfaces
HttpServletRequest
protocole http
Hérite de ServletResponse : définie un objet contenant la reponse de la servlet
HttpServletResponse selon le protocole http
HttpSession
Définie un objet qui représente une session
Classe représentant un cookie (ensemble de données sauvegardées par le
Les classes
Cookie
brower sur le poste client)
Hérite de GenericServlet : classe définissant une servlet utilisant le protocole
HttpServlet
http
Classe proposant des méthodes statiques utiles pour le développement de
HttpUtils
servlet http
27.2.1. L'interface Servlet
Une servlet est une classe Java qui implémente l'interface javax.servlet.Servlet. Cette interface définie 5 méthodes qui
permettent au serveur de dialoguer avec la servlet : elle encapsule ainsi les méthodes nécessaire à la communication entre
le serveur et la servlet.
Méthode
Rôle
Cette méthode est éxécutée par le serveur lorsque la servlet est
sollicitée : chaque requète du client déclenche une seule execution de
cette méthode.
void service (ServletRequest req,
ServletResponse res)
Cette méthode pouvant être éxécutée par plusieurs threads, il faut
prévoir un processus d'exclusion pour l'utilisation de certaines
ressources.
Initialisation de la servlet. Cette méthode est appelée une seule fois
après l'instanciation de la servlet.
void init(ServletConfig conf)
Aucun traitement ne peut être effectué par la servlet tant que
l'éxecution de cette méthode n'est pas terminée.
ServletConfig getServletConfig()
Renvoie l'objet ServletConfig passé à la méthode init
Cette méthode est appelé lors la destruction de la servlet. Elle permet
void destroy()
de liberer proprement certaines ressources (fichiers, bases de données
...). C'est le serveur qui appelle cette méthode.
String getServletInfo()
Renvoie des informations sur la servlet.
Les méthodes init(), service() et destroy() assure le cycle de vie de la servlet en étant respectivement appellée lors de la
création de la servlet, lors de son appel pour le traitement d'une requète et lors de sa destruction.
La méthode init() est appellée par le serveur juste après l'instanciation de la servlet.
La méthode service() ne peut pas être invoquée tant que la méthode init n'est pas terminée.
Développons en Java
327

La méthode destroy() est appelée juste avant que le serveur ne détruise la servlet : cela permet de liberer des ressources
allouées dans la méthode init() tel qu'un fichier ou une connection à une base de données.
27.2.2. La requète et la réponse
L'interface ServletRequest définit plusieurs méthodes qui permettent d'obtenir les données sur la requète du client:
Méthode
Role
ServletInputStream getInputStream()
Permet d'obtenir un flux pour les données de la requète
BufferedReader getReader()
Idem
L'interface ServletResponse définit plusieurs méthodes qui permettent de fournir la réponse faite par la servlet suite à ces
traitements :
Méthode
Role
SetContentType
Permet de préciser le type MIME de la réponse
ServletOutputStream getOutputStream()
Permet d'obtenir un flux pour envoyer la réponse
PrintWriter getWriter()
Permet d'obtenir un flux pour envoyer la réponse
27.2.3. Un exemple de servlet
Une servlet qui implémente simplement l'interface Servlet doit évidemment redéfinir toute les méthodes définies dans
l'interface.
Il est très utile lorsque que l'on créé une servlet qui implémente directement l'interface Servlet de sauvegarder l'objet
ServletConfig fourni par le serveur en paramètre de la méthode init() car c'est le seul moment ou l'on a accès à cet objet.
Exemple ( code java 1.1 ) :
import .*;
import javax.servlet.*;
public class TestServlet implements Servlet {
  private ServletConfig cfg;
  public void init(ServletConfig config) throws ServletException {
     cfg = config;
  }
  public ServletConfig getServletConfig() {
    return cfg;
  }
  public String getServletInfo() {
    return "Une servlet de test";
  }     
  public void destroy() {
  }
  public void service (ServletRequest req,  ServletResponse res ) 
  throws ServletException, IOException  {
    res.setContentType( "text/html" );
    PrintWriter out = res.getWriter();
    out.println( "<THML>" );
    out.println( "<HEAD>");
Développons en Java
328

    out.println( "<TITLE>Page generee par une servlet</TITLE>" );
    out.println( "</HEAD>" );
    out.println( "<BODY>" );
    out.println( "<H1>Bonjour</H1>" );
    out.println( "</BODY>" );
    out.println( "</HTML>" );
    out.close();
  }
}
27.3. Le protocole HTTP
Le protocol HTTP est un protocol qui fonctionne sur le modèle client/serveur. Un client qui est un application (souvent
un navigateur web) envoie une requete à un serveur (un serveur web). Ce serveur attend en permanence les requètes sur
un port particulier (par défaut le port 80). A la reception de la requete, le serveur lance un thread qui va la traiter pour
générer la réponse. Le serveur envoie la réponse au client.
Une particularité du protocol HTTP est de maintenir la connexion entre le client et le serveur uniquement durant
l'échange de la requète et de la réponse.
Il existe deux versions principales du protocole HTTP : 1.0 et 1.1.
La requête est composé de trois parties :
la commande
• 
la section en?tête
• 
le corps
• 
la première ligne de la requète contient la commande à executer par le serveur. La commande est suivi éventuellement
d'un argument qui précise la commande (par exemple l'url de la ressource demandée). Enfin la ligne doit contenir la
version du protocole HTTP utilisée précédé de HTTP/.
Exemple :
GET / HTTP/1.0
Avec HTTP 1.1, les commandes suivantes sont définies : GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE et
CONNECT. Les trois premières sont les plus utilisées.
Il est possible de fournir sur les lignes suivantes de la partie en?tête des paramètres supplémentaires. Cet partie en?tête
est optionnelles. Les informations fournies peuvent permettre au serveur d'obtenir des informations sur le client. Chaque
information doit être mise sur une ligne unique. Le format est nom_du_champ:valeur. Les champs sont prédéfinis et sont
sensibles à la casse.
Une ligne vide doit précéder le corps de la requête. Le contenu du corps de la requête dépend du type de la commande.
La requète doit obligatoirement être terminé par une ligne vide.
La réponse est elle aussi composée des trois mêmes parties :
une ligne de status
• 
une en?tête dont le contenu est normalisé
• 
un corps dont le contenu dépend totalement de la requête
• 
La première ligne de l'en?tête contient un état qui est composé : de la version du protocole HTTP utilisé, du code de
status et d'une description succinte de ce code.
Le code de status composé de trois chiffres renseigne sur le résultat du traitement qui a généré cette réponse. Ce code
Développons en Java
329

peut être regroupé en plusieurs catégories en fonction de leur valeur :
Plage de valeur du code
Signification
100 à 199
Information
200 à 299
traitement avec succès
300 à 399
la requete a été redirigé
400 à 499
la requete est incomplete ou erronée
500 à 599
Une erreur est intervenue sur le serveur
Plusieurs codes son définis par le protocole HTTP dont les plus importants sont :
200 : traitement correct de la requète
• 
204 : traitement correct de la requète mais la réponse ne contient aucun contenu (ceci permet au browser de
• 
laisser la page courante affichée)
404 : la ressource demande n'est pas trouvée (surement le plus célèbre)
• 
500 : erreur interne du serveur
• 
L'en?tête contient des informations qui précise le contenu de la réponse.
Le corps de la réponse est précédé par une ligne vide.
La suite de cette section sera développée dans une version future de ce document
27.4. Les servlets http
L'usage principale des servlets est la création de pages HTML dynamiques. Sun fourni une classe qui encapsule une
servlet utilisant le protocole http. Cette classe est la classe HttpServlet
Cette classe hérite de GenericServlet, donc elle implémente l'interface Servlet, et redéfinie toutes les méthodes
nécessaires pour fournir un niveau d'abstraction permettant de développer facilement des servlets avec le protocole http.
Ce type de servlet n'est pas utile que pour générer des pages HTML bien que cela soit son principale usage, elle peut
aussi réaliser un ensemble de traitements tel que mettre à jour une base de données. En réponse, elle peut générer une
page html qui indique le succès ou non de la mise à jour.
Elle définit un ensemble de fonctionnalités très utiles : par exemple, elle contient une méthode service() qui appelle
certaines méthodes à redéfinir en fonction du type de requète http (doGet(), doPost(), etc ...).
La requète du client est encapsulée dans un objet qui implémente l'interface HttpServletRequest : cette objet contient les
données de la requète et des informations sur le client.
La réponse de la servlet est encapsulée dans un objet qui implémente l'interface HttpServletResponse.
Typiquement pour définir une servlet, il faut définir une classe qui hérite de la classe HttpServlet et redéfinir la classe
doGet et/ou doPost selon les besoins.
La méthode service héritée de HttpServlet appelle l'une ou l'autre de ces méthodes en fonction du type de la requète http :
Développons en Java
330

une requète GET : c'est une requète qui permet au client de demander une page html
• 
une requète POST : c'est une requète qui permet au client d'envoyer des informations issues par exemple d'un
• 
formulaire
Une servlet peut traiter un ou plusieurs types de requètes grace à plusieurs autres méthodes :
doHead : pour les requètes http de type HEAD
• 
doPut : pour les requètes http de type PUT
• 
doDelete : pour les requètes http de type DELETE
• 
doOptions : pour les requètes http de type OPTIONS
• 
doTrace : pour les requètes http de type TRACE
• 
La classe HttpServlet hérite aussi de plusieurs méthodes définies dans l'interface Servlet : init, destroy et getServletInfo.
27.4.1. La méthode init()
Si cette méthode doit être redéfinie, il est important d'invoquer la méthode héritée avec un (config), config étant
l'objet fourni en paramètre de la méthode. La méthode définie dans la classe HttpServlet sauvegarde l'objet de type
ServletConfig.
De plus, le classe GenericServlet implémente l'interface ServletConfig. Les méthodes redéfinies pour cette interface
utilisent l'objet sauvegardé. Ainsi, la servlet peut utiliser sa propre méthode getInitParameter() ou utiliser la méthode
getInitParameter() de l'objet de type ServletConfig. La première solution permet un usage plus facile dans toute la
servlet.
Sans l'appel à la méthode héritée lors d'une redéfinition, la méthode getInitParameter() de la servlet levera une exception
de type NullPointerException.
27.4.2. L'analyse de la requète
La méthode service() est la méthode qui est appelée lors d'un appel à la servlet.
Par défaut dans la classe HttpServlet, cette méthode contient du code qui réalise une analyse de la requète client contenue
dans l'objet HttpServletRequest. Selon le type de requète GET ou POST, elle appelle la méthode doGet() ou doPost().
C'est bien ce type de requète qui indique quelle méthode utiliser dans la servlet.
Ainsi, la méthode service() n'est pas à redéfinir pour ces requètes et il suffit de redéfinir les méthodes doGet() et/ou
doPost() selon les besoins.
27.4.3. La méthode doGet()
Une requète de type GET est utile avec des liens. Par exemple :
<A HREF="http://localhost:8080/examples/servlet/tomcat1.MyHelloServlet">test de la servlet</A>
Dans une servlet de type HttpServlet, une telle requète est associée à la méthode goGet.
La signature de la méthode doGet() :
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
}
Développons en Java
331

Le traitement typique de la méthode doGet() est d'analyser les paramètres de la requète, alimenter les données de
l'en?tête de la réponse et d'écrire la réponse.
27.4.4. La méthode doPost()
Un requète POST n'est utilisable qu'avec un formulaire HTML.
Exemple de code HTML :
<FORM ACTION="http://localhost:8080/examples/servlet/tomcat1.TestPostServlet" 
METHOD="POST">
<INPUT NAME="NOM">
<INPUT NAME="PRENOM">
<INPUT TYPE="ENVOYER">
</FORM>
Dans l'exemple ci dessus, le formulaire comporte deux zones de saisies correspondant à deux paramètres : NOM et
PRENOM.
Dans une servlet de type HttpServlet, une telle requète est associée à la méthode doPost().
La signature de la méthode doPost() :
protected void doPost(HttpServletRequest request, HttpServletResponse response) 
throws IOException
{
}
La méthode doPost() doit généralement recueillir les paramètres pour les traiter et générer la réponse. Pour obtenir la
valeur associée à chaque paramètre il faut utiliser la méthode getParameter de l'objet HttpServletRequest. Cette méthode
attent en paramètre le nom du paramètre dont on veut la valeur. Ce paramètre est sensible à la casse.
Exemple :
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
   String nom = request.getParameter("NOM");
   String prenom = request.getParameter("PRENOM");
}
27.4.5. La génération de la réponse
La servlet envoie sa réponse au client en utilisant un objet de type HttpServetResponse. HttpServletResponse est une
interface : il n'est pas possible d'instancier un tel objet mais le moteur de servlet instancie un objet qui implémente cette
interface et le passe en paramètre de la méthode service.
Cette interface possède plusieurs méthodes pour mettre à jour l'en?tête http et le page HTML de retour.
Méthode
Rôle
void sendError (int)
Envoie une erreur avec un code retour et un message par défaut
Développons en Java
332

void sendError (int, String)
Envoie une erreur avec un code retour et un message
Héritée de ServletResponse, cette méthode permet de préciser le type
void setContentType(String)
MIME de la réponse
Héritée de ServletResponse, cette méthode permet de préciser la
void setContentLength(int)
longueur de la réponse
Héritée de ServletResponse, elle retourne un flux pour l'envoie de la
ServletOutputStream getOutputStream()
réponse
Héritée de ServletResponse, elle retourne un flux pour l'envoie de la
PrintWriter getWriter()
réponse
Avant de générer la réponse sous forme de page HTML, il faut indiquer dans l'en tête du message http, le type mime du
contenu du message. Ce type sera souvent « text/html » qui correspond à une page HTML mais il peut aussi prendre
d'autre valeur en fonction de ce que retourne la servlet (une image par exemple). La méthode à utiliser est
setContentType.
Il est aussi possible de préciser la longueur de la réponse avec la méthode setContentLength(). Cette précision est
optionnelle mais si elle est utilisée, la longueur doit être exacte pour éviter des problèmes.
Il est préférable de créer une ou plusieurs méthodes recevant en paramètre l'objet HttpServletResponse qui seront dédiées
à la génération du code HTML afin de ne pas alourdir les méthodes doXXX().
Il existe plusieurs façons de générer une page HTML : elles utiliseront toutes soit la méthode getOutputStream() ou
getWriter() pour obtenir un flux dans lequel la réponse sera envoyée.
Utilisation d'un StringBuffer et getOutputStream
• 
Exemple ( code java 1.1 ) :
protected void GenererReponse1(HttpServletResponse reponse) throws IOException
{
   //creation de la reponse
   StringBuffer sb = new StringBuffer();
   sb.append("<HTML>\n");
   sb.append("<HEAD>\n");
   sb.append("<TITLE>Bonjour</TITLE>\n");
   sb.append("</HEAD>\n");
   sb.append("<BODY>\n");
   sb.append("<H1>Bonjour</H1>\n");
   sb.append("</BODY>\n");
   sb.append("</HTML>");
   // envoie des infos de l'en tete
   reponse.setContentType("text/html");
   reponse.setContentLength(sb.length());
   // envoie de la reponse
   reponse.getOutputStream().print(sb.toString());
}
L'avantage de cette méthode est qu'elle permet facilement de déterminer la longueur de la réponse.
Dans l'exemple, l'ajout des retours chariot '\n' à la fin de chaque ligne n'est pas obligatoire mais elle facilite la
compréhension du code HTML surtout si il devient plus complexe.
Utilisation directe de getOutputStream
• 
Développons en Java
333

Exemple :
import .*;
import javax.servlet.*;
import .*;
public class TestServlet4 extends HttpServlet {
   public void doGet(HttpServletRequest req, HttpServletResponse res)
   throws ServletException, IOException {
      res.setContentType("text/html");
      ServletOutputStream out = res.getOutputStream();
      out.println("<HTML>\n");
      out.println("<HEAD>\n");
      out.println("<TITLE>Bonjour</TITLE>\n");
      out.println("</HEAD>\n");
      out.println("<BODY>\n");
      out.println("<H1>Bonjour</H1>\n");
      out.println("</BODY>\n");
      out.println("</HTML>");
   } 
}
Utilisation de la méthode getWriter()
• 
Exemple ( code java 1.1 ) :
protected void GenererReponse2(HttpServletResponse reponse) throws IOException {
   reponse.setContentType("text/html");
   PrintWriter out = reponse.getWriter();
   out.println("<HTML>");
   out.println("<HEAD>");
   out.println("<TITLE>Bonjour</TITLE>");
   out.println("</HEAD>");
   out.println("<BODY>");
   out.println("<H1>Bonjour</H1>");
   out.println("</BODY>");
   out.println("</HTML>");
}
Avec cette méthode, il faut préciser le type MIME avant d'écrire la réponse. L'emploi de la méthode println()
permet d'ajouter un retour chariot en fin de chaque ligne.
Si un problème survient lors de la génération de la réponse, la méthode sendError() permet de renvoyer une
erreur au client : un code retour est positionné dans l'en tête http et le message est indiqué dans une simple page
HTML.
27.4.6. Un exemple de servlet HTTP très simple
Toute servlet doit au moins importer trois packages : pour la gestion des flux et deux packages de l'API servlet ;
javax.servlet.* et .
Il faut déclarer une nouvelle classe qui hérite de HttpServlet.
Il faut redéfinir la méthode doGet() pour y insérer le code qui va envoyer dans un flux le code HTML de la page générée.
Exemple ( code java 1.1 ) :
import .*;
import javax.servlet.*;
import .*;
Développons en Java
334

public class MyHelloServlet extends HttpServlet {
   public void doGet(HttpServletRequest request, HttpServletResponse response) 
   throws IOException, ServletException {
      response.setContentType("text/html");
      PrintWriter out = response.getWriter();
      out.println("<html>");
      out.println("<head>");
      out.println("<title>Bonjour tout le monde</title>");
      out.println("</head>");
      out.println("<body>");
      out.println("<h1>Bonjour tout le monde</h1>");
      out.println("</body>");
      out.println("</html>");
   }
}
La méthode getWriter() de l'objet HttpServletResponse renvoie un flux de type PrintWriter dans lequel on peut écrire la
réponse.
Si aucun traitement particulier n'est associé à une requète de type POST, il est pratique de demander dans la méthode
doPost() d'éxécuter la méthode doGet(). Dans ce cas, la servlet est capable de renvoyer une réponse pour les deux types
de requète.
Exemple ( code java 1.1 ) :
public void doPost(HttpServletRequest request,HttpServletResponse response) 
throws ServletException,IOException {
   this.doGet(request, response);
}
27.5. Les informations sur l'environnement d'execution des servlets
Une servlet est éxécutée dans un contexte particulier mis en place par le moteur de servlet.
La servlet peut obtenir des informations sur ce contexte.
La servlet peut aussi obtenir des informations à partir de la requète du client.
27.5.1. Les paramètres d'initialisation
Dès que de la servlet est instanciée, le moteur de servlet appelle sa méthode init() en lui donnant en paramètre un objet de
type ServletConfig.
ServletConfig est une interface qui possède deux méthodes permettant de connaître les paramètres d'initialisation :
String getInitParameter(String);
• 
Exemple :
String param;
public void init(ServletConfig config) {
Développons en Java
335

   param = config.getInitParameter("param");
}
Enumeration getInitParameterNames() : retourne une enumeration des paramètres d'initialisation
• 
Exemple ( code java 1.1 ) :
public void init(ServletConfig config) throws ServletException {
   cfg = config;
   .println("Liste des parametres d'initialisation");
   for (Enumeration e=config.getInitParameterNames(); e.hasMoreElements();) {
      .println(e.nextElement());
   }
}
La déclaration des paramètres d'initialisation dépend du serveur qui est utilisé.
27.5.2. L'objet ServletContext
La servlet peut obtenir des informations à partir d'un objet ServletContext retourné par la méthode getServletContext()
d'un objet ServletConfig.
Il est important de s'assurer que cet objet ServletConfig, obtenu par la méthode init() est soit explicitement sauvegardé
soit sauvegardé par l'appel à la méthode init() héritée qui effectue cette sauvegarde.
L'interface ServletContext contient plusieurs méthodes dont les principales sont :
méthode
Role
Deprecated
Retourne le type MIME du fichier en
String getMimeType(String)
paramètre
Retourne le nom et le numero de version du
String getServletInfo()
moteur de servlet
Retourne une servlet à partir de son nom grace Ne plus utiliser depuis la version 2.1
Servlet getServlet(String)
au context
du jsdk
Enumeration
Retourne une enumeration qui contient la liste
Ne plus utiliser depuis la version 2.1
getServletNames()
des servlets realatives au contexte
du jsdk
Ecrit les informations fournies en paramètre
Utiliser la nouvelle méthode
void log(Exception, String)
dans le fichier log du serveur
surchargée de log()
void log(String)
Idem
void log (String, Throwable)
Idem
Exemple : écriture dans le fichier log du serveur :
public void init(ServletConfig config) throws ServletException {
Développons en Java
336

   ServletContext sc = config.getServletContext();
   ( "Demarrage servlet TestServlet" );
}
Le format du fichier log est dependant du serveur utilisé :
Exemple : résultat avec tomcat
Context log path="/examples" :Demarrage servlet TestServlet
27.5.3. Les informations contenues dans la requète
De nombreuses informations en provenance du client peuvent être extraites de l'objetServletRequest passé en paramètre
par le serveur (ou de HttpServletRequest qui hérite de ServletRequest).
Les informations les plus utiles sont les paramètres envoyés dans la requète.
L'interface ServletRequest dispose de nombreuses méthodes pour obtenir ces informations :
Méthode
Role
int getContentLength()
Renvoie la taille de la requète, 0 si elle est inconnue
String getContentType()
Renvoie le type MIME de la requète, null si il est inconnu
ServletInputStream getInputStream()
Renvoie un flux qui contient le corps de la requète
Enumeration getParameterNames()
Renvoie une énumeration contenant le nom de tous les paramètres
String getProtocol()
Retourne le nom du protocol et sa version utilisé par la requète
BufferedReader getReader()
Renvoie un flux qui contient le corps de la requète
String getRemoteAddr()
Renvoie l'adresse IP du client
String getRemoteHost()
Renvoie le nom de la machine cliente
String getScheme
Renvoie le protocole utilisé par la requète (exemple : http, ftp ...)
String getServerName()
Renvoie le nom du serveur qui à reçu la requète
int getServerPort()
Renvoie le port du serveur qui a reçu la requète
Exemple ( code java 1.1 ) :
package tomcat1;
import .*;
import javax.servlet.*;
import .*;
import .*;
public class InfoServlet extendsHttpServlet {
   public voiddoGet(HttpServletRequest request, HttpServletResponse response) 
   throws IOException,ServletException {
      GenererReponse(request, response);
Développons en Java
337

   }
   protected voidGenererReponse(HttpServletRequest request, HttpServletResponse reponse) 
   throws IOException {
      reponse.setContentType("text/html");
      PrintWriter out =reponse.getWriter();
      out.println("<html>");
      out.println("<body>");
      out.println("<head>");
      out.println("<title>Informationsa disposition de la servlet</title>");
      out.println("</head>");
      out.println("<body>");
      out.println("<p>Typemime de la requète :"
        +request.getContentType()+"</p>");
      out.println("<p>Protocolede la requète :"
        +request.getProtocol()+"</p>");
      out.println("<p>AdresseIP du client :"
        +request.getRemoteAddr()+"</p>");
      out.println("<p>Nom duclient : "
        +request.getRemoteHost()+"</p>");
      out.println("<p>Nom duserveur qui a reçu la requète :"
        +request.getServerName()+"</p>");
      out.println("<p>Port duserveur qui a reçu la requète :"
        +request.getServerPort()+"</p>");
      out.println("<p>scheme: "+request.getScheme()+"</p>");
      out.println("<p>listedes parametres </p>");
      for (Enumeration e =request.getParameterNames() ; e.hasMoreElements() ; ) {
         Object p = e.nextElement();
         out.println("<p>&nbsp;&nbsp;nom : "+p+" valeur :"
            +request.getParameter(""+p)+"</p>");
      }
      out.println("</body>");
      out.println("</html>");
   }
}
Résultat : avec l'url http://localhost:8080/examples/servlet/tomcat1.InfoServlet?param1=valeur1&param2=valeur2 :
Une page html s'affiche contenant :
Type mime de la requète : null
Protocole de la requète : HTTP/1.0
Adresse IP du client : 127.0.0.1
Nom du client : localhost
Nom du serveur qui a reçu la requète : localhost
Port du serveur qui a reçu la requète : 8080
scheme : http
liste des parametres
   nom : param2 valeur :valeur2
   nom : param1 valeur :valeur1
Développons en Java
338

27.6. La mise en oeuvre des servlets avec Tomcat
Pour pouvoir mettre en oeuvre des servlets, il faut obligatoirement utiliser un conteneur de servlets qui proposent un
environnement d'éxécution des servlets. Il en existe plusieurs commerciaux ou libre. Le plus connu et le plus utilisé est
l'implémentation de référence, nommée Tomcat et développée par le projet Jakarta du groupe Apache.
Il existe plusieurs versions de Tomcat qui mettent en oeuvres des versions différentes des spécifications des servlets et
des JSP :
Version de Tomcat
Version Servlet
Version JSP
3.0, 3.1, 3.2, 3.3
2.2
1.1
4.0, 4.1
2.3
1.2
5.0 (en cours de
2.4
2.0
développement)
27.6.1. Installation de tomcat
27.6.1.1. L'installation de tomcat 3.1 sur Windows 98
pour récuperer le fichier jakarta?
Dézipper le fichier par exemple dans C:\. L'archive est décompressée dans un répertoire nommé jakarta?tomcat
Dans une boite DOS, assigner le répertoire contenant tomcat dans une variable d'environnement TOMCAT_HOME
Exemple : set TOMCAT_HOME=c:\jakarta?tomcat
Lancer Tomcat en executant le fichier dans le répertoire TOMCAT_HOME\bin
Vérifier que Tomcat s'execute en saisissant l'url http://localhost:8080 dans un browser. La page d'accueil de Tomcat
s'affiche.
Développons en Java
339

Le script %TOMCAT_HOME%\bin\ permet de stopper Tomcat.
27.6.1.2. L'installation de tomcat 4.0 sur Windows 98
Il suffit d'éxécuter le programme jakarta?tomcat?
Développons en Java
340

Développons en Java
341

Développons en Java
342

27.6.2. L'utilisation avec Jbuilder 3.0
27.6.2.1. La définition d'une nouvelle bibliothèque
Pour définir une nouvelle bibliothèque, il faut sélectionner l'option default project properties dans le menu project
dans l'onglet required properties, cliquer sur le bouton " add "
cliquer sur le bouton " new "
Développons en Java
343

Saisir un nom, par exemple tomcat. Dans l'onglet classe, cliquer sur le bouton " add "
Sélectionner les fichiers , , et dans le répertoire %TOMCAT_HOME%\lib et
cliquer sur le bouton " ok "
Développons en Java
344

Selectionner l'onglet source
Cliquer sur le bouton " add "
Développons en Java
345

Sélectionner le répertoire %TOMCAT_HOME%\src et cliquer le sur le bouton " ok "
Cliquer sur le bouton " ok " pour fermer la boîte de dialogue et revenir à la précédente.
Cliquer sur le bouton " cancel " 2 fois (sur la boite de dialogue courante et la suivante) pour ne pas modifier les
paramètres par défaut des projets.
Développons en Java
346

27.6.2.2. La creation d'un nouveau projet
Créer un nouveau projet en sélectionnant l'option New project du menu file. Nommer ce projet par exemple tomcat1.
Sélectionner l'option Menu project/project properties
Sur l'onglet Paths, dans l'onglet required librairies, appuyer sur add et sélectionner la librairie tomcat précédemment
définie.
Activer l'onglet Run
Ajouter l'option ?=C:\jakarta?tomcat dans la zone de saisie VM parameters.
Développons en Java
347

Mettre la classe org.apache.tomcat.startup.tomcat comme classe principale du projet en appuyant sur le bouton " Set .. "
et en choisissant la classe dans l'arborescence.
Développons en Java
348

Si les classes n'apparaisent pas, fermer et rouvrir la boite de dialoque " project properties "
Cliquer sur " ok "
Fermer la boite en cliquant sur " ok ".
Remarque : ce paramétrage sera à faire pour tous les nouveaux projets qui contiendront des servlets executées avec
Tomcat.
Executer le projet (menu run/run project ou F9)
Développons en Java
349

Développons en Java
350

Il est possible de vérifier le bon fonctionnement en le visualisant dans le browser.
Double clic sur .
Dans la zone de saisie de l'url, saisie http://localhost:8080
Un clic sur le petit carré rouge au dessus de l'onglet " tomcat " permet d'arreter tomcat. Le triangle vert permet de le
lancer.
27.6.2.3. La creation d'une servlet
Sélectionner l'option " new class " du menu " file " pour ajouter une classe.
Exemple ( code java 1.1 ) : saisir le code de la classe
package tomcat1;
Développons en Java
351

import .*;
import javax.servlet.*;
import .*;
public class MyHelloServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException
    {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<body>");
        out.println("<head>");
        out.println("<title>Bonjour</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Bonjour</h1>");
        out.println("</body>");
        out.println("</html>");
    }

27.6.2.4. Le test de la servlet
Pour tester : le projet doit etre en cours d'execution (onglet tomcat avec un triangle vert) Saisir L'url :
http://localhost:8080/servlet/tomcat1.MyHelloServlet
Pour tester les modifications faites dans les servlets, il faut arreter le serveur tomcat et le relancer (clic sur le carré rouge
puis sur le triangle vert)
Développons en Java
352

27.7. L'utilisation des cookies
Les cookies sont des fichiers contenant des données au format texte, envoyés par le serveur et stocké sur le poste client.
Les données contenues dans le cookie sont envoyées au serveur à chaque requête.
Les cookies peuvent être utilisés explicitement ou implicitement par exemple lors de l'utilisation d'une session.
Les cookies ne sont pas dangereux car ce sont uniquement des fichiers textes qui ne sont pas executés. De plus les
navigateurs posent des limites sur le nombre (en principe 20 cookie pour un même serveur) et la taille des cookies (4ko
maximum). Par contre les cookies peuvent contenir des données plus ou moins sensibles.
27.7.1. La classe Cookie
La classe .Cookie encapsule un cookie.
Un cookie est composé d'un nom, d'une valeur et d'attributs.
Pour créer un cookie, il suffit d'instancier un nouvel objet Cookie. La classe Cookie ne possède qu'un seul conctructeur
qui attend deux paramètres de type String : le nom et la valeur associée.
Le classe Cookie possède plusieurs getter et setter pour obtenir ou définir des attributs qui sont tous optionnels.
Attribut
Rôle
Comment
Commentaire associé au cookie
Le nom de domaine (partiel ou complet) associé au cookie. Seul les serveurs contenant se nom
Domain
de domaine recevront le cookie.
Durée de vie en seconde du cookie. Une fois ce délai expiré, le cookie est détruit sur le poste
MaxAge
client. Une valeur actuelle, limite la durée de vie du cookie à la durée de vie du browser
Name
Nom du cookie
Chemin du cookie. Ce chemin permet de renvoyer le cookie uniquement au serveur dont l'url
contient également le chemin. Par défaut, cet attribut contient le chemin de l'url de la servlet.
Path
Par exemple, pour que le cookie soit renvoyé à toutes les requêtes du serveur, il suffit
d'affecter la valeur "/" à cette attribut.
Secure
Booléen qui précise si le cookie ne doit être envoyé que via une connexion SSL.
Value
Valeur associée au cookie.
Version
Version du protocole utilisé pour gérer le cookie
27.7.2. L'enregistrement et la lecture d'un cookie
Pour envoyer un cookie au browser, il suffit d'utiliser la méthode addCookie() de la classe HttpServletResponse.
Exemple :
Cookie monCookie = new Cookie("nom","valeur");
response.addCookie(monCookie);
Pour lire un cookie envoyé par le browser, il faut utiliser la méthode getCookies() de la classe HttpServletRequest. Cette
méthode renvoie un tableau d'objet Cookie. Les cookies sont renvoyés dans l'en?tête de la requête http. Pour rechercher
un cookie particulier, il faut parcourir le tableau et rechercher le cookie à partir de son nom grace à la méthode
getName() de l'objet Cookie.
Développons en Java
353

Exemple :
Cookie[] cookies = request.getCookies();
String valeur = "";
for(int i=0;i<cookies.length;i++) {
  if(cookies[i].getName().equals("nom")) {
    valeur=cookies[i].getValue();
  }
}
27.8. Le partage d'informations entre plusieurs échanges HTTP
Cette section sera développée dans une version future de ce document
27.9. Packager une application web
Le format war (Web Application Archive) permet de regrouper en un seul fichier tous les éléments d'une application web
que ce soit pour le côté serveur (servlets, JSP, classes java, ...) ou pour le côté client (ressources HTML, images, son ... ).
C'est une extension du format jar spécialement dédiée aux applications web qui a été introduite dans les spécifications de
la version 2.2 des servlets. C'est un format indépendant de toute plate?forme et exploitable par tous les conteneurs web
qui respecte à minima cette version des spécifications.
Le but principal est de simplifier le déploiement d'une application web et d'uniformiser cet action quel que soit le
conteneur web utilisé.
27.9.1. Structure d'un fichier .war
Comme les fichiers jar, les fichiers war possèdent une structure particulière qui est incluse dans un fichier compressé de
type "zip" possédant comme extension ".war".
Développons en Java
354

Le nom du fichier .war est important car ce nom sera automatiquement associé dans l'url pour l'accès à l'application en
concatenant le nom du domaine, un slash et le nom du fichier war. Par exemple, pour un serveur web sur le poste local
avec un fichier déployé sur le serveur d'application, l'url pour accéder à l'application web sera
http://localhost/test/
Le répertoire WEB?INF et le fichier qu'il contient doivent obligatoirement être présent dans l'archive. Le fichier
est le descripteur de déploiement de l'application web.
Le serveur web peut avoir accès via le serveur d'application à toutes les ressources contenues dans le fichier .war hormis
celles contenues dans le répertoire WEB?INF. Ces dernières ne sont accessibles qu'au serveur d'application.
Le répertoire WEB?INF/classes est automatiquement ajouté par le conteneur au CLASSPATH lors du déploiement de
l'application web.
L'archive web peut être créée avec l'outils jar fourni avec le JDK ou avec un outils commercial. Avec l'outils jar, il suffit
de créer l'arborescence de l'application, de ce placer dans le répertoire racine de cette arborescence et d'éxécuter la
commande :
jar cvf .
Toute l'arborescence avec les fichiers qu'elle contient sera incluse dans le fichier .
27.9.2. Le fichier
Le fichier /WEB? est un fichier au format XML qui est le descripteur de déploiement permettant de
configurer : l'application, les servlets, les sessions, les bibliothèques de tags personnalisées, les paramètres de contexte,
les types Mimes, les pages par défaut, les ressouces externes, la sécurité de l'application et des ressources J2EE.
Le fichier commence par un prologue et une indication sur la version de la DTD à utiliser. Celle?ci dépend des
spécifications de l'API servlet utilisées.
Exemple : servlet 2.2
Développons en Java
355

<?xml version="1.0" encoding="ISO?8859?1"?>
  <!DOCTYPE web?app PUBLIC "?//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
  "?">
Exemple : servlet 2.3
 <?xml version="1.0" encoding="ISO?8859?1"?>
  <!DOCTYPE web?app PUBLIC "?//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "?">
L'élément racine est le tag <web?app>. Cet élément peut avoir plusieurs tags fils dont l'ordre d'utilisation doit respecter
celui défini dans la DTD utilisée.
Le tag <icon> permet de préciser une petite et une grande image qui pourront être utilisées par des outils graphiques.
Le tag <display?name> permet de donner un nom pour l'affichage dans les outils.
Le tag <description> permet de fournir un texte de description de l'application web.
Le tag <context?param> permet de fournir un paramètre d'initialisation de l'application. Ce tag peut avoir trois tags fils :
<param?name>, <param?value> et <description>. Il doit y en avoir autant que de paramètres d'initialisation. Les valeurs
fournies peuvent être retrouvées dans le code de la servlet grace à la méthode getInitParameter() de l'objet
ServletContext.
La tag <servlet> permet de définir une servlet. Le tag fils <icon> permet de préciser une petite et une grande image pour
les outils graphique. Le tag <servlet?name> permet de donner un nom à la servlet qui sera utilisé pour le mapping avec
l'URL par défaut de la servlet. Le tag <display?name> permet de donner un nom d'affichage. Le tag <description>
permet de fournir une description de la servlet. Le tag <servlet?class> permet de préciser le nom complètement qualifié
de la classe java dont la servlet sera une instance. Le tag <init?param> permet de préciser un paramètre d'initialisation
pour la servlet. Ce tag possède les tag fils <param?name>, <param?value>, <description>. Les valeurs fournies peuvent
être retrouvées dans le code de la servlet grace à la méthode getInitParameter() de la classe ServletConfig. Le tag
<load?on?startup> permet de préciser si la servlet doit être instanciée lors de l'initialisation du conteneur. Il est possible
de préciser dans le corps de ce tag un numéro de séquence qui pemettra d'ordonner la création des servlets.
Exemple : servlet 2.2
 <servlet>
    <servlet?name>MaServlet</servlet?name>
    <servlet?class>.servlet.MaServlet</servlet?class>
    <load?on?startup>1</load?on?startup>
    <init?param>
                  <param?name>param1</param?name>
                        <param?value>valeur1</param?value>
    </init?param>
  </servlet>
Le tag <servlet?mapping> permet d'associer la servlet à une URL. Ce tag possède les tag fils <servlet?name> et
<servlet?mapping>.
Exemple : servlet 2.2
 <servlet?mapping>
    <servlet?name>MaServlet</servlet?name>
          <url?pattern>/test</url?pattern>
  </servlet?mapping>
Développons en Java
356

Le tag <session?config> permet de configurer les sessions. Le tag fils <session?timeout> permet de préciser la durée
maximum d'inactivité de la session avant sa destruction. La valeur fournie dans le corps de ce tag est exprimé en minutes.
Exemple : servlet 2.2
 <session?config>
    <session?timeout>15</session?timeout>
        </session?config>
Le tag <mime?mapping> permet d'associer des extensions à un type mime particulier.
Le tag <welcome?file?list> permet de définir les pages par défaut. Chacun des fichiers est défini grace au tag fils
<welcome?file>
Exemple : servlet 2.2
 <welcome?file?list>
    <welcome?file></welcome?file> 
    <welcome?file></welcome?file> 
  <welcome?file?list>
Le tag <error?page> permet d'associer une page web à un code d'erreur HTTP particulier ou a une exception java
particulière. Le code erreur est précisé avec le tag fils <error?code>. L'exception java est précisée avec le tag fils
<exception?type>. La page web est précisé avec le tag fils <location>.
Le tag <tag?lib> permet de définir une biliothèque de tags personnalisée. Le tag fils <taglib?uri> permet préciser l'URI
de la bibliothèque. Le tag fils <taglib?location> permet de préciser le chemin de la bibliothèque.
Exemple : déclaration de la biliothèque core de JSTL
 <taglib>
          <taglib?uri>;/taglib?uri>
          <taglib?location>/WEB?</taglib?location>
  </taglib>
27.9.3. Le déploiement d'une application web
Le déploiement d'une archive web dans un serveur d'application est très facile car il suffit simplement de copier le fichier
.war dans le répertoire par défaut dédié aux application web. Par exemple dans Tomcat, c'est le répertoire webapps.
Attention cependant, si chaque conteneur qui repecte les spécifications 1.1 des JSP sait utiliser un fichier .war, leur
exploitation par chaque conteneur est légèrement différente.
Par exmple avec Tomcat, il est possible de travailler directement dans le répertoire webapps avec le contenu de l'archive
web décompressé. Cette fonctionnalité est particulièrement intéressante lors de la phase de développement de
l'application car il n'est alors pas obligatoire de générer l'archive web à chaque modification pour réaliser des tests.
Attention, si l'application est redéployée sous la forme d'une archive .war, il faut obligatoirement supprimer le répertoire
qui contient l'ancienne version de l'application.
Développons en Java
357

28. Les JSP (Java Servers Pages)
Les JSP (Java Server Pages) sont une technologie Java qui permettent la génération de pages web dynamiques.
La technologie JSP permet de séparer la présentation sous forme de code HTML et les traitements sous formes de classes
java définissant un bean ou une servlet. Ceci est d'autant plus facile que les JSP définissent une syntaxe particulière
permettant d'appeler un bean et d'insérer le résultat de son traitement dans la page HTML dynamiquement.
Les informations fournies dans ce chapitre concerne les spécifications 1.0 et ultérieures des JSP.
28.1. Présentation des JSP
Les JSP permettent d'introduire du code java dans des tags prédéfinis à l'intérieur d'une page HTML. La technologie JSP
mélange la puissance de java côté serveur et la facilité de mise en page d'HTML côté client.
S u n   f o u r n i   d e   n o m b r e u s e s   i n f o r m a t i o n s   s u r   l a   t e c h n o l o g i e   J S P   à   l ' a d r e s s e   s u i v a n t e   :

Une JSP est habituellement constituée :
de données et de tags HTML
• 
de tags JSP
• 
de scriptlets (code java intégré à la JSP)
• 
Les fichiers JSP possèdent par convention l'extension .jsp.
Concrètement, les JSP sont basées sur les servlets. Au premier appel de la page JSP, le moteur de JSP crée et compile
automatiquement une servlet qui permet la génération de la page web. Le code HTML est repris intégralement dans la
servlet. Le code java est inséré dans la servlet.
La servlet ainsi générée est sauvegardée puis elle est exécutée. Les appels suivants de la JSP sont beaucoup plus rapides
car la servlet, conservée par le serveur, est directement exécutée.
Il a plusieurs manières de combiner les technologies JSP, les beans/EJB et les servlets.
Comme le code de la servlet est généré dynamiquement, les JSP sont relativement difficiles à debugguer.
Cette approche possède plusieurs avantages :
l'utilisation de java par les JSP permet une indépendance de la plate?forme d'exécution mais aussi du serveur
• 
web utilisé.
la séparation des traitements et de la présentation : la page web peut être écrite par un designer et les tags java
• 
peuvent être ajouter ensuite par le développeur. Les traitements peuvent être réalisés par des composants
réutilisables (des java beans).
les JSP sont basées sur les servlets : tous ce qui est fait par une servlet pour la génération de pages dynamiques
• 
peut être fait avec une JSP.
Développons en Java
358

Il existe plusieurs versions des spécifications JSP :
Version
0.91
Première release
1.0
Juin 1999 : première version finale
1.1
Décembre 1999 :
1.2
Octobre 2000, JSR 053
2.0
JSR 152 en cours de développement
28.1.1. Le choix entre JSP et Servlets
Les servlets et les JSP ont de nombreux points communs puisque qu'une JSP est finalement convertie en une servlet. Le
choix d'utiliser l'une ou l'autre de ces technologies ou les deux doit être fait pour tirer le meilleur parti de leurs avantages.
Dans une servlet, les traitements et la présentation sont regroupés. L'aspect présentation est dans ce cas pénible à
développer et à maintenir à cause de l'utilisation répétitive de méthodes pour insérer le code HTML dans le flux de sortie.
De plus, une simple petite modification dans le code HTML nécessite la recompilation de la servlet. Avec un JSP, la
séparation des traitements et de la présentation rend ceci très facile et automatique.
Il est préférable d'utiliser les JSP pour générer des pages web dynamiques.
L'usage des servlets est obligatoire si celles ci doivent communiquer directement avec une applets ou une application et
non plus avec un serveur web.
28.1.2. JSP et les technologies concurrentes
Il existe plusieurs technologies dont le but est similaires aux JSP notamment ASP et PHP.
28.2. Les outils nécessaires
Dans un premier temps, Sun a fourni un kit de développement pour les JSP : le Java Server Web Development Kit
(JSWDK). Actuellement, Sun a chargé le projet Apache de développer l'implémentation officielle d'un moteur de JSP.
Ce projet se nomme Tomcat.
En fonction des versions des API utilisées, il faut choisir un produit différent. Le tableau ci dessous résume le produit a
utiliser en fonction de la version des API mise en oeuvre.
Produit
Version
Version de l'API servlet implémentée
Version de l'API JSP implémentée
JSWDK
1.0.1
2.1
1.0
Tomcat
3.2
2.2
1.1
Tomcat
4.0
2.3
1.2
Tomcat
5.0
2.4
2.0
Développons en Java
359

Ces produits sont librement téléchargeables sur le site de Sun à l'adresse suivante :

Pour télécharger le JSWDK, il faut cliquer sur le lien « archive ».
28.2.1. JavaServer Web Development Kit (JSWDK) sous Windows
Le JSWDK est sous la forme d'un fichier zip nommé jswdk_1_0_1?.
Pour l'installer, il suffit de décompacter l'archive.
Pour lancer le serveur :
C:\jswdk?1.0.1>
Using classpath:.\classes;.\;.\lib\;.\lib\;.
\lib\;.\lib\;.\examples\WEB?INF\jsp\beans;.\webpages\WEB?INF
\servlets;.\webpages\WEB?INF\jsp\beans;.\lib\;.\lib\;\lib\
r;C:\jdk1.3\lib\;
C:\jswdk?1.0.1>
Le serveur s'exécute dans une console en tache de fond. Cette console permet de voir les messages émis par le serveur.
Exemple : au démarrage
JSWDK WebServer Version 1.0.1
Loaded configuration from: file:C:\jswdk?1.0.1\
endpoint created: localhost/127.0.0.1:8080
Si la JSP contient une erreur, le serveur envoie une page d'erreur :
Une exception est levée et est affichée dans la fenêtre ou le serveur s'exécute :
Exemple :
?? Commentaires de la page JSP ??
^
1 error
at .compile(:347)
at .runtime.JspLoader.loadJSP(:135)
at .runtime.JspServlet$JspServletWrapper.loadIfNecessary(JspS
:77)
at .runtime.JspServlet$JspServletWrapper.service(JspServlet.j
ava:87)
at .runtime.JspServlet.serviceJspFile(:218)
at .runtime.JspServlet.service(:294)
Développons en Java
360

at .HttpServlet.service(:840)
at .ServletWrapper.handleRequest(:155

at .Context.handleRequest(:414)
at (:139)
HANDLER THREAD PROBLEM: .IOException: Socket Closed
.IOException: Socket Closed
at .PlainSocketImpl.getInputStream(Unknown Source)
at .Socket$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at .Socket.getInputStream(Unknown Source)
at (:161)
Le répertoire work contient le code et le byte code des servlets générée à partir des JSP.
Pour arrêter le serveur, il suffit d'exécuter le script .
A l'arrêt du serveur, le répertoire work qui contient les servlets générées à partir des JSP est supprimé.
28.2.2. Tomcat
Cette section sera développée dans une version future de ce document
28.3. Le code HTML
Une grande partie du contenu d'une JSP est constitué de code HTML. D'ailleurs, le plus simple pour écrire une JSP est
d'écrire le fichier HTML avec un outils dédié et d'ajouter ensuite les tags JSP pour ce qui concerne les parties
dynamiques.
La seule restriction concernant le code HTML concerne l'utilisation dans la page générée du texte « <% » et « %> ».
Dans ce cas, le plus simple est d'utiliser les caractères spéciaux HTML &lt ; et &gt ;. Sinon l'analyseur syntaxique du
moteur de JSP considère que c'est un tag JSP et renvoie une erreur.
Exemple :
<HTML>
<HEAD>
<TITLE>Test</TITLE>
</HEAD>
<BODY>
<p>Plusieurs tags JSP commencent par &lt;% et se finissent par %&gt;</p>
</BODY>
</HTML>
28.4. Les Tags JSP
Il existe trois types de tags :
tags de directives : ils permettent de contrôler la structure de la servlet générée
• 
tags de scripting: il permettent d'insérer du code java dans la servlet
• 
Développons en Java
361

tags d'actions: ils facilitent l'utilisation de composants
• 
Attention : Les tags sont sensibles à la
casse.
28.4.1. Les tags de directives <%@ ... %>
Les directives permettent de préciser des informations globales sur la page JSP. Les spécifications des JSP définissent
trois directives :
page : permet de définir des options de configuration
• 
include : permet d'inclure des fichiers statiques dans la JSP avant la génération de la servlet
• 
taglib : permet de définir des tags personnalisés
• 
Leur syntaxe est la suivante :
<%@ directive attribut="valeur" ... %>
28.4.1.1. La directive page
Cette directive doit être utilisée dans toutes les pages JSP : elle permet de définir des options qui s'applique à toute la
JSP.
Elle peut être placée n'importe ou dans le source mais il est préférable de la mettre en début de fichier, avant même le tag
<HTML>. Elle peut être utilisée plusieurs fois dans une même page mais elle ne doit définir la valeur d'une option qu'une
seule fois, sauf pour l'option import.
Les options définies par cette directive sont de la forme option=valeur.
Option
Valeur
Valeur par défaut
Autre valeur possible
autoFlush
Une chaine
«true»
«false»
buffer
Une chaine
«8kb»
«none» ou «nnnkb» (nnn indiquant la valeur)
contentType
Une chaîne contenant le type mime
errorPage
Une chaîne contenant une URL
extends
Une classe
import
Une classe ou un package.*
info
Une chaîne
isErrorPage
Une chaîne
«false»
«true»
isThreadSafe
Une chaîne
«true»
«false»
langage
Une chaîne
«java»
session
Une chaîne
«true»
«false»
Exemple :
<%@ page import=".*" %>
<%@ page import=".Vector" %>
<%@ page info="Ma premiere JSP"%>
Les options sont :
Développons en Java
362

autoFlush="
• 
true|false"
Cette option indique si le flux en sortie de la servlet doit être vidé quand le tampon est plein. Si la valeur est
false, une exception est levée dès que le tampon est plein. On ne peut pas mettre false si la valeur de buffer est
none.
buffer="none|
• 
8kb|sizekb"
Cette option permet de préciser la taille du buffer des données générées contenues par l'objet out de type
JspWriter.
contentType="
• 
mimeType [ ; charset=characterSet ]" | "text/html;charset=ISO?8859?1"
Cette option permet de préciser le type MIME des données générées.
Cette option est équivalente à <% response.setContentType("mimeType"); %>
errorPage=
• 
"relativeURL"
Cette option permet de préciser la JSP appelée au cas où une exception est levée
Si l'URL commence pas un '/', alors l'URL est relative au répertoire principale du serveur web sinon elle est
relative au répertoire qui contient la JSP
extends
• 
="package.class"
Cette option permet de préciser la classe qui sera la super classe de l'objet java créé à partir de la JSP.
import= "{
• 
 package.class | package.* }, ..."
Cette option permet d'importer des classes contenues dans des packages utilisées dans le code de la JSP. Cette
option s'utilise comme l'instruction import dans un source java.
Chaque classe ou package est séparée par une virgule.
Cette option peut être présente dans plusieurs directives page.
info="text"
• 
Cette option permet de préciser un petit descriptif de la JSP. Le texte fourni sera renvoyé par la méthode
getServletInfo() de la servlet générée.
isErrorPage="true|
• 
false"
Cette option permet de préciser si la JSP génère un page d'erreur. La valeur true permet d'utiliser l'objet
Exception dans la JSP
isThreadSafe="
• 
true|false"
Cette option indique si la servlet générée sera multithread : dans ce cas, une même instance de la servlet peut
gérer plusieurs requêtes simultanément. En contre partie, elle doit gérer correctement les accès concurrents aux
ressources. La valeur false impose à la servlet générée d'implémenter l'interface SingleThreadModel.
language="java"
• 
Cette option définie le langage utilisé pour écrire le code dans la JSP. La seule valeur autorisée actuellement est
«java».
session="
• 
true|false"
Cette option permet de préciser si la JSP est incluse dans une session ou non. La valeur par défaut (true) permet
l'utilisation d'un objet session de type HttpSession qui permet de gérer une session.
Développons en Java
363

28.4.1.2. La directive include
Cette directive permet d'inclure un fichier dans le source JSP. Le fichier inclus peut être un fragment de code JSP, HTML
ou java. Le fichier est inclus dans la JSP avant que celle ci ne soit interprétée par le moteur de JSP.
Ce tag est particulièrement utile pour insérer un élément commun à plusieurs pages tel qu'un en?tête ou un bas de page.
Si le fichier inclus est un fichier HTML, celui ci ne doit pas contenir de tag <HTML>, </HTML>, <BODY> ou
</BODY> qui ferait double emploi avec ceux présents dans le fichier JSP. Ceci impose d'écrire des fichiers HTML
particuliers uniquement pour être inclus dans les JSP : ils ne pourront pas être utilisés seuls.
La syntaxe est la suivante :
<%@ include file="chemin relatif du fichier" %>
Si le chemin commence par un '/', alors le chemin est relatif au contexte de l'application, sinon il est relatif au fichier JSP.
Exemple :
:
<p><table border="1" cellpadding="4" cellspacing="0" width="30%" align=center >
<tr bgcolor="#A6A5C2">
<td align="center">BONJOUR</Td>
</Tr>
</table></p>
:
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
<p align="center">Test d'inclusion d'un fichier dans la JSP</p>
<%@ include file=""%>
<p align="center">fin</p>
</BODY>
</HTML>
P o u r   t e s t e r   c e t t e   J S P   a v e c   l e   J S W D K ,   i l   s u f f i t   d e   p l a c e r   c e s   d e u x   f i c h i e r s   d a n s   l e   r é p e r t o i r e
jswdk?1.0.1\examples\jsp\test.
Pour visualiser la JSP, il faut saisir l'url dans un navigateur.
Attention : un changement dans le fichier inclus ne provoque pas une regénération et une compilation de la
servlet correspondant à la JSP. Pour insérer un fichier dynamiquement à l'exécution de la servlet il faut
utiliser le tag <jsp:include>.
28.4.1.3. La directive taglib
Cette directive permet de déclarer l'utilisation d'une bibliothèque de tags personnalisés. L'utilisation de cette directive est
détaillée dans la section consacrée au bibliothèques de tags personnalisés.
Développons en Java
364

28.4.2. Les tags de scripting
Ces tags permettent d'insérer du code java qui sera inclus dans la servlet générée à partir de la JSP. Il existe trois tags
pour insérer du code java :
le tag de déclaration : le code java est inclus dans le corps de la servlet générée. Ce code peut être la déclaration
• 
de variables d'instances ou de classes ou la déclaration de méthodes.
le tag d'expression : évalue une expression et insère le résultat sous forme de chaîne de caractères dans la page
• 
web générée.
le tag de scriptlets : par défaut, le code java est inclus dans la méthode service() de la servlet.
• 
Il est possible d'utiliser dans ces tags plusieurs objets définis par les JSP.
28.4.2.1. Le tag de déclarations <%! ... %>
Ce tag permet de déclarer des variables ou des méthodes qui pourront être utilisées dans la JSP. Il ne génère aucun
caractère dans le fichier HTML de sortie.
La syntaxe est la suivante :
<%! declarations %>
Exemple :
<%! int i = 0; %> 
<%! dateDuJour = new (); %> 
Les variables ainsi déclarées peuvent être utilisées dans les tags d'expressions et de scriptlets.
Il est possible de déclarer plusieurs variables dans le même tag en les séparant avec des ' ;'.
Ce tag permet aussi d'insérer des méthodes dans le corps de la servlet.
Exemple :
<HTML>
<HEAD>
<TITLE>Test</TITLE>
</HEAD>
<BODY>
<%! 
int minimum(int val1, int val2) { 
   if (val1 < val2) return val1;
   else return val2;

%> 
<% int petit = minimum(5,3);%>
<p>Le plus petit de 5 et 3 est <%= petit %></p>
</BODY> 
</HTML>
28.4.2.2. Le tag d'expressions <%= ... %>
Le moteur de JSP remplace ce tag par le résultat de l'évaluation de l'expression présente dans le tag.
Ce résultat est toujours converti en une chaîne. Ce tag est un raccourci pour éviter de faire appel à la méthode println()
lors de l'insertion de données dynamiques dans le fichier HTML.
Développons en Java
365

La syntaxe est la suivante :
<%= expression %>
Le signe '=' doit être collé au signe '%'.
Attention : il ne faut pas mettre de ' ;' à la fin de l'expression.
Exemple : Insertion de la date dans la page HTML
<%@ page import=".*" %>
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
<p align="center">Date du jour : 
<%= new Date() %>
</p>
</BODY>
</HTML>
Résultat :
Date du jour : Thu Feb 15 11:15:24 CET 2001
L'expression est évaluée et convertie en chaîne avec un appel à la méthode toString(). Cette chaîne est insérée dans la
page HTML en remplacement du tag. Il est ainsi possible que le résultat soit une partie ou la totalité d'un tag HTML ou
même JSP.
Exemple :
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
<%="<H1>" %>
Bonjour
<%="</H1>" %>
</BODY>
</HTML>
Résultat : code HTML généré
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
<H1>
Bonjour
</H1>
</BODY>
</HTML>
Développons en Java
366

28.4.2.3. Les variables implicites
Les spécifications des JSP définissent plusieurs objets utilisables dans le code dont les plus utiles sont :
Object
Classe
Role
out
.JspWriter
Flux en sortie de la page HTML générée
request
.HttpServletRequest
Contient les informations de la requête
response
.HttpServletRequest
Contient les informations de la réponse
session
.HttpSession
Gère la session
28.4.2.4. Le tag des scriptlets <% ... %>
Ce tag contient du code java nommé un scriptlet.
La syntaxe est la suivante : <% code java %>
Exemple :
<%@ page import=""%>
<html>
<body>
<%! Date dateDuJour; %>
<% dateDuJour = new Date();%>
Date du jour : <%= dateDuJour %><BR>
</body>
</html>
Par défaut, le code inclus dans le tag est inséré dans la méthode service de la servlet générée à partir de la JSP.
Ce tag ne peut pas contenir autre chose que du code java : il ne peut pas par exemple contenir de tags HTML ou JSP.
Pour faire cela, il faut fermer le tag du scriptlet, mettre le tag HTML ou JSP puis de nouveau commencer un tag de
scriptlet pour continuer le code.
Exemple :
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
<% for (int i=0; i<10; i++) { %> 
<%= i %> <br>
<% }%>
</BODY>
</HTML>
Résultat : la page HTML générée
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
0 <br>
Développons en Java
367

1 <br>
2 <br>
3 <br>
4 <br>
5 <br>
6 <br>
7 <br>
8 <br>
9 <br>
</BODY>
</HTML>
28.4.3. Les tags de commentaires
Il existe deux types de commentaires avec les JSP :
les commentaires visibles dans le code HTML
• 
les commentaires invisibles dans le code HTML
• 
28.4.3.1. Les commentaires HTML <!?? ... ??>
Ces commentaires sont ceux définis par format HTML. Ils sont intégralement reconduit dans le fichier HTML généré. Il
est possible d'insérer, dans ce tag, un tag JSP de type expression
La syntaxe est la suivante :
<!?? commentaires [ <%= expression %> ] ??>
Exemple :
<%@ page import=".*" %>
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
<!?? Cette page a ete generee le <%= new Date() %> ??>
<p>Bonjour</p>
</BODY>
</HTML>
Résultat :
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
<!?? Cette page a ete generee le Thu Feb 15 11:44:25 CET 2001 ??>
<p>Bonjour</p>
</BODY>
</HTML>
Le contenu d'une expression incluse dans des commentaires est dynamique : sa valeur peut changer à chaque génération
de la page en fonction de son contenu.
Développons en Java
368

28.4.3.2. Les commentaires cachés <%?? ... ??%>
Les commentaires cachés sont utilisés pour documenter la page JSP. Leur contenu est ignoré par le moteur de JSP et ne
sont donc pas reconduit dans les données HTML générées.
La syntaxe est la suivante :
<%?? commentaires ??%>
Exemple :
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
<%?? Commentaires de la page JSP ??%>
<p>Bonjour</p>
</BODY>
</HTML>
Résultat :
<HTML>
<HEAD>
<TITLE>Essai de page JSP</TITLE>
</HEAD>
<BODY>
<p>Bonjour</p>
</BODY>
</HTML>
Ce tag peut être utile pour éviter l'exécution de code lors de la phase de débuggage.
28.4.4. Les tags d'actions
Les tags d'actions permettent de réaliser des traitements couramment utilisés.
28.4.4.1. Le tag <jsp:useBean>
Le tag <jsp:useBean> permet de localiser une instance ou d'instancier un bean pour l'utiliser dans la JSP.
L'utilisation d'un bean dans une JSP est très pratique car il peut encapsuler des traitements complexes et être réutilisable
par d'autre JSP ou composants. Le bean peut notamment assurer l'accès à une base de données. L'utilisation des beans
permet de simplifier les traitements inclus dans la JSP.
Lors de l'instanciation d'un bean, on précise la porté du bean. Si le bean demandé est déjà instancié pour la porté précisée
alors il n'y pas de nouvelle instance du bean qui est créée mais sa référence est simplement renvoyée : le tag
<jsp:useBean> n'instancie pas obligatoirement un objet.
Ce tag ne permet pas de traiter des EJB.
La syntaxe est la suivante :
<jsp:useBean
id="beanInstanceName"
Développons en Java
369

scope="page|request|session|application"
{ class="package.class" |
type="package.class" |
class="package.class" type="package.class" |
beanName="{package.class | <%= expression %>}" type="package.class"
}
{ /> |
> ...
</jsp:useBean>
}
L'attribut id permet de donner un nom à la variable qui va contenir la référence sur le bean.
L'attribut scope permet de définir la portée durant laquelle le bean est défini et utilisable. La valeurs de cette attribut
détermine la manière dont le tag localise ou instancie le bean. Les valeurs possibles sont :
Valeur
Rôle
c'est la valeur par défaut. Le bean est utilisable dans toute la page JSP ainsi que dans les fichiers
page
statiques inclus.
le bean est accessible durant la durée de vie de la requête. La méthode getAttribute() de l'objet
request
request permet d'obtenir une référence sur le bean.
le bean est utilisable par toutes les JSP qui appartiennent à la même session que la JSP qui a
session
instanciée le bean. Le bean est utilisable tout au long de la session par toutes les pages qui y
participent. La JSP qui créé le bean doit avoir l'attribut session = « true » dans sa directive page.
le bean est utilisable par toutes les JSP qui appartiennent à la même application que la JSP qui a
application
instanciée le bean. Le bean n'est instancié que lors du rechargement de l'application.
L'attribut class permet d'indiquer la classe du bean.
L'attribut type permet de préciser le type de la variable qui va contenir la référence du bean. La valeur indiquée doit
obligatoirement être une super classe du bean ou une interface implémentée par le bean (directement ou par héritage)
L'attribut beanName permet d'instancier le bean grâce à la méthode instanciate() de la classe Beans.
Exemple :
<jsp:useBean id="monBean" scope="session" class="test.MonBean" />
Dans cet exemple, une instance de MonBean est instancié un seul est unique fois lors de la session. Dans la même
session, l'appel du tag <jsp:useBean> avec le même bean et la même portée ne feront que renvoyer l'instance créée. Le
bean est accessible durant toute la session.
Le tag <jsp:useBean> recherche si une instance du bean existe avec le nom et la portée précisée. Si elle n'existe pas, alors
une instance est créée. Si il y a instanciation du bean, alors les tags <jsp:setProperty> inclus dans le tag sont utilisés pour
initialiser les propriétés du bean sinon ils sont ignorés. Les tags inclus entre les tags <jsp:useBean> et </jsp:useBean> ne
sont exécutés que si le bean est instancié.
Exemple :
<jsp:useBean id="monBean" scope="session" class="test.MonBean" >
<jsp:setProperty name="monBean" property="*" />
</jsp:useBean>
Développons en Java
370

Cet exemple a le même effet que le précédent avec une initialisation des propriétés du bean lors de son instanciation avec
les valeur des paramètres correspondants.
Exemple complet :

<html>
<HEAD>
<TITLE>Essai d'instanciation d'un bean dans une JSP</TITLE>
</HEAD>
<body>
<p>Test d'utilisation d'un Bean dans une JSP </p>
<jsp:useBean id="personne" scope="request" class="test.Personne" />
<p>nom initial = <%=personne.getNom() %></p>
<%
personne.setNom("mon nom");
%>
<p>nom mise à jour = <%= personne.getNom() %></p>
</body>
</html>

package test;
public class Personne {
  private String nom;
  private String prenom;
  public Personne() {
    = "nom par defaut";
    this.prenom = "prenom par defaut";
  }
  public void setNom (String nom) {
    = nom;
  }
  public String getNom() {
    return ();
  }
  public void setPrenom (String prenom) {
    this.prenom = prenom;
  }
  public String getPrenom () {
    return (this.prenom);
  }
}
Selon le moteur de JSP utilisé, les fichiers du bean doivent être placé dans un répertoire particulier pour être accessible
par la JSP.
P o u r   t e s t e r   c e t t e   J S P   a v e c   T o m c a t ,   i l   f a u t   c o m p i l e r   l e   b e a n   P e r s o n n e   d a n s   l e   r é p e r t o i r e
c:\jakarta?tomcat\webapps\examples\web?inf\classes\test et placer le fichier dans le répertoire
c:\jakarta?tomcat\webapps\examples\jsp\test.
Développons en Java
371

28.4.4.2. Le tag <jsp:setProperty >
Le tag <jsp:setProperty> permet de mettre à jour la valeur d'un ou plusieurs attributs d'un Bean. Le tag utilise le setter
(méthode getXXX() ou XXX est le nom de la propriété) pour mettre à jour la valeur. Le bean doit exister grâce à un
appel au tag <jsp:useBean>.
Il existe trois façon de mettre à jour les propriétés soit à partir des paramètres de la requête soit avec une valeur :
alimenter automatiquement toutes les propriétés avec les paramètres correspondants de la requête
• 
alimenter automatiquement une propriété avec le paramètre de la requête correspondant
• 
alimenter une propriété avec la valeur précisée
• 
La syntaxe est la suivante :
<jsp:setProperty name="beanInstanceName"
{ property="*" |
property="propertyName" [ param=" parameterName" ] |
property="propertyName" value="{string | <%= expression%>}"
}
/>
L'attribut name doit contenir le nom de la variable qui contient la référence du bean. Cette valeur doit être identique à
celle de l'attribut id du tag <jsp:useBean> utilisé pour instancier le bean.
L'attribut property= «*» permet d'alimenter automatiquement les propriétés du bean avec les paramètres correspondants
contenus dans la requête. Le nom des propriétés et le nom des paramètres doivent être identiques.
Comme les paramètres de la requête sont toujours fournis sous forme de String, une conversion est réalisée en utilisant la
méthode valueOf() du wrapper du type de la propriété.
Exemple :
<jsp:setProperty name="monBean" property="*" />
L'attribut property="propertyName" [ param="parameterName"] permet de mettre à jour un attribut du bean. Par défaut,
l'alimentation est faite automatiquement avec le paramètre correspondant dans la requête. Si le nom de la propriété et du
paramètre sont différents, il faut préciser l'attribut property et l'attribut param qui doit contenir le nom du paramètre qui
va alimenter la propriété du bean.
Exemple :
<jsp:setProperty name="monBean" property="nom"/>
Développons en Java
372

L'attribut property="propertyName" value="{string | <%= expression %>}" permet d'alimenter la propriété du bean avec
une valeur particulière.
Exemple :
<jsp:setProperty name="monBean" property="nom" value="toto" />
Il n'est pas possible d'utiliser param et value dans le même tag.
Exemple : Cette exemple est identique au précédent
<html>
<HEAD>
<TITLE>Essai d'instanciation d'un bean dans une JSP</TITLE>
</HEAD>
<body>
<p>Test d'utilisation d'un Bean dans une JSP </p>
<jsp:useBean id="personne" scope="request" class="test.Personne" />
<p>nom initial = <%= personne.getNom() %></p> 
<jsp:setProperty name="personne" property="nom" value="mon nom" />
<p>nom mis à jour = <%= personne.getNom() %></p>
</body>
</html>
Ce tag peut être utilisé entre les tags <jsp:useBean> et </jsp:useBean> pour initialiser les propriétés du bean lors de son
instanciation.
28.4.4.3. Le tag <jsp:getProperty>
Le tag <jsp:getProperty> permet d'obtenir la valeur d'un attribut d'un Bean. Le tag utilise le getter (méthode getXXX() ou
XXX est le nom de la propriété) pour obtenir la valeur et l'insérer dans la page HTML généré. Le bean doit exister grâce
à un appel au tag <jsp:useBean>.
La syntaxe est la suivante :
<jsp:getProperty name="beanInstanceName" property=" propertyName" />
L'attribut name indique le nom du bean tel qu'il a été déclaré dans le tag <jsp:useBean>.
L'attribut property indique le nom de la propriété dont on veut la valeur.
Exemple :
<html>
<HEAD>
<TITLE>Essai d'instanciation d'un bean dans une JSP</TITLE>
</HEAD>
<body>
<p>Test d'utilisation d'un Bean dans une JSP </p>
<jsp:useBean id="personne" scope="request" class="test.Personne" />
<p>nom initial = <jsp:getProperty name="personne" property="nom" /></p>
<jsp:setProperty name="personne" property="nom" value="mon nom" />
<p>nom mise à jour = <jsp:getProperty name="personne" property="nom" /></p>
</body>
</html>
Développons en Java
373

Attention : ce tag ne permet pas d'obtenir la valeur d'une propriété indexée ni les valeurs d'un attribut
d'un EJB.
Remarque : avec Tomcat 3.1, l'utilisation du tag <jsp:getProperty> sur un attribut dont la valeur est null n'affiche rien
alors que l'utilisation d'un tag d'expression retourne « null ».
Exemple :
<html>
<HEAD>
<TITLE>Essai d'instanciation d'un bean dans une JSP</TITLE>
</HEAD>
<body>
<p>Test d'utilisation d'un Bean dans une JSP </p> 
<jsp:useBean id="personne" scope="request" class="test.Personne" />
<p>nom initial = <jsp:getProperty name="personne" property="nom" /></p>
<% personne.setNom(null);%>
<p>nom mis à jour = <jsp:getProperty name="personne" property="nom" /></p>
<p>nom mis à jour = <%= personne.getNom() %></p>
</body>
</html>
28.4.4.4. Le tag de redirection <jsp:forward>
Le tag <jsp:forward> permet de rediriger la requête vers une autre URL pointant vers un fichier HTML, JSP ou un
servlet.
Dès que le moteur de JSP rencontre ce tag, il redirige le requête vers l'URL précisée et ignore le reste de la JSP courante.
Tout ce qui a été généré par la JSP est perdu.
La syntaxe est la suivante :
<jsp:forward page="{relativeURL | <%= expression %>}" />
ou
<jsp:forward page="{relativeURL | <%= expression %>}" >
<jsp:param name="parameterName" value="{ parameterValue | <%= expression %>}" /> +
</jsp:forward>
L'option page doit contenir la valeur de l'URL de la ressource vers laquelle la requête va être redirigée.
Cette URL est absolue si elle commence par un '/' ou relative à la JSP sinon. Dans le cas d'une URL absolue, c'est le
serveur web qui détermine la localisation de la ressource.
Développons en Java
374

Il est possible de passer un ou plusieurs paramètres vers la ressource appelée grâce au tag <jsp :param>.
Exemple :

<html> 
<body> 
<p>Page initiale appelée</p>
<jsp:forward page=""/>
</body>
</html>

<HTML>
<HEAD>
<TITLE>Page HTML</TITLE>
</HEAD>
<BODY>
<p><table border="1" cellpadding="4" cellspacing="0" width="30%" align=center >
<tr bgcolor="#A6A5C2">
<td align="center">Page HTML forwardée</Td>
</Tr>
</table></p>
</BODY>
</HTML>
Le fichier doit être dans le même répertoire que la JSP. Lors de l'appel à la JSP, c'est le page HTML qui est
affichée. Le contenu généré par la page JSP n'est pas affiché.
28.4.4.5. Le tag <jsp:include>
Ce permet d'inclure le contenu d'un fichier dynamiquement au moment ou la servlet est executé. C'est la différence avec
la directive include avec laquelle le fichier est inséré dans la JSP avant la génération de la servlet.
La syntaxe est la suivante :
<jsp:include page="relativeURL" flush="true" />
L'attribut page permet de préciser l'URL relative de l'élément à insérer.
L'attribut flush permet d'indiquer si le tampon doit être vidé.
La suite de cette section sera développée dans une version future de ce document
28.4.4.6. Le tag <jsp:plugin>
Cette section sera développée dans une version future de ce document
Développons en Java
375

28.5. Un Exemple très simple
Exemple :

<HTML>
<HEAD>
<TITLE>Identification</TITLE>
</HEAD>
<BODY>
<FORM METHOD=POST ACTION="">
Entrer votre nom : 
<INPUT TYPE=TEXT NAME="nom">
<INPUT TYPE=SUBMIT VALUE="SUBMIT">
</FORM>
</BODY>
</HTML>

<HTML> 
<HEAD> 
<TITLE>Accueil</TITLE>
</HEAD> 
<BODY> 
<% 
String nom = request.getParameter("nom"); 
%> 
<H2>Bonjour <%= nom %></H2> 
</BODY> 
</HTML>
28.6. La gestion des erreurs
Lors de l'éxécution d'une page JSP, des erreurs peuvent survenir. Chaque erreur ce traduient par la lever d'une exception.
Si cette exception est capturée dans un bloc try/catch de la JSP, celle ci est traitée. Si l'exception n'est pas capturée dans
la page, il y a deux possibilités selon qu'une page d'erreur soit associée à la page JSP.
Pour associer une page d'erreur particulière à une page JSP, il faut utiliser la directive page avec l'attribut errorpage qui
précise le nom de la page JSP qui va gérer les erreurs.
Exemple :
%page errorPage="" %>
28.6.1. La définition d'une page d'erreur
Une page d'erreur est une JSP dont l'attribut isErrorPage est égal à true dans la directive page. Une telle dispose d'un
accès à la variable exception de type Throwable qui encapsule l'exception qui a été levée.
Développons en Java
376

Cette section sera développée dans une version future de ce document
28.7. Les bibliothèques de tag personnalisées (custom taglibs)
28.7.1. Présentation
Les bibliothèques de tags (taglibs)  ou tags personnalisés (custom tags) permettent de définir ses propres tags basé sur
XML, de les regrouper dans une bibliothèque et de les réutiliser dans des JSP. C'une une extension de la technologie JSP
apparu à partir de la version 1.1 des spécifications des JSP.
Un tag personnalisé est un élément du langage JSP défini par un développeur pour des besoins particuliers qui ne sont
pas traités en standard par les JSP. Elles permettent de définir ces propres tags qui réaliseront des actions pour générer la
réponse.
Le principal but est de favoriser la séparation des rôles entre le développeur java et concepteur de page web. L'idée
maitresse est de déporter le code java contenu les scriplets de la JSP dans des classes dédiées et de les appeler dans le
code source de la JSP en utilisant des tags particuliers.
Ce concept peut sembler proche de celui des javabeans dont le rôle principal est aussi de définir des composants
réutilisables. Les javabeans sont particulièrements adaptés pour stockées et échangés des données entre les composants
de l'application web via la session.
Les tags personnalisés sont adapatés pour enlever du code java inclus dans les JSP est le déporté dans une classe dédié.
Cette classe est physiquement un javabean qui implémente une interface particulière.
La principale différence entre un javabean et un tag personnalisé est que ce dernier tient compte de l'environnement dans
lequel il s'éxécute (notamment la JSP et le contexte de l'application web ) et interagit avec lui.
Pour de plus amples informations sur les bibliothèques de tags personnalisés, il suffit de consulter le site de Sun qui leurs
sont consacrées : .
Les tags personnalisés possèdent des fonctionnalités intéressantes :
ils ont un accès aux objets de la JSP notamment l'objet de type HttpResponse. Ils peuvent donc modifier le
• 
contenu de la réponse générée par la JSP
ils peuvent recevoir des paramètres envoyés à partir de la JSP leur de leur appel
• 
ils peuvent avoir un corps qu'ils peuvent manipuler. Par extension de cette fonctionnalité, il est possible
• 
d‘imbriquer un tag personnalisé dans un autre avec un nombre d'imbrication illimité
Les avantages des bibliothèques de tags personnalisés sont donc :
un suppression du code java dans la JSP remplacé par un tag XML facilement compréhensible ce qui simplifie
• 
grandement la JSP
une API facile a mettre en oeuvre
• 
une forte et facile réutilisabilité des tags développés
• 
une maintenance des JSP facilitée
• 
La définition d'une bibliothèque de tags comprend plusieurs entités :
une classe dit "handler" pour chaque tag qui compose la bibliothèque
• 
Développons en Java
377

un fichier de description de la bibliothèque
• 
28.7.2. Les handlers de tags
Chaque tag est associé à une classe qui va contenir les traitements à éxécuter lors de l'utilisation du tag. Une telle classe
est nommée "handler de tag" (tag handler). Pour permettre leur appel, une telle classe doit obligatoirement implémenter
directement ou indirectement l'interface 
L'interface Tag possède une interface fille BodyTag qui doit être utilisée dans le cas ou le tag peut utiliser le contenu de
son corps.
Pour plus de faciliter, l'API JSP propose les classes TagSupport et BodyTagSupport qui implémentent respectivement
l'interface Tag et BodyTag. Ces deux classes, contenues dans le package .tagext, proposent des
implémentations par défaut des méthodes de l'interface. Ces deux classes proposent un traitement standard par défaut
pour chacunes des méthodes de l'interface qu'ils implémentent. Pour définir un handler de tag, il suffit d'hériter de l'une
ou l'autre de ces deux classes.
Les méthodes définies dans les interfaces Tag et BodyTag sont appellées, par la servlet issue de la compilation de la JSP,
au cours de l'utilisation du tag.
Le cycle de vie général d'un tag est le suivant :
lors de la rencontre du début du tag, un objet du type du handler est instancié
• 
plusieurs propriété sont initialisées (pageContext, parent, ...) en utilisant les setters correspondant
• 
si le tag contient des attributs, les setters correspondant sont appelés pour alimenter leur valeur
• 
la méthode doStartTag() est appelée
• 
Si la méthode doStartTag() renvoie la valeur EVAL_BODYINCLUDE alors le contenu du corps du tag est
• 
évalué
lors de la rencontre de la fin du tag, appel de la méthode doEndTag()
• 
Si la méthode doEndTag() renvoie la valeur EVAL_PAGE alors l'évaluation de la page se poursuit, si elle
• 
renvoie la valeur SKIP_PAGE elle ne se poursuit pas
Toutes ces opérations sont réalisées par le code généré lors de la compilation de la JSP.
Un handler de tag possède un objet qui permet d'avoir un accès aux objets implicite de la JSP. Cet objet est du type
.PageContext
Comme le code contenu dans la classe du tag ne peut être utilisé que dans le contexte particulier du tag, il peut être
intéressant de sortir une partie de ce code dans une ou plusieurs classes dédiées qui peuvent être éventuellement des
beans.
Pour compiler ces classes, il obligatoirement que le jar de l'API servlets () soit inclus dans la variable
CLASSPATH.
28.7.3. L'interface Tag
Cette interface définit les méthodes principales pour la gestion du cycle de vie d'un tag personnalisé qui ne doit pas
manipuler le contenu de son corps.
Elle définie plusieurs constantes :
Constante
Rôle
EVAL_BODY_INCLUDE
Continuer avec l'évaluation du corps du tag
EVAL_PAGE
Continuer l'évaluation de la page
SKIP_BODY
Empeche l'évaluation du corps du tag
Développons en Java
378

SKIP_PAGE
Empecher l'évaluation du reste de la page
Elle définie aussi plusieurs méthodes :
Méthode
Rôle
int doEndTag()
Traitements à la rencontre du tag de début
int doStartTag()
Traitements à la rencontre du tag de fin
setPageContext(Context)
Sauvegarde du contexte de la page
La méthode doStartTag() est appelée lors de la rencontre du tag d'ouverture et contient les traitements à effectuer dans ce
cas. Elle doit renvoyer un entier prédéfini qui indique comment va se poursuivre le traitement du tag :
EVAL_BODY_INCLUDE : poursuite du traitement avec évaluation du corps du tag
• 
SKIP_BODY : poursuite du traitement sans évaluation du corps du tag
• 
La méthode doEndTag() est appelée lors de la rencontre du tag de fermeture et contient les traitements à effectuer dans
ce cas. Elle doit renvoyer un entier prédéfini qui indique comment va se poursuivre le traitement de la JSP.
EVAL_PAGE : poursuite du traitement de la JSP
• 
SKIP_PAGE : ne pas poursuivre le traitement du reste de la JSP
• 
28.7.4. L'accès aux variables implicites de la JSP
Les tags ont accès aux variables implicites de la JSP dans laquelle ils s'éxécutent via un objet de type PageContext. La
variable pageContext est un objet de ce type qui est initialisé juste après l'instanciation du handler.
Le classe PageContext est une classe abstraite dont l'implémentation des spécifications doit fournir une adaption
concrète.
Cette classe définie plusieurs méthodes :
Méthodes
Rôles
JspWriter getOut()
Permet un accès à la variable out de la JSP
Exception getException()
Permet un accès à la variable exception de la JSP
Object getPage()
Permet un accès à la variable page de la JSP
ServletRequest getRequest()
Permet un accès à la variable request de la JSP
ServletResponse getResponse()
Permet un accès à la variable response de la JSP
ServletConfig getServletConfig()
Permet un accès à l'instance de la variable de type ServletConfig
ServletContext
Permet un accès à l'instance de la variable de type ServletContext
getServletContext()
HttpSession getSession()
Permet un accès à la session
Object getAttribute(String)
Renvoie l'objet associé au nom fourni en paramètre dans la portée de la page
Permet de place dans la portée de la page un objet dont le nom est fourni en
setAttribute(String, Object)
paramètre
Développons en Java
379

28.7.5. Les deux types de handlers
Il existe deux types de handlers :
les handlers de tags sans corps
• 
les handlers de tags avec corps
• 
28.7.5.1. Les handlers de tags sans corps
Pour définir le handler d'un tag personnalisé sans corps, il suffit de définir une classe qui implémente l'interface Tag ou
qui héritent de la classe TagSupport. Il faut définir ou redéfinir les méthodes doStartTag() et endStartTag()
La méthode doStartTag() est appelée à la rencontre du début du tag. Cette méthode doit contenir le code à éxécuter dans
ce cas et renvoyer la constante SKIP_BODY puisque le tag ne contient pas de corps
28.7.5.2. Les handlers de tags avec corps
Le cycle de vie d'un tel tag inclus le traitement du corps si la méthode doStartTag() renvoie la valeur
EVAL_BODY_TAG.
Dans ce cas, les opérations suivantes sont réalisés :
la méthode setBodyContent() est appelée
• 
le contenu du corps est traité
• 
la méthode doAfterBody() est appelée. Si elle renvoie la valeur EVAL_BODY_TAG, le contenu du coprs est de
• 
nouveau traité
28.7.6. Les paramètres d'un tag
Un tag peut avoir un ou plusieurs paramètres qui seront transmis à la classe via des attributs. Pour chacun des paramètres,
il faut définir des getter et des setter en respectant les règles et conventions des beans. Il est impératif de définir un
champ, un setter et éventuellement un accesseur pour chaque attribut.
La JSP utilisera le setter pour fournir à l'objet la valeur de l'attribut.
Au moment de la génération de la servlet par le moteur de JSP, celui ci vérifie par introspection la présence d'un setter
pour l'attribut.
28.7.7. Définition du fichier de description de la bibliothèque de tags (TLD)
Le fichier de description de la bibliothèque de tags (tag library descriptor file) est un fichier au format XML qui décrit
une bibliothèque de tag.  Les informations qu'il contient concerne la bibliothèque de tag elle même et concerne aussi
chacun des tags qui la compose.
Ce fichier est utilisé par le conteneur Web lors de la compilation de la JSP pour remplacer le tag par du code java.
Développons en Java
380

Ce fichier doit toujours avoir pour extension .tld. Il doit être placé dans le répertoire web?inf du fichier war ou dans un
de ces sous répertoires. Le plus pratique est de tous les regrouper dans un répertoire nommé par exemple tags ou tld.
Comme tout bon fichier XML, le fichier TLD commence par un prologue :
Exemple :
<?xml version="1.0" encoding="ISO?8859?1" ?>
<!DOCTYPE taglib
  PUBLIC "?//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
  "?">
La DTD précisée doit correspondre à la version de l'API JSP utilisée. L'exemple précédent concernait la version 1.1,
l'exemple suivant concerne la version 1.2
Exemple :
<?xml version="1.0" encoding="ISO?8859?1" ?>
<!DOCTYPE taglib
  PUBLIC "?//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "?">
Le tag racine du document XML est le tag <taglib>
Ce tag peut contenir plusieurs tags qui définissent les caractéristiques générales de la bibliothèque. Les tags suivants  sont
définis dans les spécifications 1.2 :
Nom
Rôle
tlib?version
version de la bibliothèque
jsp?version
version des spécifications JSP utilisée
short?name
nom court la bibliothèque (optionnel)
uri
uri qui identifie de façon unique la bibliothèque : cette uri n'a pas besoin d'exister rééllement
display?name
nom de la bibliothèque
small?icon
(optionnel)
large?icon
(optionnel)
description
description de la bibliothèque
validator
(optionnel)
listener
(optionnel)
tag
il en faut autant que de tags qui composent la bibliothèque
Pour chaque tag personnalisé défini dans la bibliothèque, il faut un tag <tag>. Le tag <tag> permet de définir les
caractérisques d'un tag de la bibliothèque.
Ce tag peut contenir les tags suivants :
Nom
Rôle
name
nom du tag : il doit être unique dans la bibliothèque
tag?class
nom entièrement qualifié de la classe qui contient le handler du tag
tei?class
nom qualifié d'une classe fille de la classe .tagext.TagExtraInfo (optionnel)
Développons en Java
381

type du corps du tag. Les valeurs possibles sont :
JSP : le corps du tag contient des tags JSP qui doivent être interprétés
• 
body?content
tagdependent : l'interprétation du contenu du corps est faite par le tag
• 
empty : le corps doit obligatoirement être vide
• 
La valeur par défaut est JSP
display?name
nom court du tag
small?icon
nom relatif par rapport à la ibliothèque d'un fichier gif ou jpeg contenant une icône. (optionnel)
large?icon
nom relatif par rapport à la ibliothèque d'un fichier gif ou jpeg contenant une icône. (optionnel)
description
description du tag (optionnel)
variable
(optionnel)
attribute
il en faut autant que d'attribut  possédé par le tag (optionnel)
example
un exemple de l'utilisation du tag (optionnel)
Pour chaque attributs du tag personnalisé, il faut utiliser un tag <attribute>. Ce tag décrit un attribut d'un tag et peut
contenir les tags suivants :
Nom
Description
name
Nom de l'attribut
required
boolean qui indique la présence obligatoire de l'attribut
boolean qui indique si la page doit évaluer l'expression lors de l'éxécution. Il faut donc mettre la valeur
rtexprvalue
true si la valeur de l'attribut est fournie avec un tag JSP d'expression <%= %>
Le tag Variable contient les tag suivants :
Nom
Rôle
name?given
name?from?attribut
variable?class
classe de la valeur de l'attribut. Par défaut .String
declare
Par défaut : True
visibilité de l'attribut. Les valeurs possibles sont :
AT_BEGIN
• 
scope
NESTED
• 
AT_END
• 
Par défaut : NESTED (optionnel)
description
description de l'attribut (optionnel)
Chaque bibliothèque doit être définie avec un fichier de description au format xml possèdant une extension .tld. Le
contenu de ce fichier doit pouvoir être validé avec une DTD fournie par SUN.
Ce fichier est habituellement stockée dans le répertoire web?inf de l'application web ou un de ces sous répertoires.
Exemple :
Développons en Java
382

<?xml version="1.0" encoding="ISO?8859?1" ?>
  <!DOCTYPE taglib PUBLIC "?//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
  "?">
<taglib>
  <tlibversion>1.0</tlibversion>
  <jspversion>1.1</jspversion>
  <shortname>testtaglib</shortname>
  <uri>.taglib</uri>
  <info>Bibliotheque de test des taglibs</info>
  <tag>
  <name>testtaglib1</name>
  <tagclass>.taglib.TestTaglib1</tagclass>
  <info>Tag qui affiche bonjour</info>
  </tag>
</taglib>
28.7.8. Utilisation d'une bibliothèque de tags
Pour utiliser une bibliothèque de classe, il y a des actions à réaliser au niveau du code source de la JSP et au niveau de
conteneur d'application web pour déployer la bibliothèque de tags.
28.7.8.1. Utilisation dans le code source d'une JSP
Pour chaque bibliothèque à utiliser dans une JSP, il faut la déclarer en utilisant la directive taglib avant son utilisation. Le
plus simple est d'effectuer ces déclarations tout au début du code de la JSP.
Elle possède deux attributs :
uri : l'uri de la bibliothèque telle que définie dans le fichier de description
• 
prefix : un préfix qui servira d'espace de nom pour les tags de la bibliothèque dans la JSP
• 
Exemple :
<%@ taglib uri="/WEB?" prefix="maTagLib" %>
L'attribut uri permet de donner une identitée au fichier de description de la bibliothèque de tags (TLD). La valeur fournie
peut être :
directe (par exemple le nom du fichier avec son chemin relatif)
• 
Exemple :
<%@ taglib uri="/WEB?" prefix="maTagLib" %>
ou indirecte (concordance avec un nom logique défini dans un tag taglib du descripteur de déploiement de
• 
l'application web )
Exemple :
<%@ taglib uri= “/maTaglib” prefix= “maTagbib” %>
Dans ce dernier cas, il faut ajouter pour chaque bibliothèque un tag "taglib" dans le fichier de description de déploiement
de l'application/WEB?
Développons en Java
383

Exemple :
 <taglib>
    <taglib?uri>/maTagLibTest</taglib?uri>
    <taglib?location>/WEB?</taglib?location>
  </taglib>
L'appel d'un tag se fait en utilisant un tag dont le nom à la forme suivante : prefix:tag
Le préfix est celui défini dans la directive taglib.
Exemple : un tag sans corps :
<maTagLib:testtaglib1/>
Exemple : une tag avec corps :
<prefix:tag>
   ...
</prefix:tag>
Le corps peut contenir du code HTML, du code JSP ou d'autre tag personnalisé.
Le tag peut avoir des attributs si ceux ci ont été définis. La syntaxe pour les utiliser respecte la norme XML
Exemple : un tag avec un paramètre constant :
<prefix:tag attribut="valeur"/>
La valeur de cet attribut peut être une donnée dynamiquement évaluée lors de l'éxécution :
Exemple : un tag avec un paramètre :
<prefix:tag attribut="<%= uneVariable%>"/>
28.7.8.2. Déploiement d'une bibliothèque
Au moment de la compilation de la JSP en servlet, le conteneur transforme chaque tag en un appel à un objet du type de
la classe associé au tag.
Il y a deux types d'éléments dont il faut s'assurer l'accès par le contenur d'application web :
le fichier de description de bibliothèque
• 
les classes des handlers de tag
• 
Les classes des handlers de tags peuvent être stockés à deux endroits dans le fichier war selon leur format :
si ils sont packagés sous forme de fichier jar alors ils doivent être placés dans le répertoire /WEB?INF/lib
• 
si ils ne sont pas packagés alors ils doivent être placés dans le répertoire /WEB?INF/classes
• 
Développons en Java
384

28.7.9. Déploiement et tests dans Tomcat
Tomcat étant l'implémentation de référence pour les technologies servlets et JSP, il est pratique d'effectuer des tests avec
cet outils.
La version de Tomcat utilisée dans cette section est la 3.2.1.
28.7.9.1. Copie des fichiers
Les classes compilées doivent être copiées dans le répertoire WEB?INF/classes de la webapp si elles ne sont pas
packagées dans u jar, sinon le ou les jour doivent être copiés dans le répertoire WEB?INF/lib.
Le fichier tld doit être copié dans le répertoire WEB?INF ou dans un de ces sous répertoires.
28.7.9.2. Enregistrement de la bibliothèque
Il faut enregistrer la bibliothèque dans le fichier de configuration contenu dans le répertoire web?inf du
répertoire de l'application web.
Il faut ajouter dans ce fichier, un tag <taglib> pour chaque bibliothèque utilisée par l'application web contenant deux
informations :
l'uri de la bibliothèque contenue dans le tag taglib?uri. Cette uri doit être identique à celle définie dans le fichier
• 
de description de la bibliothèque
la localisation du fichier de description
• 
Exemple :
<?xml version="1.0" encoding="ISO?8859?1"?>
<!DOCTYPE web?app
  PUBLIC "?//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
  "?">
<web?app>
  <welcome?file?list id="ListePageDAccueil">
    <welcome?file></welcome?file>
    <welcome?file></welcome?file>
  </welcome?file?list>
  <taglib>
    <taglib?uri>/maTagLibTest</taglib?uri>
    <taglib?location>/WEB?</taglib?location>
  </taglib>
</web?app>
28.7.9.3. Test
Il reste plus qu'à lancer Tomcat si ce n'est pas encore faire et de saisir l'url de la page contenant l'appel au tag
personnalisé.
28.7.10. Les bibliothèques de tags existantes
Il existe de nombreuses bibliothèques de tags libres ou commerciales disponibles sur le marché. Cette section va tenter de
présenter quelques unes de plus connues et des plus utilisées du monde libre. Cette liste n'est pas exhaustive.
Développons en Java
385

28.7.10.1. Struts
Struts est un framework pour la réalisation d'application web reposant sur le modèle MVC 2.
Pour la partie vue, Struts utilise les JSP et propose en plus plusieurs bibliothèques de tags pour faciliter le développement
de cette partie présentation. Struts possède quatre grandes bibliothèques :
formulaire HMTL
• 
modeles (templates)
• 
Javabeans (bean)
• 
traitements logiques (logic)
• 
Le site web de struts se trouve à l'url :
28.7.10.2. Jakarta Tag libs
28.7.10.3. JSP Standard Tag Library (JSTL)
JSP Standard Tag Library (JSTL) est une spécification issu du travail du JCP sous la JSR numéro 52. Le chapitre sur
JSTL fourni plus de détails sur cette spécification .
Développons en Java
386

29. JSTL (Java server page Standard Tag Library)
29.1. Présentation
JSTL est l'acronyme de Java server page Standard Tag Library. C'est un ensemble de tags personnalisés développé sous
la JSR 052 qui propose des fonctionnalités souvent rencontrées dans les JSP :
Tag de structure (itération, conditionnement ...)
• 
Internationnalisation
• 
Exécution de requete SQL
• 
Utilisation de document XML
• 
JSTL nécessite un conteneur d'application web qui implémente l'API servlet 2.3 et l'API JSP 1.2. L'implémentation de
référence (JSTL?RI) de cette spécification est développée par le projet Taglibs du groupe Apache sous le nom
« Standard ».
Il est possible de télécharger cette implémentation de référence à l'URL :
?
JSTL est aussi inclus dans le JWSDP (Java Web Services Developer Pack), ce qui facilite son installation et son
utilisation. Les exemples de cette section ont été réalisés avec le JWSDP 1.001
JSTL possède quatre bibliothèques de tag :
Rôle
TLD
Uri
Fonctions de base
c.tld

Traitements XML
x.tld

Internationnalisation


Traitements SQL


JSTL propose un langage nommé EL (expression langage) qui permet de faire facilement référence à des objets java
accessible dans les différents contexte de la  JSP.
La bibliothèque de tag JSTL est livrée en deux versions :
JSTL?RT : les expressions pour désigner des variables utilisant la syntaxe JSP classique
• 
JSTL?EL : les expressions pour désigner des variables utilisant le langage EL
• 
Pour plus informations, il est possible de consulter les spécifications à l'url suivante :

Développons en Java
387

29.2. Un exemple simple
Pour commencer, voici un exemple et sa mise en oeuvre détaillée. L'application web d'exemple se nomme test. Il faut
créer un répertoire test dans le répertoire webapps de tomcat.
Pour utiliser JSTL, il faut copier les fichiers et dans le répertoire WEB?INF/lib de l'application web.
Il faut copier les fichiers .tld dans le répertoire WEB?INF ou un de ces sous répertoires. Dans la suite de l'exemple, ces
fichiers ont été placé le répertoire /WEB?INF/tld.
Il faut ensuite déclarer les bibliothèques à utiliser dans le fichier du répertoire WEB?INF comme pour toutes
bibliothèque de tags personnalisés.
Exemple : pour la bibliothèque Core :
<taglib>
    <taglib?uri>;/taglib?uri>
<taglib?location>/WEB?</taglib?location> 
</taglib> 
L'arborescence des fichiers est la suivante :
webapps
      test
            WEB?INF
                  lib
                       
                       
                  tld
                        c.tld
                 
           
Pour pouvoir utiliser une bibliothèque personnalisée, il faut utiliser la directive taglib :
Exemple :
<%@ taglib prefix="c" uri="; %>
Voici les code sources des différents fichiers de l'application web :
Exemple : fichier
<%@ taglib uri="; prefix="c" %>
<html>
  <head>
    <title>Exemple</title>
  </head>
  <body>
      <c:out value="Bonjour" /><br/>
  </body>
</html>
Exemple : le fichier WEB?
Développons en Java
388

<?xml version="1.0" encoding="ISO?8859?1"?>
<!DOCTYPE web?app
    PUBLIC "?//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "?">
<web?app>
  <taglib>
    <taglib?uri>;/taglib?uri>
<taglib?location>/WEB?</taglib?location> 
</taglib>
</web?app>
Pour tester l'application, il suffit de lancer Tomcat et de saisir l'url dans un browser.
29.3. Le langage EL (Expression Langage)
JSTL propose un langage particulier constitué d'expressions qui permet d'utiliser et de faire référence à des objets java
accessible dans les différents contexte de la page JSP. Le but est de fournir un moyen simple d'accéder aux données
nécessaire à une JSP.
La syntaxe de base est ${xxx} ou xxx est le nom d'une variable d'un objet java définie dans un contexte particulier. La
définition dans un contexte permet de définir la portée de la variable (page, requete, session ou application).
EL permet facilement de s'affranchir de la syntaxe de java pour obtenir une variable.
Exemple : accéder à l'attribut nom d'un objet personne situé dans la session avec Java
<%= session.getAttribute("personne").getNom() %>
Exemple : accéder à l'attribut nom d'un objet personne situé dans la session avec EL
${}
EL possède par défaut les variables suivantes :
Variable
Rôle
PageScope
variable contenue dans la portée de la page (PageContext)
RequestScope
variable contenue dans la portée de la requète (HttpServletRequest)
SessionScope
variable contenue dans la portée de la session (HttpSession)
ApplicationScope
variable contenue dans la portée de l'application (ServletContext)
Param
paramètre de la requete http
ParamValues
paramètres de la requète sous la forme d'une collection
Header
en tête de la requète
HeaderValues
en têtes de la requète sous la forme d'une collection
InitParam
paramètre d'initialisation
Cookie
cookie
Développons en Java
389

PageContext
objet PageContext de la page
EL propose aussi différents opérateurs :
Operateur
Rôle
Exemple
.
Obtenir une propriété d'un objet
${}
${param[« nom »]}
[]
Obtenir une propriété par son nom ou son indice
${row[1]}
Teste si un objet est null ou vide si c'est une chaine de caractère. Renvoie un
${empty
Empty
booleen
}
==
test l'égalité de deux objet
eq
!=
test l'inégalité de deux objet
ne
<
test strictement inférieur
lt
>
test strictement supérieur
gt
<=
test inférieur ou égal
le
>=
test supérieur ou égal
ge
+
Addition
?
Soustraction
*
Multiplication
/
Division
div
%
Modulo
mod
&&
and
||
or
!
Négation d'un valeur
not
EL ne permet pas l'accès aux variables locales. Pour pouvoir accéder à de telles variables, il faut obligatoirement en créer
une copie dans une des portées particulières : page, request, session ou application
Exemple :
<%
  int valeur = 101;
%>
  valeur = <c:out value="${valeur}" /><BR/>
Développons en Java
390

Résultat :
valeur =
Exemple : avec la variable copiée dans le contexte de la page
<%
  int valeur = 101;
  pageContext.setAttribute("valeur", new Integer(valeur));
%>
  valeur = <c:out value="${valeur}" /><BR/>
Résultat :
valeur = 101
29.4. La bibliothèque Core
Elle propose les tags suivants répartis dans trois catégories :
Catégorie
Tag
set
out
Utilisation de EL
remove
catch
if
choose
Gestion du flux (condition et itération)
forEach
forTokens
import
Gestion des URL
url
redirect
Pour utiliser cette bibliothèque, il faut la déclarer dans le fichier du répertoire WEB?INF de l'application web.
Exemple :
 <taglib>
    <taglib?uri>;/taglib?uri>
    <taglib?location>/WEB?</taglib?location> 
</taglib> 
Dans chaque JSP qui utilise un ou plusieurs tags de la bibliothèque, il faut la déclarer avec une directive taglib
Exemple :
<%@ taglib uri="; prefix="c" %>
Développons en Java
391

29.4.1. Le tag set
Le tag set permet de stocker une variable dans une portée particulière (page, requete, session ou application).
Il possède plusieurs attributs :
Attribut
Rôle
value
valeur à stocker
target
nom de la variable contenant un bean dont la propriété doit être modifiée
property
nom de la propriété à modifier
var
nom de la variable qui va stocker la valeur
scope
portée de la variable qui va stocker la valeur
Exemple :
    <c:set var="maVariable1" value="valeur1" scope="page" />
    <c:set var="maVariable2" value="valeur2" scope="request" />
    <c:set var="maVariable3" value="valeur3" scope="session" />
    <c:set var="maVariable4" value="valeur4" scope="application" />
La valeur peut être déterminée dynamiquement.
Exemple :
    <c:set var="maVariable" value="${}" scope="page" />
L'attribut target avec l'attribut property permet de modifier la valeur d'une propriété (précisée avec l'attribut property)
d'un objet (précisé avec l'attribut target).
La valeur de la variable peut être précisée dans le corps du tag plutot que d'utiliser l'attribut value.
Exemple :
<c:set var="maVariable" scope="page">
       Valeur de ma variable
</c:set>
29.4.2. Le tag out
Le tag out permet d'envoyer dans le flux de sortie de la JSP le résultat de l'évaluation de l'expression fournie dans le
paramètre « value ». Ce tag est équivalent au tag d'expression <%= ... %> de JSP.
Il possède plusieurs attributs :
Développons en Java
392

Attribut
Rôle
value
valeur à afficher (obligatoire)
default
définir une valeur par défaut si la valeur est null
booléen qui precise si les caractères particuliers (< > & ...) doivent être convertis en leur équivalent
escapeXml HTML (&lt; &gt; &amp ; ...)
Exemple :
    <c:out value='${pageScope.maVariable1}' />
    <c:out value='${requestScope.maVariable2}' />
    <c:out value='${sessionScope.maVariable 3}' />
    <c:out value='${applicationScope.maVariable 4}' />
Il n'est pas obligatoire de préciser la portée dans laquelle la variable est stockée : dans ce cas, la variable est recherchée
prioritairement dans la page, la requete, la session et enfin  l'application.
L'attribut default permet de définir une valeur par défaut si le résultat de l'évaluation de la valeur est null. Si la valeur est
null et que l'attribut default n'est pas utilisé alors c'est une chaine vide qui est envoyée dans le flux de sortie.
Exemple :
   <c:out value="${}" default="Inconnu" />
Le tag out est particulière utile pour générer le code dans un formulaire en remplaçant avantageusement les scriplets.
Exemple :
<input type="text" name="nom" value="<c:out value="${}"/>" />
29.4.3. Le tag remove
Le tag remove permet de supprimer une variable d'une portée particulière.
Il possède plusieurs attributs :
Attribut
Rôle
var
nom de la variable à supprimer (obligatoire)
scope
portée de la variable
Exemple :
    <c:remove var="maVariable1" scope="page" />
    <c:remove var="maVariable2" scope="request" />
    <c:remove var="maVariable3" scope="session" />
Développons en Java
393

    <c:remove var="maVariable4" scope="application" />
29.4.4. Le tag catch
Ce tag permet de capturer des exceptions qui sont levées lors de l'éxécution du code inclus dans son corps.
Il possède un attribut :
Attribut
Rôle
var
nom d'une variable qui va contenir des informations sur l'anomalie
Si l'attribut var n'est pas utilisé, alors toutes les exceptions levées lors de l'exécution du corps du tag sont ignorées.
Exemple : code non protégé
<c:set var="valeur" value="abc" />
<fmt:parseNumber var="valeurInt" value="${valeur}"/>
Résultat : une exception est lévée
javax.servlet.ServletException: In <parseNumber>, value attribute can not be parsed: "abc"
        at org.apache.jasper.runtime.PageContextImpl.handlePageException(:471)
        at $jsp.jspService(test$:1187)
        at org.apache.jasper.runtime.HttpJspBase.service(:107)
L'utilisation du tag catch peut empecher le plantage de l'application.
Exemple :
<c:set var="valeur" value="abc" />
<c:catch var="erreur">
   <fmt:parseNumber var="valeurInt" value="${valeur}"/>
</c:catch>
<c:if test="${not empty erreur}">
   la valeur n'est pas numerique
</c:if>
Résultat :
la valeur n'est pas numerique
L'objet désigné par l'attribut var du tag catch possède une propriété message qui contient le message d'erreur
Exemple :
<c:set var="valeur" value="abc" />
<c:catch var="erreur">
Développons en Java
394

   <fmt:parseNumber var="valeurInt" value="${valeur}"/>
</c:catch>
<c:if test="${not empty erreur}">
 <c:out value="${erreur.message}"/>
</c:if>
Résultat :
In &lt;parseNumber&gt;, value attribute can not be parsed: "abc"
Le soucis avec ce tag est qu'il n'est pas possible de savoir qu'elle exception a été levée.
29.4.5. Le tag if
Ce tag permet d'évaluer le contenu de son corps si la condition qui lui est fournie est vrai.
Il possède plusieurs attributs :
Attribut
Rôle
test
condition à évaluer
var
nom de la variable qui contiendra le résultat de l'évaluation
scope
portée de la variabe qui contiendra le résultat
Exemple :
<c:if test="${empty }" >Inconnu</c:if>
Le tag peut ne pas avoir de corps si le tag est simplement utiliser pour stocker le résultat de l'évaluation de la condition
dans une variable.
Exemple :
<c:if test="${empty }" var="resultat" />
Le tag if est particulière utile pour générer le code dans un formulaire en remplaçant avantageusement les scriplets.
Exemple : selection de la bonne occurrence dont la valeur est fournie en paramètre de la requète
<FORM NAME="form1" METHOD="post" ACTION="">
  <SELECT NAME="select">
    <OPTION VALUE="choix1" <c:if test="${param.select == 'choix1'}" >selected</c:if> >
      choix 1</OPTION>
    <OPTION VALUE="choix2" <c:if test="${param.select == 'choix2'}" >selected</c:if> >
      choix 2</OPTION>
    <OPTION VALUE="choix3" <c:if test="${param.select == 'choix3'}" >selected</c:if> >
      choix 3</OPTION>
  </SELECT>
</FORM>
Développons en Java
395

Pour tester le code, il faut fournir en paramètre dans l'url select=choix2
Exemple :
?select=choix2
29.4.6. Le tag choose
Ce tag permet de traiter différents cas mutuellements exclusifs dans un même tag. Le tag choose ne possède pas
d'attribut. Il doit cependant posséder un ou plusieurs tags fils « when ».
Le tag when  possède l'attribut test qui permet de préciser la condition à évaluer. Si la condition est vrai alors le corps du
tag when est évaluer et le résultat est envoyé dans le flux de sortie de la JSP
Le tag otherwise permet de définir un cas qui ne correspond à aucun des autres inclus dans le tag. Ce tag ne possède
aucun attribut.
Exemple :
<c:choose>
  <c:when test="${personne.civilite == 'Mr'}">
    Bonjour Monsieur
  </c:when>
  <c:when test="${personne.civilite == 'Mme'}">
    Bonjour Madame
  </c:when>
  <c:when test="${personne.civilite == 'Mlle'}">
    Bonjour Mademoiselle
  </c:when>
  <c:otherwise>
    Bonjour
  </c:otherwise>
</c:choose>
29.4.7. Le tag forEach
Ce tag permet de parcourir les différents éléments d'une collection et ainsi d'exécuter de façon répétitive le contenu de
son corps.
Il possède plusieurs attributs :
Attribut
Rôle
var
nom de la variable qui contient l'élément en cours de traitement
items
collection à traiter
varStatus
nom d'un variable qui va contenir des informations sur l'itération en cours de traitement
begin
numéro du premier élément à traiter (le premier possède le numéro 0)
end
numéro du dernier élément à traiter
step
pas des éléments à traiter (par défaut 1)
Développons en Java
396

A chaque itération, la valeur de la variable dont le nom est précisé par la propriété var change pour contenir l'élement de
la collection en cours de traitement.
Aucun des attributs n'est obligatoire mais il faut obligatoirement qu'il y ait l'attribut items ou les attributs begin et end.
Le tag forEach peut aussi réaliser des itérations sur les nombres et non sur des éléments d'une collection. Dans ce cas, il
ne faut pas utiliser l'attributs items mais uniquement utiliser les attributs begin et end pour fournir les bornes inférieures
et supérieures de l'itération.
Exemple :
<c:forEach begin="1" end="4" var="i">
<c:out value="${i}"/><br>
</c:forEach>
Résultat :
1
2
3
4
L'attribut step permet de préciser le pas de l'itération.
Exemple :
<c:forEach begin="1" end="12" var="i" step="3">
  <c:out value="${i}"/><br>
</c:forEach>
Exemple :
1
4
7
10
L'attribut varStatus permet de définir une variable qui va contenir des informations sur l'itération en cours d'éxécution.
Cette variable possède plusieurs propriétés :
Attribut
Rôle
index
indique le numéro de l'occurrence dans l'ensemble de la  collection
count
indique le numéro de l'itération en cours (en commençant par 1)
first
booléen qui indique si c'est la première itération
last
booléen qui indique si c'est la dernière itération
Développons en Java
397

Exemple :
<c:forEach begin="1" end="12" var="i" step="3" varStatus="vs">
  index = <c:out value="${vs.index}"/> : 
  count = <c:out value="${vs.count}"/> : 
  value = <c:out value="${i}"/>
  <c:if test="${vs.first}">
     : Premier element
  </c:if>
  <c:if test="${}">
     : Dernier element
  </c:if>
  <br>
</c:forEach>
Résultat :
  index = 1 : count = 1 : value = 1 : Premier element 
  index = 4 : count = 2 : value = 4 
  index = 7 : count = 3 : value = 7 
  index = 10 : count = 4 : value = 10 : Dernier element
29.4.8. Le tag forTokens
Ce tag permet de découper une chaine selon un ou plusieurs séparateurs donnés et ainsi d'exécuter de façon répétitive le
contenu de son corps autant de fois que d'occurrences trouvées.
Il possède plusieurs attributs :
Attribut
Rôle
var
variable qui contient l'occurrence en cours de traitement (obligatoire)
items
la chaine de caractères à traiter (obligatoire)
delims
précise le séparateur
varStatus
nom d'un variable qui va contenir des informations sur l'itération en cours de traitement
begin
numero du premier élément à traiter (le premier possède le numéro 0)
end
numéro du dernier élément à traiter
step
pas des éléments à traiter (par défaut 1)
L'attribut delims peut avoir comme valeur une chaine de caractères ne contenant qu'un seul caractère (délimiteur unique)
ou un ensemble de caractères (délimiteurs multiples).
Exemple :
<c:forTokens var="token" items="chaine 1;chaine 2;chaine 3" delims=";">
  <c:out value="${token}" /><br>
</c:forTokens>
Exemple :
Développons en Java
398

chaine 1
chaine 2
chaine 3
Dans le cas ou il y a plusieurs délimiteurs, chacun peut servir de séparateur
Exemple :
<c:forTokens var="token" items="chaine 1;chaine 2,chaine 3" delims=";,">
  <c:out value="${token}" /><br>
</c:forTokens>
Attention : Il n'y a pas d'occurrence vide. Dans le cas ou deux séparateurs se suivent consécutivement dans la chaine à
traiter, ceux ci sont considérés comme un seul séparateur. Si la chaine commence ou se termine par un séparateur, ceux ci
sont ignorés.
Exemple :
<c:forTokens var="token" items="chaine 1;;chaine 2;;;chaine 3" delims=";">
  <c:out value="${token}" /><br>
</c:forTokens>
Résultat :
chaine 1
chaine 2
chaine 3
Il est possible de ne traiter qu'un sous ensemble des occurrences de la collection. JSTL attribut à chaque occurrence un
numéro incrémenter de 1 en 1 à partir de 0. Les attributs begin et end permettent de préciser une plage d'occurrence à
traiter.
Exemple :
<c:forTokens var="token" items="chaine 1;chaine 2;chaine 3" delims=";" begin="1" end="1" >
  <c:out value="${token}" /><br>
</c:forTokens>
Résultat :
chaine 2
Il est possible de n'utiliser que l'attribut begin ou l'attribut end. Si seul l'attribut begin est précisé alors les n dernières
occurrences seront traitées. Si seul l'attribut end est précisé alors seuls les n premières occurrences seront traitées.
Les attributs varStatus et step ont le même rôle que ceux du tag forEach.
Développons en Java
399

29.4.9. Le tag import
Ce tag permet d'accéder à une ressource via son URL pour l'inclure ou l'utiliser dans les traitements de la JSP. La
ressource accédée peut être dans une autre application.
Son grand intérêt par rapport au tag <jsp :include> est de ne pas être limité au contexte de l'application web.
Il possède plusieurs attributs :
Attribut
Rôle
url
url de la ressource (obligatoire)
var
nom de la variable qui va stocker le contenu de la ressource sous la forme d'une chaine de caractère
scope
portée de la variable qui va stocker le contenu de la ressource
contexte de l'application web qui contient la ressource (si la ressource n'est pas l'application web
context
courante)
charEncoding jeux de caractères utilisé par la ressource
nom de la variable qui va stocker le contenu de la ressource sous la forme d'un objet de type
varReader
.Reader
L'attribut url permet de préciser l'url de la ressource. Cette url peut être relative (par rapport à l'application web) ou
absolue.
Exemple :
<c:import url="" /><br>
Par défaut, le contenu de la ressource est inclus dans la JSP. Il est possible de stocker le contenu de la ressource dans une
chaine de caractères en utilisant l'attribut var. Cet attribut attend comme valeur le nom de la variable.
Exemple :
<c:import url="" var="message" />
<c:out value="${message}" /><BR/>
29.4.10. Le tag redirect
Ce tag permet de faire une redirection vers une nouvelle URL.
Les paramètres peuvent être fournis grace à un ou plusieurs tags fils param.
Exemple :
<c:redirect url="">
  <c:param name="id" value="123"/>
</c:redirect>
Développons en Java
400

29.4.11. Le tag url
Ce tag permet de formatter une url. Il possède plusieurs attributs :
Attribut
Rôle
value
base de l'url (obligatoire)
var
nom de la variable qui va stocker l'url
scope
portée de la variable qui va stocker l'url
context
Le tag url peut avoir un ou plusieurs tag fils « param ». Le tag param permet de préciser un parametre et sa valeur pour
qu'il soit ajouté à l'url générée.
Le tag param possède deux attributs :
Attribut
Rôle
name
nom du paramètre
value
valeur du paramètre
Exemple :
<a href="<c:url url=""/>"/>
29.5. La bibliothèque XML
Cette bibliothèque permet de manipuler des données en provenance d'un document XML.
Elle propose les tags suivants répartis dans trois catégories :
Catégorie
Tag
parse
Fondamentale
set
out
if
Gestion du flux (condition et itération)
choose
forEach
Transformation XSLT
transform
Les exemples de cette section utilisent un fichier xml nommé dont le contenu est le suivant :
Fichier utilisé dans les exemples :
Développons en Java
401

<personnes>
  <personne id="1">
    <nom>nom1</nom>
    <prenom>prenom1</prenom>
  </personne>
  <personne id="2">
    <nom>nom2</nom>
    <prenom>prenom2</prenom>
  </personne>
  <personne id="3">
    <nom>nom3</nom>
    <prenom>prenom3</prenom>
  </personne>
</personnes>
L'attribut select des tags de cette bibliothèque utilise la norme Xpath pour sa valeur. JSTL propose une extension
supplémentaire à Xpath pour préciser l'objet sur lequel l'expression doit être évaluée. Il suffit de préfixer le nom de la
variable par un $
Exemple : recherche de la personne dont l'id est 2 dans un objet nommé listepersonnes qui contient l'arborescence du
document xml.
$listepersonnes/personnes/personne[@id=2]
L'implémentation de JSTL fournie avec le JWSDP utilise Jaxen comme moteur d'interprétation XPath. Donc pour utiliser
cette bibliothèque, il faut s'assurer que les fichiers   et jaxen? soient présents dans le répertoire lib du
répertoire WEB?INF de l'application web.
Pour utiliser cette bibliothèque, il faut la déclarer dans le fichier du répertoire WEB?INF de l'application web.
Exemple :
  <taglib>
    <taglib?uri>;/taglib?uri>
    <taglib?location>/WEB?</taglib?location>
  </taglib>
Dans chaque JSP qui utilise un ou plusieurs tags de la bibliothèque, il faut la déclarer avec une directive taglib.
Exemple :
<%@ taglib uri="; prefix="x" %>
29.5.1. Le tag parse
La tag parse permet d'analyser un document et de stocker le résultat dans une variable qui pourra être exploité par la JSP
ou une autre JSP selon la portée sélectionnée pour le stockage.
Attribut
Rôle
Développons en Java
402

xml
contenu du document à analyser
var
nom de la variable qui va contenir l'arbre DOM générer par l'analyse
scope
portée de la variable qui va contenir l'arbre DOM
varDom
scopeDom
filter
System
Exemple : chargement et sauvegarde dans une variable de la JSP
<c:import url="" var="personnes" />
<x:parse xml="${personnes}" var="listepersonnes"  />
Dans cette exemple, il suffit simplement que le fichier soit dans le dossier  racine de l'application web.
29.5.2. Le tag set
Le tag set est équivalent au tag set de la bibliothèque core. Il permet d'évaluer l'expression Xpath fournie dans l'attribut
select et de placer le résultat de cette évaluation dans une variable. L'attribut var permet de préciser la variable qui va
recevoir le résultat de l'évaluation sous la forme d'un noeud de l'arbre du document XML.
Il possède plusieurs attributs :
Attribut
Rôle
select
expression XPath à évaluer
var
nom de la variable qui va stocker le résultat de l'évaluation
scope
portée de la variable qui va stocker le résultat
Exemple : obtenir les informations de la personne dont l'id est 2
<c:import url="" var="personnes" />
<x:parse xml="${personnes}" var="listepersonnes"  />
<x:set var="unepersonne" select="$listepersonnes/personnes/personne[@id=2]" />
<h1>nom = <x:out select="$unepersonne/nom"/></h1>
29.5.3. Le tag out
Le tag out est équivalent au tag out de la bibliothèque core. Il est permet d'évaluer l'expression Xpath fournie dans
l'attribut select et d'envoyer le résultat dans le flux de sortie. L'attribut select permet de préciser l'expression Xpath qui
doit être évaluée.
Il possède plusieurs attributs :
Développons en Java
403

Attribut
Rôle
select
expression XPath à évaluer
escapeXML
Exemple : Afficher le nom de la personne dont l'id est 2
<c:import url="" var="personnes" />
<x:parse xml="${personnes}" var="listepersonnes"  />
<x:set var="unepersonne" select="$listepersonnes/personnes/personne[@id=2]" />
<h1><x:out select="$unepersonne/nom"/></h1>
Pour stocker le résultat de l'évaluation d'une expression dans une variable, il faut utiliser une combinaison du tag x:out et
c:set
Exemple :
<c:set var="personneId">
      <x:out select="$listepersonnes/personnes/personne[@id=2]" />
    </c:set>
29.5.4. Le tag if
Ce tag est équivalent au tag if de la bibliothèque core sauf qu'il évalue une expression XPath
Il possède plusieurs attributs :
Attribut
Rôle
select
expression XPath à évaluer sous la forme d'un booléen
var
nom de la variable qui va stocker le résultat de l'évaluation
scope
portée de la variable qui va stocker le résultat de l'évaluation
29.5.5. Le tag choose
Ce tag est équivalent au tag choose de la bibliothèque core sauf qu'il évalue des expressions XPath
29.5.6. Le tag forEach
Ce tag est équivalent au tag forEach de la bibliothèque Core. Il permet de parcourir les noeuds issus de l'évaluation d'une
expression Xpath.
Il possède plusieurs attributs :
Attribut
Rôle
Développons en Java
404

select
expression XPath à évaluer (obligatoire)
var
nom de la variable qui va contenir le noeud en cours de traitement
Exemple : parcours des personnes et affichage de l'id, du nom et du prénom
<c:import url="" var="personnes" />
<x:parse xml="${personnes}" var="listepersonnes"  />
<x:forEach var="unepersonne" select="$listepersonnes/personnes/*">
    <c:set var="personneId">
      <x:out select="$unepersonne/@id"/>
    </c:set>
    <c:out value="${personneId}" /> ? <x:out select="$unepersonne/nom"/> &nbsp; 
       <x:out select="$unepersonne/prenom"/> <br>
</x:forEach>
29.5.7. Le tag transform
Ce tag permet d'appliquer une transformation XSLT à un document XML. L'attribut xsl permet de préciser la feuille de
style XSL. L'attribut optionnel xml permet de préciser le document xml.
Il possède plusieurs attributs :
Attribut
Rôle
xslt
feuille se style XSLT (obligatoire)
xml
nom de la variable qui contient le document XML à traiter
var
nom de la variable qui va recevoir le résultat de la transformation
scope
portée de la variable qui va recevoir le résultat de la transformation
xmlSystemId
xsltSystemId
result
Exemple :
<x:transform xml='${docXml}' xslt='${feuilleXslt}'/>
Le document xml à traiter peut être fourni dans le corps du tag
Exemple :
<x:transform xslt='${feuilleXslt}'>
  <personnes>
    <personne id="1">
      <nom>nom1</nom>
      <prenom>prenom1</prenom>
    </personne>
    <personne id="2">
      <nom>nom2</nom>
      <prenom>prenom2</prenom>
Développons en Java
405

    </personne>
    <personne id="3">
      <nom>nom3</nom>
      <prenom>prenom3</prenom>
    </personne>
  </personnes>
</x:transform>
Le tag transform peut avoir un ou plusieurs noeuds fils param pour fournir des paramètres à la feuille de style XSLT.
29.6. La bibliothèque I18n
Cette bibliothèque facilite l'internationnalisation d'une page JSP.
Elle propose les tags suivants répartis dans trois catégories :
Catégorie
Tag
Définition de la langue
setLocale
>bundle
Formattage de messages
message
setBundle
formatNumber
parseNumber
formatDate
Formattage de dates et nombres
parseDate
setTimeZone
timeZone
Pour utiliser cette bibliothèque, il faut la déclarer dans le fichier du répertoire WEB?INF de l'applciation web.
Exemple :
  <taglib>
    <taglib?uri>;/taglib?uri>
<taglib?location>/WEB?</taglib?location> 
</taglib>
Dans chaque JSP qui utilise un ou plusieurs tags de la bibliothèque, il faut la déclarer avec une directive taglib
Exemple :
<%@ taglib uri="; prefix="fmt" %>
Le plus simple pour mettre en oeuvre la localisation des messages, c'est de définir un ensemble de fichier qui sont appelé
bundle en anglais.
Il faut définir un fichier pour la langue par défaut et un fichier pour chaque langue particulière. Tous ces fichiers ont un
préfix commun appelé basename et doivent avoir comme extension .properties. Les fichiers pour les langues particulieres
Développons en Java
406

doivent le préfix commun suivit d'un underscore puis du code langue et eventuellement d'un underscore suivi du code
pays. Ces fichiers doivent être inclus dans le classpath : le plus simple est de les copier dans le répertoire
WEB?INF/classes de l'application web.
Exemple :
message.properties
messageen.properties
Dans chaque fichier, les clés sont identiques, seul la valeur associé à la clé change.
Exemple : le fichier message.properties pour le français (langue par défaut)
msg=bonjour
Exemple : le fichier messageen.properties pour l'anglais
msg=Hello
Pour plus d'information, voir le chapitre sur l'internationalisation.
29.6.1. Le tag bundle
Ce tag permet de préciser un bundle à utiliser dans les traitements contenus dans son corps.
Il possède plusieurs attributs :
Attribut
Rôle
baseName
nom de base de ressource à utiliser (obligatoire)
prefix
Exemple :
<fmt:bundle basename="message" > 
  <fmt:message key="msg"/>
</fmt:bundle>
29.6.2. Le tag setBundle
Ce tag permet de forcer le bundle à utiliser par défaut.
Il possède plusieurs attributs :
Attribut
Rôle
Développons en Java
407

baseName
nom de base de ressource à utiliser (obligatoire)
var
nom de la variable qui va stocker le nouveau bundle
scope
portée de la variable qui va recevoir le nouveau bundle
Exemple :
mon message =
<fmt:setBundle basename="message" />
  <fmt:message key="msg"/>
29.6.3. Le tag message
Ce tag permet de localiser un message.
Il possède plusieurs attributs :
Attribut
Rôle
key
clé du message à utiliser
bundle
bundle à utiliser
var
nom de la variable qui va recevoir le résultat du formattage
scope
portée de la variable qui va recevoir le résutlat du formattage
Pour fournir chaque valeur, il faut utiliser un ou plusieurs tags fils param pour fournir la valeur correspondante.
Exemple :
mon message =
<fmt:setBundle basename="message" /> 
  <fmt:message key="msg"/>
Résultat :
mon message = bonjour
Si aucune valeur n'est trouvée pour la clé fournie alors le tag renvoie ???XXX ??? ou XXX représente le nom de la clé.
Exemple :
mon message =
<fmt:setBundle basename="message" /> 
  <fmt:message key="test"/>
Développons en Java
408

Résultat :
mon message = ???test???
29.6.4. Le tag setLocale
Ce tag permet de sélectionner une nouvelle Locale.
Exemple :
<fmt:setLocale value="en"/>
mon message =
<fmt:setBundle basename="message" />
  <fmt:message key="msg"/>
Résultat :
mon message = Hello
29.6.5. Le tag formatNumber
Ce tag permet de formatter des nombres selon la locale. L'attribut value permet de préciser la valeur à formatter.
L'attribut type permet de préciser le type de formattage à réaliser.
Il possède plusieurs attributs :
Attribut
Rôle
value
valeur à formatter
type
CURRENCY ou NUMBER ou PERCENT
pattern
format personnalisé
currencyCode
code de la monnaie à utiliser pour le type CURRENCY
currencySymbol
symbole de la monnaire à utiliser pour le type CURRENCY
groupingUsed
booléen pour préciser si les nombre doivent être groupés
maxIntegerDigits
nombre maximun de chiffre dans la partie entière
minIntegerDigits
nombre minimum de chiffre dans la partie entière
maxFractionDigits
nombre maximun de chiffre dans la partie décimale
minFractionDigits
nombre minimum de chiffre dans la partie décimale
var
nom de la variable qui va stocker le résultat
scope
portée de la variable qui va stocker le résultat
Exemple :
Développons en Java
409

<c:set var="montant" value="12345.67" />
montant = <fmt:formatNumber value="${montant}" type="currency"/>
29.6.6. Le tag parseNumber
Ce tag permet de convertir une chaine de caractère qui contient un nombre en une variable décimale.
Il possède plusieurs attributs :
Attribut
Rôle
value
valeur à traiter
type
CURRENCY ou NUMBER ou PERCENT
parseLocale
Locale à utiliser lors du traitement
integerOnly
booléen qui indique si le résultat doit être un entier (true) ou un flottant (false)
pattern
format personnalisé
var
nom de la variable qui va stocker le résultat
scope
portée de la variable qui va stocker le résultat
Exemple : convertir en entier un identifiant passé en paramètre de la requète
<fmt:parseNumber value="${}" var="id"/>
29.6.7. Le tag formatDate
Ce tag permet de formatter des dates selon la locale.
Il possède plusieurs attributs :
Attribut
Rôle
value
valeur à formatter
type
DATE ou TIME ou BOTH
dateStyle
FULL ou LONG ou MEDIUM ou SHORT ou DEFAULT
timeStyle
FULL ou LONG ou MEDIUM ou SHORT ou DEFAULT
pattern
format personnalisé
timeZone
timeZone utilisé pour le formattage
var
nom de la variable qui va stocker le résultat
scope
portée de la variable qui va stocker le résultat
L'attribut value permet de préciser la valeur à formatter. L'attribut type permet de préciser le type de formattage à
Développons en Java
410

réaliser. L'attribut dateStyle permet de préciser le style du formattage.
Exemple :
<jsp:useBean id="now" class="" />
Nous sommes le <fmt:formatDate value="${now}" type="date" dateStyle="full"/>.
29.6.8. Le tag parseDate
Ce tag permet d'analyser une chaine de caractères contenant une date pour créer un objet de type .
Il possède plusieurs attributs :
Attribut
Rôle
value
valeur à traiter
type
DATE ou TIME ou BOTH
dateStyle
FULL ou LONG ou MEDIUM ou SHORT ou DEFAULT
timeStyle
FULL ou LONG ou MEDIUM ou SHORT ou DEFAULT
pattern
format personnalisé
parseLocale
Locale utilisé pour le formattage
timeZone
timeZone utilisé pour le formattage
var
nom de la variable de type qui va stocker le résultat
scope
portée de la variable qui va stocker le résultat
29.6.9. Le tag setTimeZone
Ce tag permet de stocker un fuseau horraire dans une variable.
Il possède plusieurs attributs :
Attribut
Rôle
value
fuseau horraire à stocker (obligatoire)
var
nom de la variable de stockage
scope
portée de la variable de stockage
29.6.10. Le tag timeZone
Ce tag permet de préciser un fuseau horraire particulier à utiliser dans son corps.
Il possède plusieurs attributs :
Développons en Java
411

Attribut
Rôle
value
chaine de caractère ou objet .TimeZone qui précise le fuseau horraire à utiliser
29.7. La bibliothèque Database
Cette biliothèque facilite l'accès aux bases de données. Son but n'est pas de remplacer les accès réalisés grace à des beans
ou des EJB mais de fournir une solution simple mais non robuste pour accéder à des bases de données. Ceci est
cependant particulièrement utile pour développer des pages de tests ou des prototypes.
Elle propose les tags suivants répartis dans deux catégories :
Catégorie
Tag
Définition de la source de données
setDataSource
query
Execution de requete SQL
transaction
update
Pour utiliser cette bibliothèque, il faut la déclarer dans le fichier du répertoire WEB?INF de l'application web.
Exemple :
  <taglib>
    <taglib?uri>;/taglib?uri>
    <taglib?location>/WEB?</taglib?location> 
</taglib>
Dans chaque JSP qui utilise un ou plusieurs tags de la bibliothèque, il faut la déclarer avec une directive taglib
Exemple :
<%@ taglib uri="; prefix="sql" %>
29.7.1. Le tag setDataSource
Ce tag permet de créer une connection vers la base de données à partir des données fournies dans les différents attributs
du tag.
Il possède plusieurs attributs :
Attribut
Rôle
driver
nom de la classe du pilote JDBC à utiliser
source
url de la base de données à utiliser
user
nom de l'utilisateur à utiliser lors de la connection
Développons en Java
412

password
mot de passe de l'utilisateur à utiliser lors de la connection
var
nom de la variable qui va stocker l'objet créer lors de la connection
scope
portée de la variable qui va stocker l'objet créer
dataSource
Exemple : accéder à une base via ODBC dont le DNS est test
<sql:setDataSource driver=".JdbcOdbcDriver" url="jdbc:odbc:test" user="" password=""/>
29.7.2. Le tag query
Ce tag permet de réaliser des requètes de sélection sur une source de données.
Il possède plusieurs attributs :
Attribut
Rôle
sql
requète SQL à executer
var
nom de la variable qui stocke les résultats de l'exécution dela requète
scope
portée de la variable qui stocke le résultat
startRow
numéro de l'occurrence de départ à traiter
maxRow
nombre maximum d'occurrence à stocker
dataSource
connection particulière à la base de données à utiliser
L'attribut sql permet de préciser la requète à executer :
Exemple :
<sql:query var="reqPersonnes" sql="SELECT * FROM personnes" />
Le résultat de l'éxécution de la requète est stocké dans un objet qui implémente l'interface
.Result dont le nom est donné via l'attribut var
L'interface Result possède cinq getter :
Méthode
Rôle
String[] getColumnNames()
renvoie un tableau de chaines de caractères qui contient le nom des colonnes
int getRowCount()
renvoie le nombre d'enregistrements trouvé lors de l'éxécution de la requète
renvoie une collection qui associe à chaque colonne la valeur associé pour
Map[] getRows()
l'occurrence en cours
Object[][] getRowsByIndex()
renvoie un tableau contenant les colonnes et leur valeur
renvoie un booléen qui indique si le résultat de la requète a été limité
Développons en Java
413

boolean
isLimitedByMaxRows()
Exemple : connaitre le nombre d'occurrence renvoyées par la requète
<p>Nombre d'enregistrement trouvé : <c:out value="${reqPersonnes.rowCount}" /></p>
La requète SQL peut être précisée avec l'attribut sql ou dans le corps du tag
Exemple :
<sql:query var="reqPersonnes" >
  SELECT * FROM personnes
</sql:query>
Le tag forEach de la bibliothèque core est particulièrement utile pour itérer sur chaque occurrence retournée par la
requete SQL.
Exemple :
<TABLE border="1" CELLPadding="4" cellspacing="0">
<TR>
<td>id</td>
<td>nom</td>
<td>prenom</td>
</TR>
<c:forEach var="row" items="${}" >
<TR>
<td><c:out value="${}" /></td>
<td><c:out value="${}" /></td>
<td><c:out value="${row.prenom}" /></td>
</TR>
</c:forEach>
</TABLE>
Il est possible de fournir des valeurs à la requète SQL. Il faut remplacer dans la requète SQL la valeur par le caractère ?.
Pour fournir, la ou les valeurs il faut utiliser un ou plusieurs tags fils param.
Le tag param possède un seul attribut :
Attribut
Rôle
value
valeur de l'occurrence correspondante dans la requete SQL
Pour les valeurs de type date, il faut utiliser le tag dateParam.
Le tag dateParam possède plusieurs attributs :
Attribut
Rôle
value
objet de type qui contient la valeur de la date (obligatoire)
Développons en Java
414

type
format de la date : TIMESTAMP ou DATE ou TIME
Exemple :
<c:set var="id" value="2" />
<sql:query var="reqPersonnes" >
  SELECT * FROM personnes where id = ?
            <sql:param value="${id}" />
</sql:query>
29.7.3. Le tag transaction
Ce tag permet d'encapsuler plusieurs requètes SQL dans une transaction.
Il possède plusieurs attributs :
Attribut
Rôle
dataSource
connection particulière à la base de données à utiliser
isolation
READCOMMITTED ou READUNCOMMITTED ou REPEATABLEREAD ou SERIALIZABLE
29.7.4. Le tag update
Ce tag permet de réaliser une mise à jour grace à une requete SQL sur la source de données.
Il possède plusieurs attributs :
Attribut
Rôle
sql
requète SQL à exécuter
var
nom de la variable qui stocke le nombre d'occurrence impactée par l'exécution dela requète
scope
portée de la variable qui stocke le nombre d'occurrence impactée
dataSource
connection particulière à la base de données à utiliser
Exemple :
<c:set var="id" value="2" />
<c:set var="nouveauNom" value="nom 2 modifié" />
<sql:update var="nbRec">
UPDATE personnes
SET nom = ? 
WHERE id=?
lt;sql:param value="${nouveauNom}"/>
<sql:param value="${id}"/>
</sql:update>
Développons en Java
415

<p>nb enregistrement modifiés = <c:out value="${nbRec}"/></p>
Développons en Java
416

30. Les frameworks pour les applications web
La suite de ce chapitre sera développé dans une version future de ce document
30.1. Présentation et utilité
Un framework est un ensemble de composants qui structure tout ou partie d'une application.
Dès que l'on développe des applications web uniquement avec les API servlet et JSP, il apparait évident que de
nombreuses parties dans des applications différentes sont communes mais doivent être réécrites ou réutilisées à chaque
fois. Ceci est en grande partie liée au fait que les API servlets et JSP sont des API de bas niveau. Elles ne proposent par
exemple rien pour automatiser l'extraction des données de la reqûete HTTP et mapper leur contenu dans un objet, assurer
les transitions entre les pages selon les circonstances, ...
L'intérêt majeur des frameworks est de proposer une structure identique pour toutes les applications web qui l'utilisent et
de fournir des mécanismes plus ou moins sophistiqués pour assurer des tâches communes à toutes les applications web.
Les frameworks sont souvents accompagnés d'outils et de normes à respecter lors du développement.
Leur utilisation apporte plusieurs avantages :
augmenter la productivité une fois le framework pris en main
• 
assurer la réutilisation de composants fiables
• 
faciliter la maintenance
• 
...
• 
Le plus gros défaut des frameworks est lié à leur compléxitité : il faut un certain temps d'apprentissage pour avoir un
minimum de maitrise et d'efficacité dans leur utilisation.
Le choix d'un framework est très important car l'utilisation d'un autre framework impose un travail important :
prise en main du nouveau framework
• 
réécriture partiel de l'application
• 
Il existe de nombreux frameworks open source dont le plus utilisé est Struts. Les frameworks open source ont l'avantage
d'être développés par un grand nombre de personnes, ce qui permet d'avoir des frameworks relativement complet, fiable
et fonctionnel. En plus, comme tout projet open source, les sources sont disponibles ce qui permet éventuellement de
faire des modifications pour répondre à ces propres besoins ou ajouter des fonctionnalités.
Développons en Java
417

Les frameworks utilisent ou peuvent être complétés par des moteurs de templates qui facilitent la génération de page web
à partir de modèles.
30.1.1. Le modèle MVC
Le modele MVC (Model View Controler) a été initalement développé pour le langage Smalltalk dans le but de mieux
structurer une application avec une interface graphique.
Ce modèle sépare en trois parties une application :
la vue : représente l'interface homme?machine
• 
le modèle : représente les données de l'application
• 
le controleur : assure le lien entre les deux autres entités en contennant les règles métiers
• 
30.1.2. Le modèle MVC2
30.2. Struts
Struts est un framework pour applications web dévelopé par le projet Jakarta
de la fondation Apache. C'est la plus populaire des frameworks pour le
développement d'applications web avec java .
Il a été initialement développé par Craig Mc Clanahan qui l'a donné au projet Jakarta d'Apache en mai 2000. Depuis,
Struts a connu un succès grandissant auprès de la communauté du libre et des développeurs à tel point que la plupart des
grands IDE propriétaires (Borland, IBM, BEA, ...) intègre une partie dédié à son utilisation.
Struts met en oeuvre le modèle MVC 2 basé sur une seule servlet et des JSP pour chaque application. L'application de ce
modèle permet une séparation en trois partie distinctes de l'interface, des traitements et des données de l'application.
Strust se concentre sur la vue et le controleur. L'implémentation du modèle est laissée libre aux développeurs : ils ont le
choix d'utiliser des java beans, un outil de mapping objet/relationnel ou des EJB.
Pour le controleur, Struts propose une unique servlet par application qui lit la configuration de l'application dans un
fichier au format XML. Cette servlet reçoit toutes les requètes de l'utilisateur concernant l'application. En fonction du
paramètrage, il instancie un objet de type Action qui contient les traitements et renvoie une valeur particulière à la
servlet. Ceci lui permet de déterminer la JSP qui affichera le résultat à l'utilisateur.
Pour la vue, Struts utilise des JSP avec un ensemble de trois bibliothèques de tags personnalisés pour faciliter leur
développement.
L a   d e r n i è r e   v e r s i o n   a i n s i   q u e   t o u t e s   l e s   i n f o r m a t i o n s   u t i l e s   p e u v e n t   ê t r e   o b t e n u e s   s u r   l e   s i t e

Il existe deux versions de Struts : 1.0 et 1.1.
Développons en Java
418

30.3.1. Installation et mise en oeuvre
Il faut télécharger la dernière version de Struts sur le site du projet Jakarta.
Il suffit de dezipper le fichier dans un répertoire quelconque.
Pour pouvoir utiliser Struts dans une application web, il faut copier les fichiers et commons?*.jar dans le
répertoire WEB?INF/lib de l'application.
Comme Struts met en oeuvre le modèle MVC, il est possible de développer séparement les différents composants de
l'application.
30.3.2. Le développement des vues
Les vues représentent l'interface avec entre l'application et l'utilisateur. Avec le framework Struts, les vues d'une
application web sont des JSP. Pour faciliter leur développement, Struts propose un ensemble de trois bibliothèques de
tags personnalisés possèdant chacun un thème particulier :
HTML
• 
Bean
• 
Logic
• 
30.3.3. Les objets de type ActionForm
Un objet de type ActionForm est un objet qui permet à Struts de mapper automatiquement les données saisies dans une
JSP avec les attributs correspondant dans l'objet.
Pour automatiser cette tache, Struts utilise l'introspection pour rechercher un accesseur correspondant au nom du
paramètres contenant la donnée.
P o u r   c h a q u e   p a g e   c o n t e n a n t   d e s   d o n n é e s   à   u t i l i s e r ,   i l   f a u t   d é f i n i r   u n   o b j e t   q u i   h é r i t e   d e   l a   c l a s s e
org.apache.struts.action.ActionForm.
Pour chaque donnée, il faut définir un attribut privé qui contiendra la valeur, un getter et un setter public en respectant les
normes de développement des java beans.
La méthode reset() doit être redéfinie pour initialiser chaque attribut.
Il faut compiler cette classe est la placer dans le répertoire WEB?INF/classes suivi de l'arborescence correspondant au
package de la classe.
Il faut aussi utiliser pour chaque ActionForm, un tag form?bean dans le fichier struts?. Ce tag possède
plusieurs attributs :
Attribut
Rôle
name
le nom sous lequel Struts va connaître l'objet
type
le type complètement qualité de la classe de type ActionForm
Développons en Java
419

30.3.4. Le développement de la partie contrôleur
Basé sur le modèle MVC 2, la partie controleur de Struts est implémentée en utilisant une seule et unique servlet par
application. Cette servlet doit hériter de la classe org.apache.struts.action.ActionServlet.
Cette servlet possède des traitements génériques qui utilisent les informations contenues dans le fichier struts?
et dans des objets du type org.apache.struts.action.Action
La servlet reçoit les requètes http émises par le client et en fonction de celles ci, elle appelle un objet du type Action qui
lui est associé dans le fichier struts?.
Un objet de type Action contient une partie spécifique de la logique métier de l'application. Cet objet doit étendre la
classe org.apache.struts.action.Action.
La méthode la plus importante de cette classe est la méthode execute(). C'est elle qui doit contenir les traitements qui
seront exécutés.
30.3. Expresso
Expresso est un framework open source développé par JCorporate qui est basé sur Struts, depuis sa version 4.
Une des particularités de ce framework est de proposer un ensemble de fonctionnalités très intéressantes :
outils de mapping objet?relationnel pour la persistence des données
• 
gestion d'un pool de connexions aux bases de données
• 
workflow
• 
identification et authentification pour la sécurité
• 
...
• 
La version 5.0 de ce framework est disponible depuis octobre 2002.
30.4. Barracuda
30.5. Tapestry
Développons en Java
420

30.6. Turbine
30.7. stxx
30.8. WebMacro

30.9. FreeMarker

30.10. Velocity

Développons en Java
421

31. Java et XML
L'utilisation ensemble de Java et XML est facilitée par le fait qu'ils ont plusieurs points communs :
indépendance de toute plateforme
• 
conçu pour être utilisé sur un réseau
• 
prise en charge de la norme Unicode
• 
31.1. Présentation de XML
XML est l'acronyme de «eXtensible Markup Language».
XML permet d'échanger des données entres applications hétérogènes car il permet de modéliser et de stocker des
données de façon portable.
XML est extensible dans la mesure ou il n'utilise pas de tags prédéfinis comme HTML et il permet de définir de
nouvelles balises : c'est un métalangage.
Le format HTML est utilisé pour formater et afficher les données qu'il contient : il est destiné à structurer, formater et
échanger des documents d'une façon la plus standard possible..
XML est utilisé pour modéliser et stocker des données. Il ne permet pas à lui seul d'afficher les données qu'il contient.
Pourtant, XML et HTML sont tous les deux des dérivés d'une langage nommé SGML (Standard Generalized Markup
Language). La création d'XML est liée à la complexité de SGML. D'ailleurs, un fichier XML avec sa DTD
correspondante peut être traité par un processeur SGML.
XML et java ont en commun la portabilité réalisée grâce à une indépendance vis à vis du système et de leur
environnement.
31.2. Les règles pour formater un document XML
Un certain nombre de règles doivent être respectées pour définir un document XML valide et «bien formé». Pour pouvoir
être analysé, un document XML doit avoir une syntaxe correcte. Les principales règles sont :
le document doit contenir au moins une balise
• 
chaque balise d'ouverture (exemple <tag>) doit posséder une balise de fermeture (exemple </tag>). Si le tag est
• 
vide, c'est à dire qu'il ne possède aucune données (exemple <tag></tag>), un tag abrégé peut être utilisé
(exemple correspondant : <tag/>)
les balises ne peuvent pas être intercalées (exemple <liste><element></liste></element> n'est pas autorisé)
• 
toutes les balises du document doivent obligatoirement être contenues entre une balise d'ouverture et de
• 
fermeture unique dans le document nommée élément racine
les valeurs des attributs doivent obligatoirement être encadrées avec des quotes simples ou doubles
• 
les balises sont sensibles à la casse
• 
Les balises peuvent contenir des attributs même les balises vides
• 
Développons en Java
422

les données incluses entre les balises ne doivent pas contenir de caractères < et & : il faut utiliser respectivement
• 
&lt ; et &amp ;
La première ligne du document devrait normalement correspondre à la déclaration de document XML : le
• 
prologue.
31.3. La DTD (Document Type Definition)
Les balises d'un document XML sont libres. Pour pouvoir valider si le document est correct, il faut définir un document
nommé DTD qui est optionnel. Sans sa présence, le document ne peut être validé : on peut simplement vérifier que la
syntaxe du document est correcte.
Une DTD est un document qui contient la grammaire définissant le document XML. Elle précise notamment les balises
autorisées et comment elles s'imbriquent.
La DTD peut être incluse dans l'en tête du document XML ou être mise dans un fichier indépendant. Dans ce cas, la
directive < !DOCTYPE> dans le document XML permet de préciser le fichier qui contient la DTD.
Il est possible d'utiliser une DTD publique ou de définir sa propre DTD si aucune ne correspond à ces besoins.
Pour être valide, un document XML doit avoir une syntaxe correcte et correspondre à la DTD.
31.4. Les parseurs
Il existe plusieurs types de parseur. Les deux plus répandus sont ceux qui utilisent un arbre pour représenter et exploiter
le document et ceux qui utilisent des événements. Le parseur peut en plus permettre de valider le document XML.
Ceux qui utilisent un arbre permettent de le parcourir pour obtenir les données et modifier le document.
Ceux qui utilisent des événements associent à des événements particuliers des méthodes pour traiter le document.
SAX (Simple API for XML)  est une API libre créée par David Megginson qui utilisent les événements pour analyser et
exploiter les documents au format XML.
Les parseurs qui produisent des objets composant une arborescence pour représenter le document XML utilisent le
modèle DOM (Document Object Model) défini par les recommandations du W3C.
Le choix d'utiliser SAX ou DOM doit tenir compte de leurs points forts et de leurs faiblesses :
les avantages
les inconvénients
parcours libre de l'arbre
gourmand en mémoire
DOM
possibilité de modifier la structure et le
doit traiter tout le document avant
contenu de l'arbre
d'exploiter les résultats
peut gourmand en ressources mémoire
traite les données séquentiellement
rapide
SAX
un peu plus difficile à programmer, il est
principes faciles à mettre en oeuvre
souvent nécessaire de sauvegarder des
informations pour les traiter
permet de ne traiter que les données utiles
SAX et DOM ne fournissent que des définitions : ils ne fournissent pas d'implémentation utilisable. L'implémentation est
laissée aux différents éditeurs qui fournissent un parseur compatible avec SAX et/ou DOM.L'avantage d'utiliser l'un deux
est que le code utilisé sera compatible avec les autres : le code nécessaire à l'instanciation du parseur est cependant
Développons en Java
423

spécifique à chaque fournisseur.
I B M   f o u r n i   g r a t u i t e m e n t   u n   p a r s e u r   X M L   :   x m l 4 j .   I l   e s t   t é l é c h a r g e a b l e   à   l ' a d r e s s e   s u i v a n t e   :

Le groupe Apache développe Xerces à partir de xml4j : il est possible de télécharger la dernière version à l'URL

Sun a développé un projet dénommé Project X. Ce projet a été repris par le groupe Apache sous le nom de Crimson.
Ces trois projets apportent pour la plupart les mêmes fonctionnalitées : ils se distinguent sur des points mineurs :
performance, rapidité, facilité d'utilisation etc. ... Ces fonctionnalités évoluent très vite avec les versions de ces parseurs
qui se succèdent très rapidement.
Pour les utiliser, il suffit de dézipper le fichier et d'ajouter les fichiers .jar dans la variable définissant le CLASSPATH.
Il existe plusieurs autres parseurs que l'on peut télécharger sur le web.
31.5. L'utilisation de SAX
SAX est l'acronyme de Simple API for XML. Cette API a été développée par David Megginson.
Ce type de parseur utilise des événements pour piloter le traitement d'un fichier XML. Un objet (nommé handler en
anglais) doit implémenter des méthodes particulières définies dans une interface de l'API pour fournir les traitements à
réaliser : selon les événements, le parseur appelle ces méthodes.
Les dernières informations concernant cette API sont disponible à l'URL :
Les classes de l'API SAX sont regroupées dans le package
31.5.1. L'utilisation de SAX de type 1
SAX type 1 est composé de deux packages :
:
• 
.helpers :
• 
SAX définit plusieurs classes et interfaces :
les interfaces implémentées par le parseur : Parser, AttributeList et Locator
• 
les interfaces implémentées par le handler : DocumentHandler, ErrorHandler, DTDHandler et EntityHandler
• 
les classes de SAX :
• 
des utilitaires rassemblés dans le package .helpers notamment la classe ParserFactory
• 
Les exemples de cette section utilisent la version 2.0.15 du parseur xml4j d'IBM.
Pour parser un document XML avec un parseur XML SAX de type 1, il faut suivrent les étapes suivantes :
créer une classe qui implémente l'interface DocumentHandler ou hérite de la classe .HandlerBase et
• 
qui se charge de répondre aux différents événements émis par le parseur
créer une instance du parseur en utilisant la méthode makeParser() de la classe ParserFactory.
• 
associer le handler au parseur grâce à la méthode setDocumentHandler()
• 
exécuter la méthode parse() du parseur
• 
Exemple : avec XML4J
import .*;
Développons en Java
424

import .helpers.ParserFactory;
import .parsers.*;
import .*;
public class MessageXML {
  static final String DONNEES_XML =
  "<?xml version=\"1.0\"?>\n"
  +"<BIBLIOTHEQUE\n>"
  +" <LIVRE>\n"
  +" <TITRE>titre livre 1</TITRE>\n"
  +" <AUTEUR>auteur 1</AUTEUR>\n"
  +" <EDITEUR>editeur 1</EDITEUR>\n"
  +" </LIVRE>\n"
  +" <LIVRE>\n"
  +" <TITRE>titre livre 2</TITRE>\n"
  +" <AUTEUR>auteur 2</AUTEUR>\n"
  +" <EDITEUR>editeur 2</EDITEUR>\n"
  +" </LIVRE>\n"
  +" <LIVRE>\n"
  +" <TITRE>titre livre 3</TITRE>\n"
  +" <AUTEUR>auteur 3</AUTEUR>\n"
  +" <EDITEUR>editeur 3</EDITEUR>\n"
  +" </LIVRE>\n"
  +"</BIBLIOTHEQUE>\n";
  static final String CLASSE_PARSER = ".parsers.SAXParser";
  /**
   * Lance l'application.
   * @param args un tableau d'arguments de ligne de commande
   */
  public static void main(.String[] args) {
    MessageXML m = new MessageXML();
    m.parse();
    (0);
  }
  public MessageXML() {
    super();
  }
  public void parse() {
    TestXMLHandler handler = new TestXMLHandler();
    .println("Lancement du parseur");
    try {
      Parser parser = ParserFactory.makeParser(CLASSE_PARSER);
      parser.setDocumentHandler(handler);
      parser.setErrorHandler((ErrorHandler) handler);
      parser.parse(new InputSource(new StringReader(DONNEES_XML)));
    } catch (Exception e) {
      .println("Exception capturée : ");