0% ont trouvé ce document utile (0 vote)
192 vues608 pages

Tij 2

Excellent et célèbre cours « Comment penser en Java » 2e édition. Cours très complet avec exercices et nombreux codes source. Descriptions plus approfondies que les descriptions de l'aide du JDK d'Oracle. Cours à télécharger.

Transféré par

MAFWANA
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Thèmes abordés

  • Polymorphisme,
  • ActiveX,
  • Prototypage,
  • Client/Serveur,
  • Constructeurs,
  • Réutilisation de code,
  • Abstraction,
  • Collections,
  • JSP,
  • Interfaces
0% ont trouvé ce document utile (0 vote)
192 vues608 pages

Tij 2

Excellent et célèbre cours « Comment penser en Java » 2e édition. Cours très complet avec exercices et nombreux codes source. Descriptions plus approfondies que les descriptions de l'aide du JDK d'Oracle. Cours à télécharger.

Transféré par

MAFWANA
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Thèmes abordés

  • Polymorphisme,
  • ActiveX,
  • Prototypage,
  • Client/Serveur,
  • Constructeurs,
  • Réutilisation de code,
  • Abstraction,
  • Collections,
  • JSP,
  • Interfaces

Penser en Java

nde
2 édition

Par Bruce Eckel

Date de publication : 1 juin 2012

Dernière mise à jour : 25 avril 2013

Ce livre a été écrit par Bruce Eckel groupe de traduction


télécharger la version française (PDF) | Commander le livre en version anglaise
(amazon) | télécharger la version anglaise
Penser en Java par Bruce Eckel

I - Préface.................................................................................................................................................................. 13
I-A - Préface à la 2e édition................................................................................................................................ 14
I-A-1 - Java 2.................................................................................................................................................. 15
I-B - Le CD-ROM................................................................................................................................................. 16
II - Avant-propos........................................................................................................................................................ 16
II-A - Prérequis..................................................................................................................................................... 17
II-B - Apprendre Java...........................................................................................................................................17
II-C - Buts............................................................................................................................................................. 18
II-D - Documentation en ligne.............................................................................................................................. 18
II-E - Les chapitres...............................................................................................................................................18
II-F - Exercices..................................................................................................................................................... 22
II-G - Le CD-ROM multimédia............................................................................................................................. 22
II-H - Le Code source.......................................................................................................................................... 23
II-H-1 - Typographie et style de code.............................................................................................................24
II-I - Les versions de Java................................................................................................................................... 24
II-J - Seminars and mentoring............................................................................................................................. 24
II-K - Errors...........................................................................................................................................................25
II-L - À propos de la conception de la couverture du livre.................................................................................. 25
II-M - Remerciements...........................................................................................................................................25
II-M-1 - Collaborateurs Internet.......................................................................................................................27
III - Introduction sur les « objets ».............................................................................................................................27
III-A - Les bienfaits de l'abstraction..................................................................................................................... 28
III-B - Un objet dispose d'une interface............................................................................................................... 29
III-C - L'implémentation cachée........................................................................................................................... 30
III-D - Réutilisation de l'implémentation............................................................................................................... 31
III-E - Héritage : réutilisation de l'interface...........................................................................................................32
III-E-1 - Les relations est-un vs est-comme-un.............................................................................................. 34
III-F - Polymorphisme : des objets interchangeables...........................................................................................35
III-F-1 - Classes de base abstraites et interfaces.......................................................................................... 38
III-G - Environnement et durée de vie des objets............................................................................................... 38
III-G-1 - Collections et itérateurs.................................................................................................................... 39
III-G-2 - La hiérarchie de classes unique....................................................................................................... 40
III-G-3 - Bibliothèques de collections et support pour l'utilisation aisée des collections................................. 41
III-G-3-a - Transtypages descendants vs patrons génériques.................................................................. 41
III-G-4 - Le dilemme du nettoyage : qui en est responsable ?.......................................................................41
III-G-4-a - Ramasse-miettes vs efficacité et flexibilité...............................................................................42
III-H - Traitement des exceptions : gérer les erreurs...........................................................................................42
III-I - Multithreading.............................................................................................................................................. 43
III-J - Persistance................................................................................................................................................. 43
III-K - Java et l'Internet.........................................................................................................................................44
III-K-1 - Qu'est-ce que le Web ?.....................................................................................................................44
III-K-1-a - Le concept Client/Serveur........................................................................................................ 44
III-K-1-b - Le Web en tant que serveur géant...........................................................................................45
III-K-2 - La programmation côté client............................................................................................................45
III-K-2-a - Les plug-ins...............................................................................................................................46
III-K-2-b - Les langages de script............................................................................................................. 46
III-K-2-c - Java........................................................................................................................................... 47
III-K-2-d - ActiveX...................................................................................................................................... 47
III-K-2-e - La sécurité................................................................................................................................ 48
III-K-3 - La programmation côté serveur........................................................................................................ 49
III-K-4 - Une scène séparée : les applications............................................................................................... 49
III-L - Analyse et conception................................................................................................................................ 50
III-L-1 - Phase 0 : Faire un plan..................................................................................................................... 51
III-L-1-a - L'exposé de la mission..............................................................................................................51
III-L-2 - Phase 1 : Que construit-on ?.............................................................................................................52
III-L-3 - Phase 2 : Comment allons-nous le construire ?................................................................................54
III-L-3-a - Les cinq étapes de la conception d'un objet.............................................................................55
III-L-3-b - Indications quant au développement des objets.......................................................................55

-2-
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Phase 3 : Construire le cœur du système......................................................................................................56


III-L-5 - Phase 4 : Itérer sur les cas d'utilisation.............................................................................................56
III-L-6 - Phase 5 : Évolution............................................................................................................................57
III-L-7 - Les plans sont payants......................................................................................................................58
III-L-8 - Commencer par écrire les tests........................................................................................................ 58
III-L-9 - Programmation en binôme................................................................................................................ 59
III-M - Les raisons du succès de Java................................................................................................................ 60
III-M-1 - Les systèmes sont plus faciles à exprimer et comprendre.............................................................. 60
III-M-2 - Puissance maximale grâce aux bibliothèques..................................................................................60
III-M-3 - Traitement des erreurs......................................................................................................................60
III-M-4 - Mise en œuvre de gros projets........................................................................................................ 60
III-N - Stratégies de transition.............................................................................................................................. 61
III-N-1 - Règles de base................................................................................................................................. 61
III-N-1-a - Cours.........................................................................................................................................61
III-N-1-b - Projet à faible risque................................................................................................................ 61
III-N-1-c - S'inspirer de bonnes conceptions.............................................................................................61
III-N-1-d - Utiliser les bibliothèques de classes existantes....................................................................... 61
III-N-1-e - Ne pas traduire du code existant en Java............................................................................... 62
III-N-2 - Les obstacles au niveau du management........................................................................................ 62
III-N-2-a - Coûts de mise en œuvre..........................................................................................................62
III-N-2-b - Problèmes de performances.....................................................................................................62
III-N-2-c - Erreurs classiques de conception.............................................................................................63
III-O - Résumé......................................................................................................................................................64
IV - Tout est « objet »................................................................................................................................................ 64
IV-A - Les objets sont manipulés avec des références....................................................................................... 65
IV-B - Vous devez créer tous les objets.............................................................................................................. 65
IV-B-1 - Où réside la mémoire ?.................................................................................................................... 65
IV-B-2 - Cas particulier : les types primitifs.................................................................................................... 66
IV-B-2-a - Nombres de grande précision.................................................................................................. 67
IV-B-3 - Tableaux en Java.............................................................................................................................. 67
IV-C - Vous n'avez jamais besoin de détruire un objet....................................................................................... 68
IV-C-1 - Notion de portée............................................................................................................................... 68
IV-C-2 - Portée des objets..............................................................................................................................69
IV-C-2-a - Valeurs par défaut des membres primitifs............................................................................... 69
IV-D - Créer de nouveaux types de données : class.......................................................................................... 70
IV-E - Méthodes, paramètres et valeurs de retour.............................................................................................. 71
IV-E-1 - La liste de paramètres...................................................................................................................... 72
IV-F - Construction d'un programme Java...........................................................................................................72
IV-F-1 - Visibilité des noms............................................................................................................................ 72
IV-F-2 - Utilisation d'autres composantes.......................................................................................................73
IV-F-3 - Le mot-clef static............................................................................................................................... 74
IV-G - Votre premier programme Java................................................................................................................ 75
IV-G-1 - Compilation et exécution.................................................................................................................. 76
IV-H - Commentaires et documentation intégrée................................................................................................ 76
IV-H-1 - Commentaires de documentation..................................................................................................... 77
IV-H-2 - Syntaxe............................................................................................................................................. 77
IV-H-3 - HTML intégré.................................................................................................................................... 77
IV-H-4 - @see : faire référence aux autres classes....................................................................................... 78
IV-H-5 - Class documentation tags................................................................................................................ 78
IV-H-5-a - @version...................................................................................................................................78
IV-H-5-b - @author.................................................................................................................................... 79
IV-H-5-c - @since...................................................................................................................................... 79
IV-H-6 - Les onglets de documentation de variables..................................................................................... 79
IV-H-7 - Les onglets de documentation de méthodes....................................................................................79
IV-H-7-a - @param.................................................................................................................................... 79
IV-H-7-b - @return.....................................................................................................................................79
IV-H-7-c - @throws....................................................................................................................................79
IV-H-7-d - @deprecated............................................................................................................................ 80

-3-
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

IV-H-8 - Exemple de documentation.............................................................................................................. 80


IV-I - Style de programmation..............................................................................................................................80
IV-J - Exercices.................................................................................................................................................... 81
V - Contrôle du flux du programme.......................................................................................................................... 81
V-A - Utilisation des opérateurs Java.................................................................................................................. 82
V-A-1 - Priorité................................................................................................................................................ 82
V-A-2 - L'affectation........................................................................................................................................ 82
V-A-2-a - L'aliasing pendant l'appel des méthodes.................................................................................. 83
V-A-3 - Les opérateurs mathématiques......................................................................................................... 84
V-A-3-a - Les opérateurs unaires (à un opérande) moins et plus............................................................ 85
V-A-4 - Incrémentation et décrémentation automatique.................................................................................85
V-A-5 - Les opérateurs relationnels................................................................................................................86
V-A-5-a - Tester l'équivalence des objets................................................................................................. 87
V-A-6 - Les opérateurs logiques.....................................................................................................................88
V-A-6-a - « Court-circuit »........................................................................................................................ 89
V-A-7 - Les opérateurs bit à bit......................................................................................................................89
V-A-8 - Les opérateurs de décalage.............................................................................................................. 90
V-A-9 - L'opérateur virgule..............................................................................................................................93
V-A-10 - L'opérateur + pour les String........................................................................................................... 93
V-A-11 - Les pièges classiques dans l'utilisation des opérateurs.................................................................. 94
V-A-12 - Les opérateurs de transtypage........................................................................................................ 94
V-A-12-a - Les littéraux............................................................................................................................. 95
V-A-12-b - La promotion............................................................................................................................96
V-A-13 - Java n'a pas de « sizeof »............................................................................................................... 96
V-A-14 - Retour sur la priorité des opérateurs...............................................................................................96
V-A-15 - Résumé sur les opérateurs..............................................................................................................97
V-B - Le contrôle d'exécution...............................................................................................................................98
V-B-1 - true et false........................................................................................................................................ 98
V-B-2 - if-else.................................................................................................................................................. 98
V-B-2-a - return..........................................................................................................................................99
V-B-3 - Itération...............................................................................................................................................99
V-B-4 - do-while............................................................................................................................................ 100
V-B-5 - for..................................................................................................................................................... 100
V-B-5-a - L'opérateur virgule................................................................................................................... 101
V-B-6 - break et continue............................................................................................................................. 101
V-B-6-a - L'infâme « goto »..................................................................................................................... 102
V-B-7 - switch................................................................................................................................................105
V-B-7-a - Détails de calcul :.................................................................................................................... 107
V-C - Résumé.....................................................................................................................................................108
V-D - Exercices.................................................................................................................................................. 108
VI - Initialisation et nettoyage.................................................................................................................................. 109
VI-A - Garantie d'initialisation grâce au constructeur.........................................................................................109
VI-B - Surcharge de méthodes.......................................................................................................................... 110
VI-B-1 - Différencier les méthodes surchargées.......................................................................................... 112
VI-B-2 - Surcharge avec types de base....................................................................................................... 112
VI-B-3 - Surcharge sur la valeur de retour...................................................................................................115
VI-B-4 - Constructeurs par défaut................................................................................................................ 115
VI-B-5 - Le mot-clef this................................................................................................................................116
VI-B-5-a - Appeler un constructeur depuis un autre constructeur.......................................................... 117
VI-B-5-b - La signification de static......................................................................................................... 118
VI-C - Nettoyage : finalisation et ramasse-miettes............................................................................................ 118
VI-C-1 - À quoi sert finalize( ) ?....................................................................................................................119
VI-C-2 - Le nettoyage est impératif.............................................................................................................. 119
VI-C-3 - La «death condition»...................................................................................................................... 122
VI-C-4 - Comment fonctionne un ramasse-miettes ?................................................................................... 123
VI-D - Initialisation de membre.......................................................................................................................... 125
VI-D-1 - Spécifier une initialisation............................................................................................................... 126
VI-D-2 - Initialisation par constructeur.......................................................................................................... 127

-4-
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

VI-D-2-a - Ordre d'initialisation................................................................................................................ 127


VI-D-2-b - Initialisation de données statiques......................................................................................... 128
VI-D-2-c - Initialisation statique explicite................................................................................................. 130
VI-D-2-d - Initialisation d'instance non statique.......................................................................................131
VI-E - Initialisation des tableaux........................................................................................................................ 131
VI-E-1 - Tableaux multidimensionnels.......................................................................................................... 134
VI-F - Résumé.................................................................................................................................................... 136
VI-G - Exercices................................................................................................................................................. 137
VII - Cacher l'implémentation.................................................................................................................................. 138
VII-A - package : l'unité de bibliothèque............................................................................................................ 139
VII-A-1 - Créer des noms de packages uniques.......................................................................................... 140
VII-A-1-a - Collisions................................................................................................................................142
VII-A-2 - Une bibliothèque d'outils personnalisée.........................................................................................143
VII-A-3 - Avertissement sur les packages.................................................................................................... 145
VII-B - Les spécificateurs d'accès Java............................................................................................................. 145
VII-B-1 - « Friendly ».....................................................................................................................................145
public : accès d'interface...............................................................................................................................146
VII-B-2-a - Le package par défaut.......................................................................................................... 146
VII-B-3 - private : ne pas toucher !............................................................................................................... 147
VII-B-4 - protected : « sorte d'amical »......................................................................................................... 148
VII-C - L'accès aux classes............................................................................................................................... 149
VII-D - Résumé...................................................................................................................................................151
VII-E - Exercices.................................................................................................................................................152
VIII - Réutiliser les classes...................................................................................................................................... 153
VIII-A - Syntaxe de composition........................................................................................................................ 153
VIII-B - La syntaxe de l'héritage........................................................................................................................ 156
VIII-B-1 - Initialiser la classe de base.......................................................................................................... 157
VIII-B-1-a - Constructeurs avec paramètres........................................................................................... 158
VIII-C - Combiner composition et héritage........................................................................................................ 159
VIII-C-1 - Garantir un nettoyage propre....................................................................................................... 160
VIII-C-1-a - L'ordre du ramasse-miettes..................................................................................................162
VIII-C-2 - Cacher les noms...........................................................................................................................162
VIII-D - Choisir la composition à la place de l'héritage..................................................................................... 163
VIII-E - protected................................................................................................................................................ 164
VIII-F - Développement incrémental.................................................................................................................. 164
VIII-G - Transtypage ascendant......................................................................................................................... 165
VIII-G-1 - Pourquoi le transtypage ascendant ? .......................................................................................... 165
VIII-G-1-a - Composition à la place de l'héritage revisité....................................................................... 166
VIII-H - Le mot-clef final..................................................................................................................................... 166
VIII-H-1 - Données final................................................................................................................................ 166
VIII-H-1-a - Finals sans initialisation....................................................................................................... 168
VIII-H-1-b - Arguments final.....................................................................................................................169
VIII-H-2 - Méthodes final...............................................................................................................................169
VIII-H-2-a - final et private.......................................................................................................................169
VIII-H-3 - Classes final..................................................................................................................................171
VIII-H-4 - Attention finale.............................................................................................................................. 171
VIII-I - Initialisation et chargement de classes...................................................................................................171
VIII-I-1 - Initialisation avec héritage.............................................................................................................. 172
VIII-J - Résumé.................................................................................................................................................. 173
VIII-K - Exercices................................................................................................................................................173
IX - Polymorphisme................................................................................................................................................. 174
IX-A - Upcasting................................................................................................................................................. 175
IX-A-1 - Pourquoi utiliser l'upcast ?.............................................................................................................. 175
IX-B - The twist.................................................................................................................................................. 177
IX-B-1 - Liaison de l'appel de méthode........................................................................................................177
IX-B-2 - Produire le bon comportement....................................................................................................... 177
IX-B-3 - Extensibilité..................................................................................................................................... 180
IX-C - Redéfinition et surcharge........................................................................................................................ 182

-5-
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

IX-D - Classes et méthodes abstraites.............................................................................................................. 183


IX-E - Constructeurs et polymorphisme............................................................................................................. 185
IX-E-1 - Ordre d'appel des constructeurs.....................................................................................................185
IX-E-2 - La méthode finalize() et l'héritage...................................................................................................187
IX-E-3 - Comportement des méthodes polymorphes dans les constructeurs.............................................. 189
IX-F - Concevoir avec l'héritage.........................................................................................................................191
IX-F-1 - Héritage pur contre extension.........................................................................................................192
IX-F-2 - Downcasting et identification du type à l'exécution.........................................................................193
IX-G - Résumé................................................................................................................................................... 195
IX-H - Exercices................................................................................................................................................. 195
X - Interfaces et classes internes............................................................................................................................196
X-A - Interfaces.................................................................................................................................................. 196
X-A-1 - « Héritage multiple » en Java.......................................................................................................... 199
X-A-1-a - Combinaison d'interfaces et collisions de noms .....................................................................200
X-A-2 - Étendre une interface avec l'héritage.............................................................................................. 201
X-A-3 - Groupes de constantes....................................................................................................................202
X-A-4 - Initialisation des données membres des interfaces......................................................................... 203
X-A-5 - Interfaces imbriquées....................................................................................................................... 203
X-B - Classes internes....................................................................................................................................... 205
X-B-1 - Classes internes et transtypage ascendant.....................................................................................207
X-B-2 - Classes internes définies dans des méthodes et autres portées.................................................... 208
X-B-3 - Classes internes anonymes.............................................................................................................210
X-B-4 - Lien vers la classe externe..............................................................................................................212
X-B-5 - Classes internes static..................................................................................................................... 213
X-B-6 - Se référer à l'objet de la classe externe..........................................................................................215
X-B-7 - Classe interne à plusieurs niveaux d'imbrication.............................................................................215
X-B-8 - Dériver une classe interne............................................................................................................... 216
X-B-9 - Les classes internes peuvent-elles être redéfinies ?....................................................................... 217
X-B-10 - Identifiants des classes internes.................................................................................................... 218
X-B-11 - Raison d'être des classes internes................................................................................................ 218
X-B-11-a - Fermetures & callbacks......................................................................................................... 220
X-B-12 - Classes internes & structures de contrôle..................................................................................... 221
X-C - Résumé.....................................................................................................................................................226
X-D - Exercices.................................................................................................................................................. 226
XI - Stockage des objets......................................................................................................................................... 227
XI-A - Les tableaux............................................................................................................................................ 228
XI-A-1 - Les tableaux sont des objets.......................................................................................................... 229
XI-A-1-a - Conteneurs de scalaires.........................................................................................................231
XI-A-2 - Renvoyer un tableau.......................................................................................................................231
XI-A-3 - La classe Arrays............................................................................................................................. 232
XI-A-4 - Remplir un tableau..........................................................................................................................239
XI-A-5 - Copier un tableau............................................................................................................................240
XI-A-6 - Comparer des tableaux...................................................................................................................241
XI-A-7 - Comparaison d'éléments de tableau.............................................................................................. 241
XI-A-8 - Trier un tableau...............................................................................................................................243
XI-A-9 - Effectuer une recherche sur un tableau trié................................................................................... 244
XI-A-10 - Résumé sur les tableaux.............................................................................................................. 246
XI-B - Introduction sur les conteneurs.............................................................................................................. 246
XI-B-1 - Imprimer les conteneurs................................................................................................................. 247
XI-B-2 - Remplir les conteneurs................................................................................................................... 248
XI-C - L'inconvénient des conteneurs : le type est inconnu.............................................................................. 252
XI-C-1 - Quelquefois ça marche quand même............................................................................................ 253
XI-C-2 - Créer une ArrayList consciente du type......................................................................................... 254
XI-C-2-a - Types paramétrés...................................................................................................................255
XI-C-2-b - Récursion indésirable............................................................................................................. 255
XI-D - Itérateurs..................................................................................................................................................256
XI-E - Classification des conteneurs..................................................................................................................258
XI-F - Fonctionnalités des Collections............................................................................................................... 260

-6-
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

XI-G - Fonctionnalités des Lists.........................................................................................................................262


XI-G-1 - Réaliser une pile à partir d'une LinkedList..................................................................................... 265
XI-G-2 - Réaliser une file à partir d'une LinkedList...................................................................................... 265
XI-H - Fonctionnalités des Sets......................................................................................................................... 266
XI-H-1 - Sets triés : les SortedSets.............................................................................................................. 268
XI-I - Fonctionnalités des Maps......................................................................................................................... 268
XI-I-1 - Maps triées : les SortedMaps...........................................................................................................271
XI-I-2 - Hachage et codes de hachage........................................................................................................ 271
XI-I-2-a - Comprendre hashCode()......................................................................................................... 273
XI-I-3 - Redéfinir hashCode()........................................................................................................................277
XI-J - Stocker des références............................................................................................................................ 279
XI-J-1 - Le WeakHashMap........................................................................................................................... 280
XI-K - Les itérateurs revisités.............................................................................................................................281
XI-L - Choisir une implémentation..................................................................................................................... 282
XI-L-1 - Choisir entre les Lists......................................................................................................................283
XI-L-2 - Choisir entre les Sets......................................................................................................................285
XI-L-3 - Choisir la bonne Map...................................................................................................................... 286
XI-M - Trier et rechercher dans les Lists........................................................................................................... 288
XI-N - Utilitaires.................................................................................................................................................. 288
XI-N-1 - Rendre une Collection ou une Map non modifiable....................................................................... 289
XI-N-2 - Synchroniser une Collection ou une Map.......................................................................................290
XI-N-2-a - Échec rapide.......................................................................................................................... 290
XI-O - Les conteneurs Java 1.0 / 1.1................................................................................................................ 292
XI-O-1 - Vector & Enumeration.....................................................................................................................293
XI-O-2 - Hashtable........................................................................................................................................ 293
XI-O-3 - Stack............................................................................................................................................... 294
XI-O-4 - BitSet...............................................................................................................................................294
XI-P - Résumé....................................................................................................................................................295
XII - Gestion des erreurs avec les exceptions........................................................................................................ 298
XII-A - Les exceptions de base......................................................................................................................... 299
XII-B - Attraper une exception........................................................................................................................... 300
XII-B-1 - Le bloc try...................................................................................................................................... 300
XII-B-2 - Les gestionnaires d'exceptions...................................................................................................... 300
XII-B-2-a - Terminaison contre Restauration...........................................................................................301
XII-B-3 - Créez vos propres exceptions....................................................................................................... 301
XII-C - Spécifier des exceptions........................................................................................................................ 303
XII-C-1 - Attraper n'importe quelle exception............................................................................................... 304
XII-C-2 - Relancer une exception................................................................................................................. 305
XII-D - Les exceptions Java standard................................................................................................................307
XII-D-1 - Le cas particulier RuntimeException............................................................................................. 308
XII-E - Faire le ménage avec finally.................................................................................................................. 309
XII-E-1 - À quoi sert le finally ?.................................................................................................................... 310
XII-E-2 - Le défaut : l'exception perdue........................................................................................................311
XII-F - Restriction d'exceptions.......................................................................................................................... 312
XII-G - Les constructeurs................................................................................................................................... 314
XII-H - Indication d'exception............................................................................................................................. 316
XII-H-1 - Recommandations pour les exceptions.........................................................................................317
XII-I - Résumé.................................................................................................................................................... 317
XII-J - Exercices................................................................................................................................................. 318
XIII - Le système d'E/S de Java............................................................................................................................. 318
XIII-A - La classe File........................................................................................................................................ 319
XIII-A-1 - Lister un répertoire........................................................................................................................319
XIII-A-1-a - Les classes internes anonymes........................................................................................... 320
XIII-A-2 - Vérification et création de répertoires........................................................................................... 322
XIII-B - Entrée et sortie...................................................................................................................................... 323
XIII-B-1 - Les types d'InputStream............................................................................................................... 323
XIII-B-2 - Les types d'OutputStream.............................................................................................................325
XIII-C - Ajouter des attributs et des interfaces utiles......................................................................................... 326

-7-
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

XIII-C-1 - Lire depuis un InputStream avec FilterInputStream..................................................................... 326


XIII-C-2 - Écrire vers un OutputStream avec FilterOutputStream................................................................ 327
XIII-D - Lecteurs et écrivains [ Loader s & Writers ].......................................................................................... 328
XIII-D-1 - Les sources et les réceptacles de données................................................................................. 329
XIII-D-2 - Modifier le comportement du flux................................................................................................. 329
XIII-D-3 - Les classes inchangées................................................................................................................330
XIII-E - Et bien sûr : l'accès aléatoire aux fichiers (RandomAccessFile)........................................................... 330
XIII-F - L'usage typique des flux d'E/S.............................................................................................................. 331
XIII-F-1 - Flux d'Entrée................................................................................................................................. 333
XIII-F-1-a - 1. Entrée en tampon du fichier [Buffered input file].............................................................. 333
XIII-F-1-b - 2. Entrée depuis la mémoire................................................................................................ 333
XIII-F-1-c - 3. Entrée de mémoire formatée............................................................................................333
XIII-F-2 - Flux de sortie.................................................................................................................................334
XIII-F-2-a - 5. Stocker et récupérer des données................................................................................... 334
XIII-F-2-b - 6. Accès aléatoire en lecture et écriture aux fichiers........................................................... 335
XIII-F-3 - Un bogue ?....................................................................................................................................335
XIII-F-4 - Flux Piped..................................................................................................................................... 336
XIII-G - Standard E/S......................................................................................................................................... 336
XIII-G-1 - Lire depuis une entrée standard.................................................................................................. 336
XIII-G-2 - Modifier System.out en un PrintWriter..........................................................................................337
XIII-G-3 - Réorienter l'E/S standard..............................................................................................................337
XIII-H - Compression..........................................................................................................................................338
XIII-H-1 - Compression simple avec GZIP................................................................................................... 338
XIII-H-2 - ARchives Java (JAR)....................................................................................................................341
XIII-I - La sérialisation objet............................................................................................................................... 342
XIII-I-1 - Trouver la classe............................................................................................................................ 345
XIII-I-2 - Contrôler la sérialisation.................................................................................................................346
XIII-I-2-a - Le mot-clef « transient »........................................................................................................ 348
XIII-I-2-b - Une alternative à Externalizable............................................................................................ 350
XIII-I-2-c - Versioning...............................................................................................................................351
XIII-I-3 - Utiliser la persistance..................................................................................................................... 352
XIII-J - Tokenizer l'entrée................................................................................................................................... 356
XIII-J-1 - StreamTokenizer............................................................................................................................ 357
XIII-J-2 - StringTokenizer.............................................................................................................................. 359
XIII-J-3 - Vérifier le style de capitalisation....................................................................................................360
XIII-K - Résumé..................................................................................................................................................362
XIII-L - Exercices................................................................................................................................................ 363
XIV - Identification dynamique de type................................................................................................................... 364
XIV-A - Le besoin de RTTI................................................................................................................................ 364
XIV-A-1 - L'objet Class................................................................................................................................. 366
XIV-A-1-a - Les littéraux Class................................................................................................................367
XIV-A-2 - Vérifier avant de transtyper.......................................................................................................... 368
XIV-A-2-a - Utiliser les littéraux de classe.............................................................................................. 369
XIV-A-2-b - Un instanceof dynamique.................................................................................................... 371
XIV-A-2-c - instanceof vs. équivalence de classe...................................................................................372
XIV-B - La syntaxe du RTTI.............................................................................................................................. 373
XIV-C - Réflexion : information de classe dynamique ...................................................................................... 374
XIV-C-1 - Un extracteur de méthodes de classe......................................................................................... 375
XIV-D - Résumé................................................................................................................................................. 378
XIV-E - Exercices............................................................................................................................................... 379
XV - Création de fenêtres et d'applets....................................................................................................................380
XV-A - L'applet de base.....................................................................................................................................381
XV-A-1 - Les restrictions des applets...........................................................................................................381
Les avantages d'une applet..........................................................................................................................382
XV-A-3 - Les squelettes d'applications.........................................................................................................382
XV-A-4 - Exécuter des applets dans un navigateur Web.............................................................................384
XV-A-5 - Utilisation de Appletviewer............................................................................................................ 385
XV-A-6 - Tester les applets...........................................................................................................................385

-8-
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

XV-B - Exécuter des applets depuis la ligne de commande............................................................................. 386


XV-B-1 - Un squelette d'affichage................................................................................................................ 387
XV-B-2 - Utilisation de l'Explorateur Windows............................................................................................. 389
XV-C - Création d'un bouton..............................................................................................................................390
XV-D - Capture d'un événement........................................................................................................................390
XV-E - Zones de texte....................................................................................................................................... 392
XV-F - Contrôle de la disposition.......................................................................................................................393
XV-F-1 - BorderLayout..................................................................................................................................393
XV-F-2 - FlowLayout..................................................................................................................................... 394
XV-F-3 - GridLayout......................................................................................................................................395
XV-F-4 - GridBagLayout............................................................................................................................... 395
XV-F-5 - Positionnement absolu...................................................................................................................395
XV-F-6 - BoxLayout...................................................................................................................................... 396
XV-F-7 - La meilleure approche ?................................................................................................................ 398
XV-G - Le modèle d'événements de Swing.......................................................................................................398
XV-G-1 - Événements et types de listeners.................................................................................................399
XV-G-1-a - Utilisation de listener adapters pour simplifier......................................................................402
XV-G-2 - Surveiller plusieurs événements................................................................................................... 403
XV-H - Un catalogue de composants Swing..................................................................................................... 404
XV-H-1 - Boutons..........................................................................................................................................405
XV-H-1-a - Groupes de boutons............................................................................................................. 406
XV-H-2 - Icônes............................................................................................................................................ 407
XV-H-3 - Infobulles [Tooltips]........................................................................................................................ 408
XV-H-4 - Champs de texte [Text Fields].......................................................................................................408
XV-H-5 - Bordures........................................................................................................................................ 410
XV-H-6 - JScrollPanes.................................................................................................................................. 411
XV-H-7 - Un miniéditeur............................................................................................................................... 412
XV-H-8 - Boîtes à cocher [Check boxes]..................................................................................................... 413
XV-H-9 - Boutons radio................................................................................................................................ 414
XV-H-10 - Boîtes combo (listes à ouverture vers le bas) [combo boxes (drop-down lists)]......................... 415
XV-H-11 - Listes [List boxes]........................................................................................................................ 416
XV-H-12 - Panneaux à tabulations [Tabbed panes]..................................................................................... 417
XV-H-13 - Boîtes de messages....................................................................................................................418
XV-H-14 - Menus.......................................................................................................................................... 419
XV-H-15 - Menus pop-up..............................................................................................................................423
XV-H-16 - Dessiner.......................................................................................................................................424
XV-H-17 - Boîtes de dialogue.......................................................................................................................426
XV-H-18 - Dialogues pour les fichiers [File dialogs].....................................................................................429
XV-H-19 - HTML sur des composants Swing.............................................................................................. 430
XV-H-20 - Curseurs [sliders] et barres de progression [progress bars]....................................................... 431
XV-H-21 - Arbres [Trees].............................................................................................................................. 431
XV-H-22 - Tables...........................................................................................................................................433
XV-H-23 - Sélection de l'aspect de l'interface [Look & Feel]....................................................................... 435
XV-H-24 - Le presse-papier [clipboard]........................................................................................................ 436
XV-I - Empaquetage d'une applet dans un fichier JAR..................................................................................... 438
XV-J - Techniques de programmation............................................................................................................... 438
XV-J-1 - Lier des événements dynamiquement........................................................................................... 438
XV-J-2 - Séparation entre la logique applicative [business logic] et la logique de l'interface utilisateur [UI
logic].............................................................................................................................................................. 440
XV-J-3 - Une forme canonique.....................................................................................................................442
XV-J-4 - Qu'est-ce qu'un Bean ?..................................................................................................................443
XV-J-5 - Extraction des informations sur les Beans [BeanInfo] à l'aide de l'introspecteur [Introspector]...... 444
XV-J-6 - Un Bean plus complexe................................................................................................................. 448
XV-J-7 - Empaquetage d'un Bean................................................................................................................450
XV-J-8 - Un support des Beans plus sophistiqué........................................................................................ 451
Davantage sur les Beans............................................................................................................................. 452
XV-K - Résumé.................................................................................................................................................. 452
XV-L - Exercices.................................................................................................................................................453

-9-
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

XVI - Les threads multiples..................................................................................................................................... 454


XVI-A - Interfaces utilisateur dynamiques [Responsive user interfaces]........................................................... 455
XVI-A-1 - Héritage de Thread.......................................................................................................................456
XVI-A-2 - Threading pour une interface réactive..........................................................................................458
XVI-A-3 - Créer plusieurs threads................................................................................................................ 460
XVI-A-4 - Threads démons........................................................................................................................... 463
XVI-B - Partager des ressources limitées..........................................................................................................464
XVI-B-1 - Comment Java partage les ressources........................................................................................467
XVI-B-1-a - Efficacité de la synchronisation............................................................................................470
XVI-B-2 - JavaBeans revisités...................................................................................................................... 471
XVI-C - Blocage [Blocking].................................................................................................................................473
Passer à l'état bloqué................................................................................................................................... 474
XVI-C-1-a - Dormant (Sleeping).............................................................................................................. 475
XVI-C-1-b - Suspension et reprise.......................................................................................................... 476
XVI-C-1-c - Attendre et notifier................................................................................................................477
XVI-C-1-d - Bloqué sur I/O......................................................................................................................478
XVI-C-1-e - Tester....................................................................................................................................479
XVI-C-2 - Interblocage [Deadlock]................................................................................................................ 480
XVI-C-2-a - La dépréciation de stop(), suspend(), resume(), et destroy() en Java 2.............................. 480
XVI-C-3 - Lire et changer les priorités......................................................................................................... 483
XVI-C-4 - Les groupes de threads............................................................................................................... 486
XVI-C-4-a - Contrôler les groupes de threads........................................................................................ 488
XVI-D - Runnable revisité.................................................................................................................................. 491
XVI-D-1 - Trop de threads............................................................................................................................ 493
XVI-E - Résumé................................................................................................................................................. 495
XVI-F - Exercices............................................................................................................................................... 496
XVII - Informatique distribuée.................................................................................................................................. 497
XVII-A - La programmation réseau.................................................................................................................... 498
XVII-A-1 - Identifier une machine................................................................................................................. 498
XVII-A-1-a - Serveurs et clients.............................................................................................................. 499
XVII-A-1-b - Tester les programmes hors réseau................................................................................... 499
XVII-A-1-c - Les Ports : un emplacement unique dans la machine....................................................... 500
XVII-A-2 - Les sockets..................................................................................................................................500
XVII-A-2-a - Un serveur et un client vraiment simples........................................................................... 501
XVII-A-3 - Servir des clients multiples..........................................................................................................505
XVII-A-4 - Les Datagrammes........................................................................................................................508
XVII-A-5 - Utiliser des URL depuis un applet...............................................................................................508
XVII-A-5-a - Lire un fichier depuis un serveur........................................................................................ 509
XVII-A-6 - En savoir plus sur le travail en réseau........................................................................................510
XVII-B - Se connecter aux bases de données : Java Database Connectivity (JDBC)...................................... 510
XVII-B-1 - Faire fonctionner l'exemple..........................................................................................................512
XVII-B-1-a - Étape 1 : Trouver le Driver JDBC....................................................................................... 512
XVII-B-1-b - Étape 2 : Configurer la base de données........................................................................... 513
XVII-B-1-c - Étape 3 : Tester la configuration......................................................................................... 513
XVII-B-1-d - Étape 4 : Générer votre requête SQL.................................................................................514
XVII-B-1-e - Étape 5 : Modifier et insérer votre requête......................................................................... 514
XVII-B-2 - Une version GUI du programme de recherche........................................................................... 515
XVII-B-3 - Pourquoi l'API JDBC paraît si complexe..................................................................................... 516
XVII-B-4 - Un exemple plus sophistiqué...................................................................................................... 517
XVII-C - Les servlets.......................................................................................................................................... 521
XVII-C-1 - Le servlet de base.......................................................................................................................522
XVII-C-2 - Les servlets et le multithreading................................................................................................. 524
XVII-C-3 - Gérer des sessions avec les servlets......................................................................................... 525
XVII-C-3-a - La classe Cookie................................................................................................................ 525
XVII-C-3-b - La classe Session...............................................................................................................526
XVII-C-4 - Faire fonctionner les exemples de servlet.................................................................................. 528
XVII-D - Les Pages Java Serveur - Java Server Pages................................................................................... 528
XVII-D-1 - Les objets implicites.................................................................................................................... 529

- 10 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

XVII-D-2 - Les directives JSP.......................................................................................................................530


XVII-D-3 - Les éléments de scripting JSP....................................................................................................531
XVII-D-4 - Extraire des champs et des valeurs............................................................................................532
XVII-D-5 - Attributs et visibilité d'une page JSP...........................................................................................533
XVII-D-6 - Manipuler les sessions en JSP................................................................................................... 534
XVII-D-7 - Créer et modifier des cookies..................................................................................................... 535
XVII-D-8 - Résumé sur les JSP................................................................................................................... 535
XVII-E - RMI (Remote Method Invocation) : Invocation de méthodes distantes................................................536
XVII-E-1 - Interfaces Remote........................................................................................................................536
XVII-E-2 - Implémenter l'interface distante................................................................................................... 536
Mise en place du registre........................................................................................................................537
XVII-E-3 - Utilisation de l'objet distant.......................................................................................................... 539
XVII-F - Introduction à CORBA..........................................................................................................................540
XVII-F-1 - Principes de base de CORBA..................................................................................................... 540
XVII-F-1-a - CORBA Interface Definition Language (IDL - Langage de Définition d'Interface)............... 541
XVII-F-1-b - Le service de nommage (naming service).......................................................................... 541
XVII-F-2 - Un exemple..................................................................................................................................541
XVII-F-2-a - Écrire le source IDL............................................................................................................ 542
XVII-F-2-b - Création des stubs et des skeletons...................................................................................542
XVII-F-2-c - Implémentation du serveur et du client............................................................................... 542
XVII-F-2-d - Quelques services CORBA................................................................................................. 543
XVII-F-2-e - Activation du processus du service de nommage...............................................................544
XVII-F-2-f - Activation du serveur et du client.........................................................................................544
XVII-F-3 - Les applets Java et CORBA........................................................................................................545
XVII-F-4 - CORBA face à RMI..................................................................................................................... 545
XVII-G - Enterprise Java Beans.........................................................................................................................545
XVII-G-1 - JavaBeans contre EJB................................................................................................................546
XVII-G-2 - Que définit la spécification des EJB ?........................................................................................ 547
XVII-G-2-a - Les rôles............................................................................................................................. 547
XVII-G-2-b - Composants EJB................................................................................................................ 548
XVII-G-2-b-i - Conteneur d'EJB......................................................................................................... 548
XVII-G-2-b-ii - Serveur EJB................................................................................................................548
XVII-G-2-b-iii - Java Naming and Directory Interface (JNDI).............................................................548
XVII-G-2-b-iv - Java Transaction API / Java Transaction Service (JTA/JTS).................................... 548
XVII-G-2-b-v - CORBA et RMI/IIOP...................................................................................................548
XVII-G-3 - Qu'est-ce qui compose un composant EJB ?............................................................................. 549
XVII-G-3-a - Enterprise Bean.................................................................................................................. 549
XVII-G-3-b - Interface Home................................................................................................................... 549
XVII-G-3-c - Interface Remote.................................................................................................................549
XVII-G-3-d - Descripteur de déploiement................................................................................................549
Fichier EJB-Jar........................................................................................................................................ 549
XVII-G-4 - Comment travaille un EJB ?....................................................................................................... 549
XVII-G-5 - Types d'EJB.................................................................................................................................550
XVII-G-5-a - Session Beans.................................................................................................................... 550
XVII-G-5-a-i - Les Session Beans non persistants............................................................................550
XVII-G-5-a-ii - Les Session Beans persistants.................................................................................. 550
XVII-G-5-b - Entity Beans........................................................................................................................550
XVII-G-5-b-i - Gestion de la persistance par le Bean (BMP - Bean Managed Persistence).............. 551
XVII-G-6 - Développer un Enterprise Java Bean......................................................................................... 551
XVII-G-7 - En résumé................................................................................................................................... 554
XVII-H - Jini : services distribués....................................................................................................................... 554
XVII-H-1 - Contexte de Jini...........................................................................................................................554
XVII-H-2 - Qu'est-ce que Jini ?.....................................................................................................................555
XVII-H-3 - Comment fonctionne Jini............................................................................................................. 555
XVII-H-4 - Le processus de découverte....................................................................................................... 556
XVII-H-5 - Le processus de recherche.........................................................................................................556
XVII-H-6 - Séparation de l'interface et de l'implémentation..........................................................................557
XVII-H-7 - Abstraction des systèmes distribués........................................................................................... 557

- 11 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

XVII-I - Résumé..................................................................................................................................................558
XVII-J - Exercices...............................................................................................................................................558
XVIII - Passage et retour d'objets........................................................................................................................... 559
XVIII-A - Passage de références....................................................................................................................... 559
XVIII-A-1 - Aliasing........................................................................................................................................560
XVIII-B - Création de copies locales..................................................................................................................561
XVIII-B-1 - Passage par valeur.....................................................................................................................561
XVIII-B-2 - Clonage d'objets......................................................................................................................... 562
XVIII-B-3 - Rendre une classe cloneable..................................................................................................... 563
XVIII-B-3-a - Utilisation d'une astuce avec protected............................................................................. 563
XVIII-B-3-b - Implémenter l'interface Cloneable......................................................................................564
XVIII-B-4 - Le mécanisme de Object.clone( )...............................................................................................566
XVIII-B-5 - Cloner un objet composé........................................................................................................... 567
XVIII-B-6 - Copie profonde d'une ArrayList.................................................................................................. 568
XVIII-B-7 - Supporter le clonage plus bas dans la hiérarchie...................................................................... 571
XVIII-B-8 - Pourquoi cet étrange design ?................................................................................................... 572
XVIII-C - Contrôler la clonabilité........................................................................................................................ 572
XVIII-C-1 - Le constructeur de copie............................................................................................................575
XVIII-C-1-a - Pourquoi cela fonctionne-t-il en C++ et pas en Java ?......................................................578
XVIII-D - Classes en lecture seule.....................................................................................................................578
XVIII-D-1 - Créer des classes en lecture seule............................................................................................579
XVIII-D-2 - L'inconvénient de l'immuabilité................................................................................................... 580
XVIII-E - Chaînes immuables.............................................................................................................................581
XVIII-F - Constantes implicites...........................................................................................................................582
XVIII-G - Surcharge de l'opérateur « + » et les StringBuffer............................................................................. 582
XVIII-H - Les classes String et StringBuffer...................................................................................................... 583
XVIII-I - Les String sont spéciales..................................................................................................................... 586
XVIII-J - Résumé................................................................................................................................................ 586
XVIII-K - Exercices............................................................................................................................................. 587
XIX - L'Interface Java Natif (JNI)............................................................................................................................ 587
XIX-A - Appeler une méthode native................................................................................................................. 588
XIX-A-1 - Le générateur d'entête [ header file generator] : javah...................................................... 588
XIX-A-2 - Les conventions de nommage [name mangling] et les signatures de fonctions...........................589
XIX-A-3 - Implémenter votre DLL................................................................................................................. 589
XIX-B - Accéder à des fonctions JNI : l'argument JNIEnv.................................................................................590
XIX-C - Accéder à des chaînes Java................................................................................................................ 591
XIX-D - Passer et utiliser des objets Java.........................................................................................................591
XIX-E - JNI et les exceptions Java....................................................................................................................592
XIX-F - JNI et le threading.................................................................................................................................593
XIX-G - Utiliser une base de code préexistantes.............................................................................................. 593
XIX-H - Information complémentaire..................................................................................................................593
XX - Conseils pour une programmation stylée en java.......................................................................................... 593
XX-A - Conception..............................................................................................................................................594
XXI - Ressources.....................................................................................................................................................599
XXI-A - Logicielles.............................................................................................................................................. 599
XXI-B - Livres..................................................................................................................................................... 600
XXI-B-1 - Analyse et conception.................................................................................................................. 600
XXI-B-2 - Python........................................................................................................................................... 602
XXI-B-3 - La liste de mes livres................................................................................................................... 602

- 12 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

I - Préface

J'ai suggéré à mon frère Todd, qui est en train de migrer du hardware vers le software, que la prochaine grande
révolution serait l'ingénierie génétique.

Nous créerons bientôt des organismes dédiés à la fabrication de nourriture, de carburant, de plastique ; ils digéreront
la pollution et, de manière générale, nous permettront de maîtriser la manipulation du monde réel, ceci pour un coût
minime comparé à celui d'aujourd'hui. J'ai prétendu que la révolution informatique serait vraiment peu de chose au
regard de cela.

Puis j'ai réalisé que j'étais en train de commettre une erreur triviale chez les auteurs de science-fiction : oublier le
propos de la technologie (ce qui est évidemment très facile à faire en science-fiction). Un écrivain expérimenté sait
qu'on ne raconte jamais une histoire à propos de choses, mais de gens. La génétique aura un très grand impact
sur nos vies, mais je ne suis pas persuadé qu'elle éclipsera la révolution informatique (qui d'ailleurs rend possible
la révolution génétique) - ou au moins la révolution de l'information. L'information, c'est essentiellement se parler
les uns les autres : bien entendu, les voitures, les chaussures, et surtout les maladies génétiques sont importantes,
mais en définitive ce ne sont que des faux-semblants. La vraie question est notre relation au monde. Ainsi en est-
il de la communication.

Ce livre est un cas. Une majorité d'amis pensa que j'étais soit vraiment hardi soit légèrement dérangé pour mettre
tout cela sur le Web. « Pourquoi quelqu'un voudrait-il l'acheter ? » me disaient-ils. Si j'avais eu un tempérament plus
conservateur, je ne m'y serais pas pris de cette manière ; en réalité je ne voulais pas écrire un livre supplémentaire
de style traditionnel sur les ordinateurs. Je ne savais ce qui en aurait résulté si je n'avais pas agi ainsi, mais en tout
cas ce fut la meilleure chose que j'ai jamais réalisée avec un livre.

Tout d'abord, chacun commença à m'envoyer des correctifs. Ce fut un processus très amusant, parce que mes amis
avaient fureté dans chaque coin et recoin et repéré les erreurs techniques aussi bien que grammaticales, ce qui
me permit d'éliminer les fautes de toutes sortes que j'aurais laissé passer sans cela. Dans ce travail, ils ont été tout
simplement formidables, commençant très souvent par me dire « bon, je ne dis pas ça pour critiquer... » pour me
mettre ensuite sous le nez un ensemble d'erreurs que je n'aurais jamais été capable de trouver par moi-même. Je
crois que ce fut une espèce de travail de groupe, et cela a réellement ajouté quelque chose de spécial à ce livre.

Mais ensuite, j'ai commencé à entendre ceci : « OK, très bien, c'est bien gentil vous avez fait une version électronique,
mais moi j'aurais préféré une version complète imprimée chez un vrai éditeur ». Alors j'ai beaucoup travaillé afin que
chacun puisse l'imprimer dans un format adéquat, mais cela n'a pas suffi à résorber la demande d'un livre « publié ».
La plupart des gens n'ont pas envie de lire le livre à l'écran dans son intégralité, et l'idée de transporter un paquet
de feuilles volantes, même impeccablement imprimées, ne leur conviendrait pas davantage (de plus, je pense que
ce n'est pas forcément économique en terme de toner). Après tout il semblerait que la révolution informatique ne
risque pas de mettre les éditeurs au chômage. Un étudiant suggéra toutefois que cela pourrait servir de modèle pour
l'édition du futur : les livres seraient d'abord publiés sur le Web, et, à condition qu'ils rencontrent un certain intérêt,
on les coucherait sur papier. Actuellement, une grande majorité de livres représentent des désastres financiers, et
cette nouvelle approche pourrait peut-être rendre l'industrie de l'édition plus rentable.

Ce livre a été par ailleurs une expérience enrichissante pour moi. Ma première approche de Java fut « juste un
nouveau langage de programmation », ce qu'il est de fait par ailleurs. Mais, le temps passant, et au fur et à mesure
que je l'étudiais plus en profondeur, je commençais à m'apercevoir que son propos fondamental était différent de
celui de tous les langages que j'avais connus auparavant.

Programmer, c'est gérer la complexité : complexité du problème que l'on veut résoudre, superposée à la complexité
de la machine sur laquelle il va être résolu. Bien des projets de programmation ont avorté à cause de cette complexité.
Je voudrais maintenant dire que, de tous les langages de programmation que je connaisse, aucun n'a été conçu
pour gérer la complexité du développement et de la maintenance de programmes (1) . Bien entendu, dans la
conception des langages, beaucoup de décisions ont été prises en gardant la complexité présente à l'esprit, mais,
dans chaque exemple et à partir d'un certain moment, d'autres problèmes ont surgi qui furent considérés comme
essentiels et par suite intégrés à la mixture. Fatalement, ces nouveaux problèmes furent de ceux qui envoyèrent
finalement les programmeurs « droit dans le mur » avec ce langage. Par exemple, C++ se devait de posséder une

- 13 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

compatibilité ascendante avec C (afin de favoriser la migration des programmeurs C), ainsi qu'une certaine efficacité.
Ces deux buts étaient très utiles et ont grandement participé au succès de C++, mais dans le même temps ils ont
généré une complexité supplémentaire qui a eu pour résultat d'empêcher certains projets d'arriver à terme (bien
entendu, vous pouvez toujours vous en prendre à la responsabilité des programmeurs et/ou de leur encadrement,
mais, si un langage pouvait vous aider à repérer vos erreurs, pourquoi ne le ferait-il pas ?). Autre exemple, Visual
Basic (VB) était lié à BASIC, lequel n'était pas vraiment conçu comme un langage extensible, et par suite toutes
les extensions superposées à VB se sont traduites par une syntaxe vraiment horrible et impossible à maintenir. Perl
a une compatibilité ascendante avec Awk, Sed, Grep ainsi que d'autres outils Unix qu'il était censé remplacer, le
résultat est qu'il est souvent accusé de produire du « code-à-écrire-seulement » (c'est-à-dire qu'on est incapable de
se relire quelques mois plus tard). D'un autre côté, C++, VB, Perl, et d'autres langages comme Smalltalk, de par
leur conception, ont abordé le problème de la complexité, et par là se révèlent remarquablement efficaces dans la
résolution de certains types de problèmes.

Ce qui m'a le plus frappé alors que je commençais à comprendre Java est quelque chose qui s'apparente à l'incroyable
finalité de diminuer la complexité pour le programmeur. Un peu comme si l'on disait « rien n'est important, mis à part
réduire le temps et la difficulté pour produire un code robuste ». Dans les premières versions de Java, cette finalité
s'est traduite par un code qui ne tournait pas très vite (bien que l'on ait fait de nombreuses promesses concernant la
vitesse de Java) mais il n'empêche que cela a réduit le temps de développement de manière stupéfiante : la moitié,
ou moins, du temps nécessaire à la création d'un programme équivalent en C++. Ce seul résultat pourrait déjà se
traduire par une incroyable économie de temps et d'argent, mais Java ne s'arrête pas là. Il s'attache à encapsuler
toutes les tâches complexes qui ont pris de l'importance, comme le multithreading et la programmation réseau, au
moyen de fonctionnalités du langage ou de bibliothèques rendant parfois ces tâches triviales. Et pour finir, il traite
quelques problèmes d'une réelle complexité : programmes multiplateformes, changements dynamiques de code,
sans oublier la sécurité, chacun d'entre eux pouvant s'adapter à votre gamme de difficultés, depuis un « obstacle »
jusqu'à un « point bloquant ». Ainsi, malgré les problèmes de performance que nous avons vus, les promesses de
Java sont énormes : il est capable de faire de nous des programmeurs encore plus productifs.

Le Web est l'un des lieux où cela se révèle le plus. La programmation réseau a toujours été difficile, et Java la rend
facile (et les concepteurs du langage Java travaillent à la rendre encore plus facile). La programmation réseau, c'est
ce qui fait que nous parlons entre nous de manière plus pertinente et meilleur marché que nous ne l'avons jamais
fait avec le téléphone (l'e-mail à lui seul a révolutionné bien des entreprises). Alors que nous nous parlons de plus
en plus, des choses sensationnelles commencent à émerger, peut-être plus incroyables que celles promises par
l'ingénierie génétique.

Dans tous les cas - en créant des programmes, en travaillant en groupe pour créer des programmes, en concevant des
interfaces utilisateur permettant aux programmes de dialoguer avec l'utilisateur, en faisant tourner des programmes
sur différents types de machine, en écrivant facilement des programmes qui communiquent au travers de l'Internet
- Java accroît la bande passante de la communication entre les gens. Je pense que le but de la révolution de la
communication n'est certainement pas de transmettre de grandes quantités de bits ; la vraie révolution sera là lorsque
nous serons tous capables de nous parler plus facilement : de personne à personne, mais aussi en groupe, et,
pourquoi pas, sur la planète entière. J'ai entendu dire que la prochaine révolution verra l'émergence d'une espèce
d'esprit global associant un grand nombre de personnes à un grand nombre d'interconnexions. Il se peut que Java
soit, ou pas, l'outil de cette révolution, mais en tout cas cette possibilité m'a fait comprendre qu'il n'était pas insensé
de tenter d'enseigner ce langage.

I-A - Préface à la 2e édition

Les lecteurs de la première édition de ce livre ont fait énormément de commentaires élogieux à son propos, ce qui
m'a été très agréable. Toutefois de temps à autre l'un ou l'autre s'est plaint, et l'une des critiques récurrentes est « le
livre est trop gros ». Dans mon esprit, je dois dire que si « trop de pages » est votre seule plainte, c'est une faible
critique (on se souvient de l'empereur d'Autriche se plaignant du travail de Mozart : « trop de notes ! », mais n'allez
pas penser que je cherche d'une manière ou d'une autre à me comparer à Mozart). De plus, je peux seulement
supposer qu'une telle demande provient d'une personne qui en est encore à prendre conscience de l'étendue du
langage Java lui-même, et qui n'a pas encore vu ou lu les autres livres traitant du sujet - par exemple, ma référence
favorite, Core Java de Cay Horstmann & Gary Cornell (Prentice-Hall), qui a tellement grossi qu'on a dû le scinder
en deux volumes. Malgré cela, une des choses que j'ai essayé de faire dans cette édition a été d'éliminer les parties

- 14 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

obsolètes, ou tout au moins non essentielles. Je n'ai pas eu de scrupules en faisant cela, car l'original existe toujours
sur le site Web ainsi que sur le CD-ROM qui accompagne ce livre, sous la forme de la première édition du livre,
librement téléchargeable (http://www.BruceEckel.com). Si c'est l'ancienne version qui vous intéresse, elle existe
encore, et ceci est un merveilleux soulagement pour un auteur. Par exemple, vous pouvez remarquer que le dernier
chapitre de l'édition originale, « Projects », a disparu ; deux des projets ont intégré d'autres chapitres, et le reste
n'avait plus d'intérêt. Pareillement, le chapitre « Design Patterns », devenu trop gros, a fait l'objet d'un livre séparé
(également téléchargeable sur le site Web). Ainsi, logiquement, le livre devrait être plus mince.

Mais, hélas, il n'en sera pas ainsi.

Le plus gros problème est le continuel développement du langage Java lui-même, et en particulier l'extension de l'API
qui nous promet de nous procurer une interface standard pour tout ce que nous pourrions imaginer (et je ne serais
pas surpris de voir paraître une API « JCafetiere » pour couronner le tout). Le propos de ce livre n'est certainement
pas de parler de ces API, d'autres auteurs se chargeront de cette tâche, mais certaines questions ne peuvent être
ignorées. Parmi les plus importantes, Java « côté serveur » (principalement les Servlets et les Java Server Pages,
ou JSP), qui représente réellement une excellente solution au problème du World Wide Web, pour lequel nous
avons découvert que les divers navigateurs Web ne sont pas suffisamment consistants pour traiter la programmation
côté client. En outre, un problème reste entier, celui de créer facilement des applications qui se connectent à des
bases de données, qui supervisent des transactions, qui gèrent la sécurité, etc., ce que traitent les Enterprise Java
Beans (EJB). Ces sujets se retrouvent dans le chapitre anciennement nommé « Programmation Réseau », appelé
maintenant « Informatique Distribuée », un sujet qui est en passe de devenir essentiel. Ce chapitre a également
grossi afin d'inclure une vue d'ensemble de Jini (prononcez « djini », ce n'est pas un acronyme, mais un nom),
qui est une technologie de pointe permettant de concevoir différemment les interconnexions entre applications. Et,
bien entendu, le livre a évolué pour utiliser tout au long des exemples la bibliothèque de composants graphiques
Swing (GUI, Graphics User Interface, Interface Graphique Utilisateur, NdT). Ici aussi, si vous vous intéressez aux
anciennes versions Java 1.0/1.1, vous les trouverez dans le livre que vous pouvez télécharger gratuitement à http://
www.BruceEckel.com (et qui est également inclus dans le CD-ROM fourni avec cette nouvelle édition ; vous en
saurez davantage à ce sujet un peu plus tard).

Outre les quelques nouvelles fonctionnalités du langage Java 2 et les corrections effectuées dans tout le livre, un autre
changement majeur est le chapitre sur les collections (titre XI), qui met maintenant l'accent sur les collections Java 2
utilisées tout au long du livre. J'ai également amélioré ce chapitre pour traiter plus en profondeur certaines facettes
des collections, entre autres expliquer comment fonctionne une fonction de hashing (afin que vous sachiez comment
en créer une convenablement). Il y a eu d'autres changements, tels que la réécriture du titre III, la suppression de
quelques appendices ainsi que d'autres parties qui ne me paraissent plus indispensables pour le livre imprimé, mais
ce fut le plus gros des suppressions. D'une manière générale, j'ai essayé de tout revoir, d'enlever de cette 2e édition
tout ce qui n'était plus indispensable (mais que l'on peut trouver sous la forme électronique de la première édition),
de traiter les modifications, et d'améliorer tout ce qui pouvait l'être. Comme le langage continue d'évoluer - mais
toutefois pas à la même allure vertigineuse qu'auparavant - il ne fait pas de doute que de nouvelles éditions de ce
livre verront le jour.

Je dois m'excuser auprès de ceux qui persistent dans leur critique à propos de la taille du livre. Que vous me
croyiez ou non, j'ai travaillé dur pour le rendre plus mince. Malgré sa taille, je pense qu'il existe assez d'alternatives
pour vous satisfaire. D'une part, le livre existe sous forme électronique (sur le site Web, ainsi que sur le CD-ROM
accompagnant ce livre), ainsi lorsque vous prenez votre ordinateur portable vous pouvez également emporter le
livre sans supplément de poids. Si vous êtes réellement partisan de la minceur, il existe des versions Palm Pilot
(quelqu'un m'a dit qu'il lirait le livre au lit sur l'écran rétroéclairé de son Palm afin de ne pas déranger sa femme. Je
ne peux qu'espérer que cela l'aidera à glisser dans les bras de Morphée). Si vous le préférez sur papier, je connais
des personnes qui impriment un chapitre à la fois et l'emmènent dans leur attaché-case afin de le lire dans le train.

I-A-1 - Java 2

Alors que j'écris ceci, la sortie de la version 1.3 du Java Development Kit (JDK) de Sun est imminente, et les
modifications proposées pour le JDK 1.4 ont été publiées. Bien que ces numéros de version soient encore dans les
« uns », la manière standard de se référer à une version du JDK 1.2 ou supérieure est de l'appeler « Java 2 ». Ceci
souligne les modifications significatives entre le « vieux Java » - qui possède beaucoup de verrues, ce que je critiquais

- 15 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

dans la première version de ce livre - et la nouvelle version du langage, améliorée et plus moderne, comportant bien
moins de verrues et beaucoup de compléments, ainsi qu'une conception agréable.

Ce livre est écrit pour Java 2. J'ai la grande chance de dominer l'ancien langage et de n'écrire que pour le nouveau
langage amélioré, parce que l'ancienne information existe encore dans la 1re édition sur le Web et sur le CD-ROM
(ce qui représente votre source d'information si vous utilisez une version antérieure à Java 2). D'autre part, et parce
que n'importe qui peut librement télécharger le JDK depuis java.sun.com, cela signifie qu'en écrivant sur Java 2 je
n'oblige personne à une contrainte budgétaire élevée en lui imposant une mise à jour.

Il y a toutefois une nuance. JDK 1.3 possède quelques améliorations que j'aimerais réellement utiliser, mais la version
de Java actuellement fournie pour Linux est le JDK 1.2.2. Le système Linux (voir http://www.Linux.org) est
un développement très important en conjonction avec Java, parce qu'il est en train de devenir rapidement la plus
importante plate-forme serveur - rapide, fiable, robuste, sécurisée, bien maintenue, et gratuite, une vraie révolution
dans l'histoire de l'informatique (je ne me souviens pas avoir jamais rencontré l'ensemble de ces fonctionnalités dans
aucun outil auparavant). Et Java a trouvé une très importante niche dans la programmation côté serveur sous la
forme des Servlets, une technologie qui est une énorme amélioration de la programmation CGI traditionnelle (ceci
est décrit dans le chapitre « Informatique Distribuée »).

Aussi, malgré le fait que j'aimerais n'utiliser que les toutes nouvelles fonctionnalités de Java, il est essentiel que
l'ensemble puisse être compilé sous Linux, et donc que lorsque vous installerez le code source et que vous le
compilerez sous cet OS (avec le dernier JDK) vous puissiez constater que l'ensemble peut être compilé. Toutefois,
vous verrez que le texte est parsemé çà et là de notes à propos des fonctionnalités du JDK 1.3.

I-B - Le CD-ROM

Un autre bonus de cette édition est le CD-ROM que vous trouverez à la fin du livre. J'ai naguère rejeté cette idée,
pensant que mettre quelques Ko de code source sur cet énorme CD n'était pas justifié, et préféré à cela que les gens le
téléchargent depuis mon site Web. Cependant, vous allez voir tout de suite que ce CD-ROM représente autre chose.

Le CD contient le code source que l'on trouve dans le livre, mais il contient aussi l'intégralité du livre, sous différents
formats électroniques. Mon préféré est le format HTML, parce qu'il est rapide et complètement indexé - vous cliquez
simplement sur une entrée de l'index ou de la table des matières et vous vous retrouvez immédiatement à l'endroit
voulu dans le livre.

Toutefois la plus grande partie des 300 Mo du CD consiste en un ensemble multimédia complet nommé Thinking in
C : Foundations for C++ & Java. À l'origine, j'avais délégué à Chuck Allison la création de ce « séminaire sur CD-
ROM » en tant que produit à part entière, puis j'ai décidé de l'inclure dans les secondes éditions de Thinking in C++
et de Thinking in Java après avoir vécu, lors d'un séminaire, l'arrivée de personnes dépourvues de connaissances
suffisantes en langage C. Leur propos était apparemment « je suis un bon programmeur et je n'ai pas envie
d'apprendre le C, mais plutôt C++ ou Java, c'est pourquoi je compte passer rapidement sur C pour aller directement
à C++/Java ». Peu après leur arrivée au séminaire, ils prennent conscience que le prérequis de la connaissance de
la syntaxe du C se trouve là pour d'excellentes raisons. En incluant le CD-ROM dans le livre, nous nous assurons
que chaque participant à un séminaire a une préparation suffisante.

Le CD permet également d'élargir l'audience du livre. Même si le chapitre « Contrôle du flux de programme » traite
de parties fondamentales de Java provenant du langage C, le CD est une introduction en douceur, et à l'inverse du
livre suppose de la part de l'étudiant une moindre connaissance de la programmation. Le CD étant inclus dans le
livre, j'espère que davantage de personnes intégreront le cercle de la programmation Java.

II - Avant-propos

Tout comme n'importe quel langage humain, Java permet d'exprimer des concepts. S'il y parvient, il deviendra un
moyen d'expression considérablement plus simple et plus souple que n'importe quelle alternative, alors même que
les problèmes augmentent en taille et en complexité.

- 16 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Il est impossible de considérer Java uniquement sous l'angle d'une collection de fonctionnalités - beaucoup de
fonctionnalités perdent leur sens hors de leur contexte. On ne peut utiliser la somme des parties que si l'on pense
en termes de conception, et non simplement en termes de code. Pour appréhender Java de cette manière, il faut
comprendre les problèmes qui lui sont propres et ceux qui relèvent de la programmation en général. Ce livre traite
de problèmes de programmation, en quoi ce sont des problèmes, et quelle est l'approche de Java pour les résoudre.
Ainsi, l'ensemble de fonctionnalités que je présente dans chaque chapitre est basé sur ma manière de résoudre un
certain type de problèmes au moyen de ce langage. Par cette démarche j'espère peu à peu amener le lecteur au
point où « penser Java » lui deviendra naturel.

Je garderai constamment à l'esprit qu'il faut que chacun se construise un modèle de pensée permettant de développer
une profonde connaissance du langage ; lorsqu'il rencontrera un problème ardu, il devra être capable d'en alimenter
ce modèle et d'en déduire la solution.

II-A - Prérequis

Ce livre part du principe que le lecteur est un familier de la programmation : il sait qu'un programme est un ensemble
d'instructions, il sait ce que sont un sous-programme, une fonction, une macro-instruction, un ordre de contrôle tel
que « if » ainsi qu'une structure de boucle telle que « while », etc. Toutefois, il a certainement appris cela de différentes
façons, par exemple en programmant avec un macrolangage ou bien en utilisant un outil tel que Perl. Si vous faites
partie de ceux qui sont à l'aise avec les idées de base de la programmation, vous lirez ce livre sans problème.
Bien entendu, le livre sera plus facile pour les programmeurs C et encore plus pour les programmeurs C++, mais
n'abandonnez pas pour autant si vous n'avez aucune expérience de ces langages (en revanche, préparez-vous à
travailler dur ; par ailleurs, le CD multimédia fourni avec ce livre vous amènera rapidement à comprendre la syntaxe
de base du langage C nécessaire à l'apprentissage de Java). Je vais présenter les concepts de la programmation
orientée objet (POO) et les mécanismes de contrôle de base de Java, ainsi le lecteur en aura connaissance, et
rencontrera dans les premiers exercices les instructions de base du contrôle de flux de programme.

Bien qu'il soit souvent fait référence aux fonctionnalités des langages C et C++, il ne s'agit pas d'un aparté pour initiés,
mais au contraire d'aider tous les programmeurs à mettre Java en perspective avec ces deux langages, qui, après
tout, sont ses parents. Je vais essayer de simplifier ces références et d'expliquer à un programmeur ne connaissant
ni C ni C++ tout ce que j'imagine être peu familier pour lui.

II-B - Apprendre Java

J'ai commencé à enseigner C++ à l'époque où était édité mon premier livre Using C++(Osborne McGraw-Hill, 1989).
Enseigner la programmation est devenu ma profession ; depuis 1989 j'ai vu bien des hochements de tête, de visages
vides, ainsi que beaucoup d'expressions d'incompréhension chez maints auditoires à travers le monde. Lorsque je
me mis à donner des cours chez moi, pour des groupes plus réduits, je découvris que même ceux qui souriaient
et hochaient la tête étaient déconcertés face à de nombreux problèmes. J'ai découvert aussi, alors que je présidais
le cursus C++ durant plusieurs années à la Software Development Conference (et plus tard le cursus Java), que
moi-même ainsi que les autres conférenciers avions tendance à traiter trop de choses trop rapidement. Finalement,
à cause des différences entre les niveaux de mes auditeurs tout autant que de la manière dont je présentais mon
exposé, j'aurais fini par perdre une partie de mon auditoire. Je me suis posé beaucoup de questions, mais, faisant
partie de ceux qui rechignent au cours magistral (et chez beaucoup de gens, je crois qu'une telle attitude ne peut
provenir que du souvenir de l'ennui que distillent de tels cours), j'ai voulu faire en sorte que tout le monde reste éveillé.

À une certaine période, je terminais mes différents cours sous la pression des besoins. C'est ainsi que j'ai fini par
enseigner par essais et erreurs (une technique qui marche bien également dans la conception des programmes
Java), et finalement j'ai réalisé un cours qui utilise tout ce que j'ai appris grâce à mon expérience d'enseignant - un
cours qu'il me serait agréable de donner durant longtemps. Il consiste à s'attaquer au problème de l'apprentissage par
touches discrètes et faciles à intégrer, et lors d'un séminaire impromptu (la situation idéale pour enseigner) chaque
courte leçon est suivie d'exercices. Je donne maintenant ce cours dans des séminaires Java publics, que l'on peut
trouver sur le site http://www.BruceEckel.com. (Le séminaire d'introduction est également disponible sur le CD-
ROM, son contenu est disponible sur le même site Web.)

- 17 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Le retour d'expérience que me procure chaque séminaire m'aide à modifier et recentrer mon discours jusqu'à ce qu'il
devienne un bon moyen d'enseignement. Mais ce livre est plus qu'une simple compilation de notes de séminaires :
j'ai tenté d'y intégrer autant d'informations que je le pouvais, et je l'ai structuré afin que chaque sujet mène droit au
suivant. Enfin, plus que tout, le livre est conçu pour aider le lecteur solitaire qui se bat avec un nouveau langage
de programmation.

II-C - Buts

Comme mon précédent livre Thinking in C++, celui-ci a été structuré pour enseigner le langage. En particulier,
ma motivation est de faire en sorte qu'il puisse me servir pour enseigner le langage dans mes propres séminaires.
Lorsque je pense à un chapitre du livre, je me demande s'il pourrait faire l'objet d'une bonne leçon lors d'un séminaire.
Mon but est d'avoir des chapitres courts pouvant être exposés en un temps raisonnable, suivis par des exercices
réalisables dans une situation de salle de classe.

Dans ce livre je me suis donné comme buts :

1 Présenter le cours pas à pas afin que le lecteur assimile chaque concept avant d'aller plus avant ;
2 Utiliser des exemples qui soient aussi simples et courts que possible. De temps en temps, cela me
détournera des problèmes « du monde réel », mais j'ai remarqué que les débutants sont généralement plus
satisfaits de comprendre chaque détail d'un exemple qu'ils ne sont impressionnés par la portée du problème
qu'ils cherchent à résoudre. Il y a également une limite à la taille du code qui peut être assimilé dans une
situation de cours magistral, limite qu'il faut impérativement ne pas dépasser. À ce sujet je devrais recevoir
quelques critiques pour avoir utilisé des « exemples jouets », et je les accepte volontiers, avec le prétexte que
ce que je présente est utile, pédagogiquement parlant ;
3 Enchaîner soigneusement la présentation des fonctionnalités afin que l'on ne rencontre jamais quoi que ce
soit qui n'ait jamais été exposé. Bien entendu, ce n'est pas toujours possible, et, dans de telles situations, je
donne une brève description en introduction ;
4 Montrer ce que je pense être important concernant la compréhension du langage, plutôt qu'exposer tout mon
savoir. Je crois que l'information est fortement hiérarchisée, qu'il est avéré que 95 % des programmeurs n'ont
pas besoin de tout connaître, et que cela déroute tout le monde et ajoute à leur impression de complexité
du langage. Pour prendre un exemple en C, connaissant par cœur le tableau de priorité des opérateurs (ce
qui n'est pas mon cas), il est possible d'écrire un code astucieux. Mais en y réfléchissant un instant, ceci
risque de dérouter le lecteur et/ou le mainteneur de ce code. Il est donc préférable d'oublier la priorité des
opérateurs, et d'utiliser des parenthèses lorsque les choses ne sont pas claires ;
5 Maintenir chaque section assez concentrée de telle manière que le temps de lecture - et le temps entre
les exercices - soit court. Non seulement cela maintient l'attention et l'implication des auditeurs lors d'un
séminaire, mais cela donne au lecteur une plus grande impression de travail bien fait ;
6 Vous munir de bases solides afin que votre connaissance soit suffisante avant de suivre un cours ou lire un
livre plus difficiles.

II-D - Documentation en ligne

Le langage Java et les bibliothèques de Sun Microsystems (en téléchargement libre) sont accompagnés d'une
documentation sous forme électronique, que l'on peut lire avec un navigateur Web, et en pratique chaque
implémentation tierce de Java possède un système de documentation équivalent. La plupart des livres publiés à
propos de Java dupliquent cette documentation. Soit vous l'avez déjà, soit vous pouvez la télécharger, et donc ce
livre ne la reprendra pas, excepté lorsque c'est nécessaire, parce qu'il sera généralement plus rapide de trouver la
description d'une classe au moyen d'un navigateur plutôt que dans le livre (de plus, la documentation en ligne sera
probablement davantage à jour). Ce livre fournira certaines descriptions de classes supplémentaires lorsqu'il sera
nécessaire de compléter la documentation afin de comprendre un exemple particulier.

II-E - Les chapitres

Ce livre a été conçu en gardant une seule chose à l'esprit : la manière dont les gens apprennent le langage Java.
Le retour d'information des auditeurs de séminaires m'a aidé à découvrir les parties difficiles qui justifient un autre

- 18 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

éclairage. Dans les domaines où je fus ambitieux, où j'ai ajouté trop de fonctionnalités dans un même temps, j'ai fini
par comprendre - au travers du processus d'enseignement - que si l'on ajoute de nouvelles fonctionnalités, on doit
les expliquer complètement, et que cela peut dérouter les étudiants. Je me suis donc donné beaucoup de mal pour
introduire aussi peu que possible de nouveaux concepts en un même temps.

Le but est donc d'enseigner une seule fonctionnalité par chapitre, ou à la rigueur un petit ensemble de fonctionnalités
associées, en évitant les liaisons avec des fonctionnalités supplémentaires. De cette manière, il est possible
d'assimiler chaque chose dans le contexte de la connaissance actuelle avant d'aller plus loin.

Voici une brève description des chapitres contenus dans le livre, qui correspondent aux leçons et exercices de mes
séminaires.

Chapitre 1 : Introduction sur les Objets

Ce chapitre est une vue d'ensemble de ce qu'est la programmation orientée objet, y compris la réponse à la
question de base « Qu'est-ce qu'un objet », ce que sont une interface et une implémentation, l'abstraction et
l'encapsulation, les messages et les fonctions, l'héritage et la composition, ainsi que le polymorphisme qui est d'une
très haute importance. On y trouve également une vue d'ensemble de la manière dont les objets sont créés avec les
constructeurs, où se trouvent les objets, où les ranger une fois créés, ainsi que le magique ramasse-miettes (garbage
collector) qui détruit tous les objets devenus inutiles. D'autres questions seront abordées, comme le traitement des
erreurs par les exceptions, le multithreading pour des interfaces utilisateur réactives, la programmation réseau et
l'Internet. On y apprendra ce qui rend Java spécial, pourquoi il a tant de succès, ainsi que l'analyse et la conception
orientées objet.

Chapitre 2 : Tout est Objet

Avec ce chapitre on arrive au point où l'on peut écrire un premier programme Java. Il doit donc donner une vision
d'ensemble des choses essentielles, entre autres : le concept de référence à un objet ; comment créer un objet ;
une introduction aux types primitifs et aux tableaux ; comment ils sont détruits par le ramasse-miettes ; comment
toute chose est en Java un nouveau type de données (class) et comment créer vos propres classes ; les fonctions,
leurs arguments et leur valeur de retour ; la visibilité des noms et l'utilisation de composants provenant d'autres
bibliothèques ; le mot-clef static ; les commentaires et la documentation intégrée.

Chapitre 3 : Contrôler le Déroulement du Programme

Ce chapitre commence avec tous les opérateurs provenant de C et C++. On y découvre les pièges classiques des
opérateurs, le changement de type, la promotion et la priorité. Suivent le classique contrôle de flux de programme,
les instructions de rupture de séquence déjà connues pour avoir été rencontrées dans d'autres langages de
programmation : le choix avec if-else, la boucle avec for et while ; comment sortir d'une boucle avec break et
continue aussi bien qu'avec les break étiquetés et les continue étiquetés (qui représentent le « goto manquant »
en Java) ; la sélection avec switch. Bien que la majorité de ces fonctionnalités ressemblent au code C et C++, il existe
certaines différences. De plus, tous les exemples sont écrits en pur Java, afin de mieux montrer à quoi ressemble
le langage.

Chapitre 4 : Initialisation et Nettoyage Mémoire

Ce chapitre commence par décrire le constructeur, lequel garantit une initialisation correcte. La définition du
constructeur débouche sur le concept de surcharge de fonction (dans la mesure où plusieurs constructeurs peuvent
coexister). La suite est une discussion sur le processus de nettoyage mémoire, qui n'est pas toujours aussi simple qu'il
semblerait. Normalement, il suffit d'abandonner un objet lorsqu'on n'en a plus besoin, et le ramasse-miettes finira par
libérer la mémoire. Cette partie explore le ramasse-miettes ainsi que quelques-unes de ses particularités. Le chapitre
se termine par une vision plus centrée sur l'initialisation : initialisation automatique des membres, spécification de
l'initialisation des membres, ordre d'initialisation, initialisation static et initialisation des tableaux.

Chapitre 5 : Cacher l'Implémentation

- 19 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Ce chapitre traite de la manière dont le code est mis en paquetages, et pourquoi certaines parties d'une bibliothèque
sont visibles alors que d'autres sont cachées. Il s'intéresse tout d'abord aux mots-clefs package et import, qui sont
en relation avec la gestion des paquetages au niveau fichier et permettent de construire des bibliothèques de classes.
Il examine ensuite le problème sous l'angle des chemins de dossier et des noms de fichiers. Le reste du chapitre
traite des mots-clefs public, private et protected, du concept de l'accès « amical » (accès par défaut, NdT), et de
ce que signifient les différents niveaux de contrôle d'accès utilisés dans divers contextes.

Chapitre 6 : Réutilisation des Classes

Le concept d'héritage se retrouve dans pratiquement tous les langages de POO. Il s'agit de prendre une classe
existante et d'étendre ses fonctionnalités (ou tout aussi bien les modifier, c'est le sujet du chapitre 7). L'héritage
consiste toujours à réutiliser du code en gardant la même « classe de base », et en modifiant simplement certaines
choses çà et là afin d'obtenir ce que l'on veut. Toutefois, l'héritage n'est pas la seule manière de créer de nouvelles
classes à partir de classes existantes. Il est également possible d'encapsuler un objet dans une nouvelle classe au
moyen de la composition. Ce chapitre explique ces deux méthodes de réutilisation du code en Java, et comment
les utiliser.

Chapitre 7 : Le Polymorphisme

Si vous appreniez par vous-même, il vous faudrait neuf mois pour découvrir et comprendre le polymorphisme, l'une
des pierres angulaires de la POO. Des exemples simples et courts montreront comment créer une famille de types
au moyen de l'héritage et comment manipuler les objets dans cette famille par l'intermédiaire de leur classe de base.
Le polymorphisme de Java permet de traiter de manière générique tout objet d'une famille, ce qui signifie que la plus
grande partie du code n'est pas liée à une information spécifique sur le type. Ceci rend les programmes extensibles,
et donc leur développement et leur maintenance plus simples et moins onéreux.

Chapitre 8 : Interfaces & Classes Internes

Java fournit une troisième voie pour la réutilisation du code, avec l'interface, qui est une pure abstraction de l'interface
d'un objet. L'interface est bien plus qu'une simple classe abstraite dont on aurait poussé l'abstraction à l'extrême,
puisqu'il vous permet de développer une variation sur l'« héritage multiple » du C++, en créant une classe qui peut
être transtypée vers plus d'un type de base.

Au premier abord, les classes internes ressemblent à un simple mécanisme permettant de cacher le code : on place
des classes à l'intérieur d'autres classes. Vous apprendrez toutefois que la classe interne fait plus que cela - elle
connaît la classe enveloppante et peut communiquer avec elle - et il est certain que le style de code que l'on écrit au
moyen des classes internes est plus élégant et plus clair, bien que cela représente pour la plupart d'entre vous une
nouvelle fonctionnalité nécessitant un certain temps d'apprentissage avant d'être maîtrisée.

Chapitre 9 : Stockage des Objets

Un programme qui manipule un nombre fixe d'objets dont la durée de vie est connue ne peut être que clair et
très simple. Mais généralement, les programmes créent de nouveaux objets à différents moments, qui ne seront
connus que lors de l'exécution. De plus, avant l'exécution, on ne connaît ni le nombre ni parfois le type exact des
objets qui seront nécessaires. Afin de résoudre ce problème général de la programmation, nous devons pouvoir
créer n'importe quel nombre d'objets, à n'importe quel moment, n'importe où. Ce chapitre explore en profondeur la
bibliothèque fournie par Java 2 pour ranger les objets durant leur existence : les tableaux simples et les conteneurs
plus sophistiqués (structures de données) comme ArrayList et HashMap.

Chapitre 10 : Traitement des Erreurs au Moyen des Exceptions

Java a pour philosophie de base qu'un code mal écrit ne sera jamais exécuté. Autant que possible, le compilateur
repère les problèmes, mais parfois les problèmes - aussi bien une erreur de programmation qu'une condition d'erreur
naturelle survenant lors de l'exécution normale du programme - ne peuvent être détectés et traités qu'au moment de
l'exécution. Java possède un traitement des erreurs par les exceptions pour s'occuper de tout problème survenant
pendant l'exécution. Ce chapitre examine comment fonctionnent en Java les mots-clefs try, catch, throw, throws,

- 20 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

et finally ; quand lancer des exceptions ; et ce que l'on doit faire si on les intercepte. Il expose aussi les exceptions
standard de Java, comment créer vos propres exceptions, ce qu'il advient des exceptions dans les constructeurs, et
comment sont localisés les codes de traitement d'exception.

Chapitre 11 : le Système d'E/S de Java

En théorie, on peut diviser n'importe quel programme en trois parties : entrée, traitement et sortie des données.
Ceci suggère que les E/S (entrées/sorties) représentent une part importante de n'importe quel problème. Ce chapitre
étudie les différentes classes fournies par Java pour lire et écrire des fichiers, des blocs mémoire, ainsi que la console.
Il montre la distinction entre E/S « vieux style » et E/S « nouveau style » Java. Il examine également le processus
consistant à prendre un objet, le transformer en flux (de manière à pouvoir le ranger sur disque ou l'envoyer à
travers un réseau) puis le reconstruire, ce qui est pris en charge par la sérialisation des objets de Java. Il présente
également les bibliothèques de compression de Java, utilisées dans le format de fichier Java ARchive (JAR).

Chapitre 12 : Identification Dynamique de Type

L'identification dynamique de type de Java (Run-Time Type Identification, RTTI) permet de connaître le type exact
d'un objet à partir d'une référence sur le type de base. Habituellement, on préfère ignorer intentionnellement le type
exact d'un objet et laisser au mécanisme de liaison dynamique de Java (polymorphisme) le soin d'implémenter la
signification correcte pour ce type. Mais de temps en temps il est très utile de connaître le type réel d'un objet pour
lequel on n'a qu'une référence sur le type de base. Souvent cette information permet d'implémenter plus efficacement
un traitement spécial. Ce chapitre explique à quoi sert la RTTI, comment l'utiliser, et comment s'en débarrasser
lorsqu'on n'en a plus besoin. Enfin, il introduit le mécanisme de réflexion de Java.

Chapitre 13 : Créer des Fenêtres et des Applets

Java est livré avec la bibliothèque GUI « Swing », qui est un ensemble de classes traitant du fenêtrage d'une manière
portable (NdT : sur différentes plates-formes). Ces programmes fenêtrés peuvent être soit des applets soit des
applications autonomes. Ce chapitre est une introduction à Swing et à la création d'applets pour le World Wide Web. Il
introduit aussi l'importante technologie des « JavaBeans », fondamentale pour la création d'outils de développement
de programmes destinés au Développement Rapide d'Applications (RAD, Rapid-Application Development).

Chapitre 14 : Les Threads Multiples

Java fournit un moyen de créer de multiples sous-tâches concurrentes, appelées threads, s'exécutant dans le
contexte d'un même programme (mis à part le cas où la machine possède plus d'un processeur, ceci n'a que
l'apparence de sous-tâches multiples). Bien qu'on puisse les utiliser n'importe où, l'utilisation des threads est plus
évidente lorsqu'il s'agit de créer une interface utilisateur réactive comme lorsqu'un certain processus gourmand en
ressources système en cours d'exécution empêche un utilisateur d'utiliser un bouton ou d'entrer des données. Ce
chapitre examine la syntaxe et la sémantique du multithreading en Java.

Chapitre 15 : Informatique Distribuée

Toutes les fonctionnalités et bibliothèques de Java semblent vraiment faites les unes pour les autres lorsqu'on
commence à écrire des programmes qui travaillent en réseau. Ce chapitre explore la communication au travers
des réseaux et sur l'Internet, ainsi que les classes fournies par Java pour faciliter cela. Il introduit les concepts
très importants de Servlets et des JSP (pour la programmation « côté serveur »), ainsi que la connectivité aux
bases de données, Java DataBase Connectivity (JDBC), et l'invocation de méthodes distantes, Remote Method
Invocation (RMI). Et, pour finir, une introduction aux nouvelles technologies JINI, JavaSpaces, et Enterprise
JavaBeans (EJB).

Annexe A : Passage & Retour d'Objets

Étant donné qu'en Java seules les références permettent d'appréhender les objets, le concept de « passer un objet
à une fonction » et celui de « retourner un objet depuis une fonction » ont quelques conséquences intéressantes.

- 21 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Cette annexe explique ce qu'il faut savoir afin de gérer les objets à l'entrée et à la sortie d'une fonction, et montre
également la classe String, qui utilise une approche différente du problème.

Annexe B : L'interface Java Natif (JNI)

Un programme Java entièrement portable a de sérieux inconvénients : la vitesse, et l'incapacité d'accéder à des
services spécifiques de la plate-forme. Connaissant la plate-forme sur laquelle sera exécuté le programme, il est
possible d'accélérer spectaculairement certaines opérations en les transformant en méthodes natives, qui sont des
fonctions écrites dans un autre langage de programmation (actuellement, seuls C/C++ sont supportés). Cette annexe
procure une courte introduction à cette fonctionnalité, suffisante pour qu'on puisse créer des exemples simples
utilisant cette interface avec un code autre que Java.

Cette annexe est un ensemble de suggestions qui vous aideront dans la conception et le codage de bas niveau de
votre application.

Annexe D : Ressources

Une liste des livres sur Java qui m'ont paru particulièrement utiles.

II-F - Exercices

Je me suis aperçu que des exercices simples sont très utiles pour consolider les connaissances des étudiants lors
d'un séminaire, on en trouvera donc un ensemble à la fin de chaque chapitre.

La plupart d'entre eux sont conçus afin d'être assez simples pour être réalisés dans un temps raisonnable dans le
contexte d'une salle de classe, pendant que l'instructeur vérifie que tous les étudiants ont assimilé le sujet de la leçon.
Quelques exercices sont plus pointus, afin d'éviter l'ennui chez les étudiants expérimentés. La majorité est conçue
pour être réalisés rapidement, ainsi que pour tester et perfectionner les connaissances. Quelques-uns présentent
des difficultés, mais jamais de difficulté majeure. (Je présume que vous les découvrirez par vous-même - ou plutôt
qu'ils vous trouveront).

Les solutions des exercices se trouvent dans le document électronique The Thinking in Java Annotated Solution
Guide, disponible pour un faible coût sur http://www.BruceEckel.com.

II-G - Le CD-ROM multimédia

Deux CD-ROM multimédia sont associés à ce livre. Le premier est fourni avec le livre lui-même : Thinking in C, décrit
à la fin de la préface, et consiste en une préparation à ce livre qui décrit la syntaxe C nécessaire à la compréhension
de Java.

Il existe un deuxième CD-ROM Multimédia, basé sur le contenu du livre. Ce CD-ROM est un produit séparé et contient
la totalité du séminaire d'une semaine de formation Java « Hands-On Java ». J'y ai enregistré plus de 15 heures de
conférence, synchronisées avec des centaines de diapositives d'information. C'est un accompagnement idéal, dans
la mesure où le séminaire est basé sur ce livre.

Le CD-ROM contient toutes les conférences du séminaire de formation en immersion totale de cinq jours (il ne traite
pas de l'attention portée aux cas particuliers !). Nous espérons que cela définira un nouveau standard de qualité.

Le CD-ROM « Hands-On Java » est uniquement disponible en le commandant directement sur le site http://
www.BruceEckel.com.

- 22 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

II-H - Le Code source

L'ensemble du code source de ce livre est disponible en freeware sous copyright, en une seule archive, en
visitant le site Web http://www.BruceEckel.com. Afin que vous soyez certains d'obtenir la dernière version, cette
adresse est celle du site officiel pour la distribution du code et de la version électronique du livre. Il existe des
versions miroir du livre électronique et du code sur d'autres sites (dont certains sont référencés sur le site http://
www.BruceEckel.com), mais il est préférable de rendre visite au site officiel afin de s'assurer que la version miroir
est la plus récente. Vous êtes autorisés à distribuer le code à des fins d'enseignement ou d'éducation.

Le but essentiel du copyright est d'assurer que la source du code soit correctement citée, et d'éviter que le code soit
utilisé sans autorisation dans un médium imprimé. (Tant que la source est citée, l'utilisation d'exemples provenant
du livre ne pose généralement pas problème).

Chaque code source contient une référence à l'annonce suivante du copyright :

//:!:CopyRight.txt
Copyright ©2000 Bruce Eckel
Source code file from the 2nd edition of the book
"Thinking in Java." All rights reserved EXCEPT as
allowed by the following statements:
You can freely use this file
for your own work (personal or commercial),
including modifications and distribution in
executable form only. Permission is granted to use
this file in classroom situations, including its
use in presentation materials, as long as the book
"Thinking in Java" is cited as the source.
Except in classroom situations, you cannot copy
and distribute this code; instead, the sole
distribution point is http://www.BruceEckel.com
(and official mirror sites) where it is
freely available. You cannot remove this
copyright and notice. You cannot distribute
modified versions of the source code in this
package. You cannot use this file in printed
media without the express permission of the
author. Bruce Eckel makes no representation about
the suitability of this software for any purpose.
It is provided "as is" without express or implied
warranty of any kind, including any implied
warranty of merchantability, fitness for a
particular purpose or non-infringement. The entire
risk as to the quality and performance of the
software is with you. Bruce Eckel and the
publisher shall not be liable for any damages
suffered by you or any third party as a result of
using or distributing software. In no event will
Bruce Eckel or the publisher be liable for any
lost revenue, profit, or data, or for direct,
indirect, special, consequential, incidental, or
punitive damages, however caused and regardless of
the theory of liability, arising out of the use of
or inability to use software, even if Bruce Eckel
and the publisher have been advised of the
possibility of such damages. Should the software
prove defective, you assume the cost of all

- 23 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

necessary servicing, repair, or correction. If you


think you've found an error, please submit the
correction using the form you will find at
www.BruceEckel.com. (Please use the same
form for non-code errors found in the book.)
///:~

Vous êtes autorisés à utiliser le code pour vos projets ainsi qu'à des fins d'éducation (ceci incluant vos cours) à la
condition de conserver le copyright inclus dans chaque fichier source.

II-H-1 - Typographie et style de code

Dans ce livre, les identificateurs (de fonction, de variable, de nom de classe) sont écrits en gras. La plupart des
mots-clefs sont également en gras, à l'exception de ceux qui sont si souvent utilisés, tels que « class », que cela
en deviendrait ennuyeux.

J'utilise un style de code particulier pour les exemples de ce livre. Ce style suit les règles que Sun utilise lui-même
dans pratiquement tous les codes que l'on peut trouver sur son site (voir java.sun.com/docs/codeconv/index.html),
et semble être pris en compte par la plupart des environnements de développement Java. Si vous avez lu mes autres
livres, vous avez pu remarquer que le style de codage de Sun coïncide avec le mien - ce qui me fait évidemment
plaisir, bien que je n'y sois pour rien. Le sujet du style de format demanderait des heures de débat assez chaud, aussi
je vais simplement dire que je ne prétends pas imposer un style correct au travers de mes exemples, j'ai seulement
mes propres motivations pour faire ainsi. Puisque Java est un langage de programmation indépendant de la forme,
vous pouvez continuer à utiliser le style qui vous convient.

Les programmes de ce livre sont des fichiers directement inclus, au moyen du traitement de texte, depuis des
fichiers ayant déjà subi une compilation. Par suite, le code imprimé dans le livre ne doit pas provoquer d'erreurs
de compilation. Les erreurs qui pourraient entraîner des messages d'erreur lors de la compilation sont mises en
commentaires au moyen de //! de manière à être facilement repérées et testées par des moyens automatiques. Les
erreurs découvertes et rapportées à l'auteur feront d'abord l'objet d'une modification du code source distribué, puis,
plus tard, d'une révision du livre (qui sera également disponible sur le site Web http://www.BruceEckel.com).

II-I - Les versions de Java

Je me réfère généralement à l'implémentation Sun de Java pour déterminer la démarche correcte.

Depuis le début, Sun a fourni trois versions majeures de Java : 1.0, 1.1 et 2 (laquelle est appelée version 2 même
si les versions du JDK de Sun continuent à être numérotées 1.2, 1.3, 1.4, etc.). La version 2 semble définitivement
mettre Java en lumière, en particulier lorsqu'il est question des outils d'interface utilisateur. Ce livre en parle et a été
testé avec Java 2, bien que je fasse de temps en temps des concessions aux fonctionnalités futures de Java 2 afin
que le code soit compilable sous Linux (avec le JDK Linux disponible alors que j'écrivais ceci).

Si vous désirez apprendre les versions antérieures du langage non couvertes par cette édition, la première édition de
ce livre est librement téléchargeable à l'adresse URL : http://www.BruceEckel.com, vous la trouverez également
dans le CD livré avec ce livre.

Attention : lorsqu'il m'a fallu mentionner les versions antérieures du langage, je n'utilise pas les numéros de sous-
révision. Dans ce livre je fais uniquement référence à Java 1.0, Java 1.1, et Java 2, afin de me prémunir contre les
erreurs typographiques qui pourraient résulter de futures sous-révisions de ces produits.

II-J - Seminars and mentoring

(non traduit, les personnes intéressées par les séminaires de Bruce Eckel devant a priori maîtriser l'anglais)
My company provides five-day, hands-on, public and in-house training seminars based on the material in this book.

- 24 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Selected material from each chapter represents a lesson, which is followed by a monitored exercise period so each
student receives personal attention. The audio lectures and slides for the introductory seminar are also captured
on CD ROM to provide at least some of the experience of the seminar without the travel and expense. For more
information, go to http://www.BruceEckel.com.

My company also provides consulting, mentoring and walkthrough services to help guide your project through its
development cycle - especially your company's first Java project.

II-K - Errors

(non traduit car cela concerne les erreurs relevées dans la version anglaise du livre de Bruce Eckel) No matter
how many tricks a writer uses to detect errors, some always creep in and these often leap off the page for a fresh
reader.

There is an error submission form linked from the beginning of each chapter in the HTML version of this book (and
on the CD ROM bound into the back of this book, and downloadable from http://www.BruceEckel.com) and also
on the Web site itself, on the page for this book. If you discover anything you believe to be an error, please use this
form to submit the error along with your suggested correction. If necessary, include the original source file and note
any suggested modifications. Your help is appreciated.

II-L - À propos de la conception de la couverture du livre

La couverture de Thinking in Java est inspirée par le Mouvement des Arts et Métiers Américain (American Arts &
Crafts Movement), qui commença peu avant le XXe siècle et atteignit son zénith entre 1900 et 1920. Il vit le jour
en Angleterre en réaction à la fois contre la production des machines de la Révolution Industrielle et contre le style
hautement ornemental de l'ère Victorienne. Arts & Crafts mit l'accent sur la sobriété, les formes de la nature telles
que les voyait le mouvement « art nouveau" (en français dans le texte, NdT), le travail manuel, et l'importance des
travailleurs et artisans particuliers, et encore n'ont-ils pas dédaigné l'utilisation des outils modernes. Il y a beaucoup de
ressemblances avec la situation actuelle : le tournant du siècle, l'évolution des débuts inexpérimentés de la révolution
informatique vers quelque chose de plus raffiné et significatif pour les individus, et l'engouement pour la connaissance
du métier de programmeur face à la fabrication industrielle de code.

Je considère Java de la même manière : une tentative pour élever le programmeur au-dessus de la mécanique du
système d'exploitation afin de l'amener à devenir un « artisan du logiciel ».

L'auteur, tout autant que le concepteur du livre et de sa couverture (qui sont amis depuis l'enfance) ont trouvé leur
inspiration dans ce mouvement, et tous deux possèdent des meubles, lampes, etc. soit originaux, soit inspirés par
cette période.

L'autre thème de cette couverture suggère une boîte servant à la présentation des spécimens d'insectes recueillis
par un naturaliste. Ces insectes sont des objets, qui sont placés dans des boîtes-objets. Les boîtes-objets sont elles-
mêmes placées dans la « couverture-objet », ce qui illustre le concept fondamental d'agrégation en programmation
orientée objet. Bien entendu, ceci n'est d'aucune utilité pour un programmeur, mais crée une association avec les
« punaises » (« bugs »), ici les punaises ont été capturées, probablement tuées dans un bocal à spécimen, et pour
finir confinées dans une petite boîte pour être exposées, comme pour montrer la capacité de Java à trouver, montrer,
et soumettre les bogues (ce qui est vraiment l'un de ses attributs les plus puissants).

II-M - Remerciements

En premier, merci à tous les associés qui travaillèrent avec moi pour encadrer des séminaires, faire du consulting,
et développer des projets éducatifs : Andrea Provaglio, Dave Bartlett (qui a par ailleurs fortement contribué au
Chapitre 15), Bill Venners, et Larry O'Brien. J'ai apprécié leur patience alors que je continuais de développer le
meilleur modèle permettant à des personnes indépendantes comme nous de travailler ensemble. Merci à Rolf André

- 25 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Klaedtke (Suisse) ; Martin Vlcek, Martin Byer, Vlada & Pavel Lahoda, Martin the Bear, et Hanka (Prague) ; ainsi que
Marco Cantu (Italie) pour leur hébergement lors de ma première tournée de conférences improvisée en Europe.

Merci aussi à la « Doyle Street Cohousing Community » pour m'avoir supporté durant les deux années nécessaires
à la rédaction de cette première édition (ainsi que pour m'avoir supporté dans l'absolu). Bien des remerciements à
Kevin et Sonda Donovan pour m'avoir accueilli dans leur magnifique Crested Butte, Colorado, l'été où je travaillais
à la première édition du livre. Merci aussi à tous les amis résidents de « Crested Butte » et au « Rocky Mountain
Biological Laboratory » qui m'ont si bien accueilli.

Merci également à Claudette Moore de « Moore Literary Agency » pour son énorme patience et sa constance à
m'obtenir exactement ce je désirais.

Mes deux premiers livres ont été publiés sous la houlette de l'éditeur Jeff Pepper aux éditions Osborne/McGraw-Hill.
Jeff est arrivé au bon endroit au bon moment à Prentice-Hall, il a débroussaillé le chemin et fait tout ce qu'il fallait
pour rendre cette expérience de publication très agréable. Merci, Jeff - cela a compté pour moi.

J'ai une dette spéciale envers Gen Kiyooka et sa compagnie Digigami, qui m'ont gracieusement fourni un serveur
Web les premières années. Cela a représenté pour moi une aide inestimable.

Merci à Cay Horstmann (coauteur de Core Java, Prentice-Hall, 2000), D'Arcy Smith (Symantec), et Paul Tyma
(coauteur de Java Primer Plus, The Waite Group, 1996), pour m'avoir aidé à clarifier les concepts du langage.

Merci aux personnes qui ont pris la parole dans mon cursus Java à la Software Development Conference, aux
étudiants de mes séminaires, pour m'avoir posé les bonnes questions qui m'ont permis de clarifier mes cours.

Je remercie spécialement Larry et Tina O'Brien, qui m'ont aidé à mettre mon séminaire sur le CD-ROM original
Hands-On Java (vous en saurez davantage sur http://www.BruceEckel.com).

Beaucoup de gens m'ont envoyé des correctifs et je reste en dette avec eux, mais je dois remercier particulièrement
(pour la première édition) : Kevin Raulerson (qui repéra des tonnes d'énormes bogues), Bob Resendes (tout
simplement incroyable), John Pinto, Joe Dante, Joe Sharp (les trois, fabuleux), David Combs (beaucoup de
corrections grammaticales et d'éclaircissements), Dr Robert Stephenson, John Cook, Franklin Chen, Zev Griner,
David Karr, Leander A. Stroschein, Steve Clark, Charles A. Lee, Austin Maher, Dennis P. Roth, Roque Oliveira,
Douglas Dunn, Dejan Ristic, Neil Galarneau, David B. Malkovsky, Steve Wilkinson, ainsi qu'une foule d'autres. Prof.
Ir. Marc Meurrens déploya beaucoup d'efforts de publication et réalisa la version électronique de la première édition
du livre disponible en Europe.

J'ai rencontré dans ma vie une avalanche de personnes très techniques et très intelligentes qui sont devenues des
amis, mais qui étaient également peu communes et qui m'ont influencé en ce qu'elles pratiquaient le yoga ainsi que
d'autres formes de spiritualité, ce qui m'a instruit et inspiré. Ce sont Kraig Brockschmidt, Gen Kiyooka et Andrea
Provaglio (qui aida à la compréhension de Java et de la programmation en général en Italie, et qui est maintenant
aux États-Unis associé à l'équipe MindView).

Ce ne fut pas une grande surprise pour moi de découvrir que ma connaissance de Delphi m'a aidé à comprendre
Java, car ces deux langages ont beaucoup de concepts et de décisions de conception de langage en commun.
Des amis fanatiques de Delphi m'ont aidé à devenir plus perspicace à propos de ce merveilleux environnement
de programmation. Ce sont Marco Cantu (un autre italien - il se pourrait qu'être imprégné de culture latine donne
certaines aptitudes pour la programmation ?), Neil Rubenking (qui se nourrissait de culture yoga/végétarienne/Zen
avant de découvrir les ordinateurs), et bien entendu Zack Urlocker, un vieux copain avec qui j'ai parcouru le monde.

La perspicacité et l'aide de mon ami Richard Hale Shaw m'ont été fort utiles (celles de Kim également). Richard et
moi avons passé de concert beaucoup de mois à donner des séminaires et à tenter de trouver l'enseignement parfait
pour les auditeurs. Merci également à KoAnn Vikoren, Eric Faurot, Marco Pardi, ainsi qu'à toute l'équipe du MFI.
Merci particulièrement à Tara Arrowood, qui me rendit confiance à propos des possibilités de conférences.

- 26 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

La conception du livre, de la couverture, ainsi que la photo de couverture sont dues à mon ami Will-Harris, auteur
et concepteur connu (http://www.Will-Harris.com), qui jouait au collège avec des lettres transfert en attendant
l'invention de la publication assistée par ordinateur, tout en se plaignant de mes grognements à propos de mes
problèmes d'algèbre. Toutefois, j'ai produit moi-même mes pages prêtes à imprimer, et donc j'assume mes erreurs
de frappe. Microsoft® Word 97 for Windows a été utilisé pour écrire le livre et Adobe Acrobat pour créer les pages
offset ; le livre est sorti directement des fichiers PDF d'Acrobat (pour rendre hommage à l'ère électronique, je me
trouvais outre-mer les deux fois où la version finale du livre fut produite - la première édition fut envoyée depuis Le
Cap en Afrique du Sud et la seconde depuis Prague). Les polices de caractères sont Georgia pour le corps du texte
et Verdana pour les titres. La police de couverture est ITC Rennie Mackintosh.

Merci aux groupes qui ont créé les compilateurs : Borland, le Blackdown group (pour Linux), et bien entendu, Sun.

Je remercie particulièrement tous mes maîtres et tous mes étudiants (qui furent en même temps mes maîtres). Le
plus plaisant de mes maîtres en écriture fut Gabrielle Rico (auteur de Writing the Natural Way, Putnam, 1983). Je
garderai précieusement le souvenir d'une formidable semaine à Esalen.

Liste non exhaustive de mes collaborateurs : Andrew Binstock, Steve Sinofsky, JD Hildebrandt, Tom Keffer, Brian
McElhinney, Brinkley Barr, Bill Gates au Midnight Engineering Magazine, Larry Constantine et Lucy Lockwood,
Greg Perry, Dan Putterman, Christi Westphal, Gene Wang, Dave Mayer, David Intersimone, Andrea Rosenfield, Claire
Sawyers, d'autres italiens (Laura Fallai, Corrado, Ilsa, et Cristina Giustozzi), Chris et Laura Strand, les Almquists, Brad
Jerbic, Marilyn Cvitanic, les Mabrys, les Haflingers, les Pollocks, Peter Vinci, la famille Robbins, la famille Mœlter (ainsi
que les McMillans), Michael Wilk, Dave Stoner, Laurie Adams, les Cranstons, Larry Fogg, Mike et Karen Sequeira,
Gary Entsminger et Allison Brody, Kevin Donovan et Sonda Eastlack, Chester et Shannon Andersen, Jœ Lordi, Dave
et Brenda Bartlett, David Lee, les Rentschlers, les Sudeks, Dick, Patty, et Lee Eckel, Lynn et Todd, et leurs familles.
Et, bien entendu, Papa et Maman.

II-M-1 - Collaborateurs Internet

Merci à tous ceux qui m'ont aidé à réécrire les exemples au moyen de la bibliothèque Swing, ou pour d'autres
choses : Jon Shvarts, Thomas Kirsch, Rahim Adatia, Rajesh Jain, Ravi Manthena, Banu Rajamani, Jens Brandt, Nitin
Shivaram, Malcolm Davis, ainsi qu'à tous ceux qui se sont exprimés. Cela m'a réellement aidé à mettre le projet à jour.

III - Introduction sur les « objets »

La révolution informatique a pris naissance dans une machine. Nos langages de programmation ont donc tendance
à ressembler à cette machine.

Mais les ordinateurs ne sont pas tant des machines que des outils au service de l'esprit (« des vélos pour le cerveau »,
comme aime à le répéter Steve Jobs) et un nouveau moyen d'expression. Ainsi, ces outils commencent à moins
ressembler à des machines et plus à des parties de notre cerveau ou d'autres formes d'expressions telles que
l'écriture, la peinture, la sculpture ou la réalisation de films. La Programmation Orientée Objet (POO) fait partie de ce
mouvement qui utilise l'ordinateur en tant que moyen d'expression.

Ce chapitre présente les concepts de base de la POO, y compris quelques méthodes de développement. Ce chapitre
et ce livre présupposent que vous avez déjà expérimenté avec un langage de programmation procédural, bien que
celui-ci ne soit pas forcément le C. Si vous pensez que vous avez besoin de plus de pratique dans la programmation
et/ou la syntaxe du C avant de commencer ce livre, vous devriez explorer le CD-ROM fourni avec le livre Thinking
in C: Foundations for C++ and Java aussi disponible surwww.BruceEckel.com.

Ce chapitre tient plus de la culture générale. Beaucoup de personnes ne veulent pas se lancer dans la programmation
orientée objet sans en comprendre d'abord les tenants et les aboutissants. C'est pourquoi nous allons présenter
ici de nombreux concepts afin de vous donner un solide aperçu de la POO. Au contraire, certaines personnes ne
saisissent les concepts généraux qu'après en avoir vu quelques mécanismes mis en œuvre ; ces gens-là se sentent
perdus s'ils n'ont pas un bout de code à se mettre sous la dent. Si vous faites partie de cette catégorie de personnes
et êtes impatients d'attaquer les spécificités du langage, vous pouvez sauter ce chapitre - cela ne vous gênera pas

- 27 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

pour l'écriture de programme ou l'apprentissage du langage. Mais vous voudrez peut-être y revenir plus tard pour
approfondir vos connaissances sur les objets, les comprendre et assimiler la conception objet.

III-A - Les bienfaits de l'abstraction

Tous les langages de programmation fournissent des abstractions. On peut dire que la complexité des problèmes
qu'on est capable de résoudre est directement proportionnelle au type et à la qualité de nos capacités d'abstraction.
Par « type », il faut comprendre « Qu'est-ce qu'on tente d'abstraire ? » Le langage assembleur est une petite
abstraction de la machine sous-jacente. Beaucoup de langages « impératifs » (tels que Fortran, BASIC et C) sont
des abstractions du langage assembleur. Ces langages sont de nettes améliorations par rapport à l'assembleur,
mais leur abstraction première requiert une réflexion en termes de structure ordinateur plutôt qu'à la structure du
problème qu'on essaye de résoudre. Le programmeur doit établir l'association entre le modèle de la machine (dans
« l'espace solution », qui est l'endroit où le problème est modélisé, tel que l'ordinateur) et le modèle du problème
à résoudre (dans « l'espace problème », qui est l'endroit où se trouve le problème). Les efforts requis pour réaliser
cette association, et le fait qu'elle est étrangère au langage de programmation produit des programmes difficiles à
écrire et à maintenir, et comme effet de bord a mené à la création de l'industrie du « Génie Logiciel ».

L'autre option à la modélisation de la machine est de modéliser le problème qu'on tente de résoudre. Les premiers
langages tels que LISP ou APL choisirent une vue particulière du monde (« Tous les problèmes se ramènent à des
listes » ou « Tous les problèmes sont algorithmiques », respectivement). PROLOG convertit tous les problèmes en
chaînes de décisions. Des langages ont été créés en vue de programmer par contrainte, ou pour programmer en
ne manipulant que des symboles graphiques (ces derniers se sont révélés être trop restrictifs). Chacune de ces
approches est une bonne solution pour la classe particulière de problèmes pour laquelle ils ont été conçus, mais
devient une horreur dès lors que vous les sortez de leur domaine d'application.

L'approche orientée objet va un cran plus loin en fournissant des outils au programmeur pour représenter
des éléments dans l'espace problème. Cette représentation se veut assez générale pour ne pas restreindre le
programmeur à un type particulier de problèmes. Nous nous référons aux éléments dans l'espace problème et leur
représentation dans l'espace solution en tant qu'« objets ». (Bien sûr, on aura aussi besoin d'autres objets qui n'ont pas
leur analogue dans l'espace problème.) L'idée est que le programme est autorisé à s'adapter à l'esprit du problème
en ajoutant de nouveaux types d'objet, de façon à ce que, quand on lit le code décrivant la solution, on lise aussi
quelque chose qui décrit le problème. C'est une abstraction plus flexible et puissante que tout ce qu'on a pu voir
jusqu'à présent. Ainsi, la POO permet de décrire le problème avec les termes mêmes du problème plutôt qu'avec
les termes de la machine où la solution sera mise en œuvre. Il y a tout de même une connexion avec l'ordinateur,
bien entendu. Chaque objet ressemble à un miniordinateur ; il a un état, et il a à sa disposition des opérations qu'on
peut lui demander d'exécuter. Cependant, là encore on retrouve une analogie avec les objets du monde réel - ils ont
tous des caractéristiques et des comportements.

Des concepteurs de langage ont décrété que la programmation orientée objet en elle-même n'était pas adéquate pour
résoudre facilement tous les problèmes de programmation, et recommandent la combinaison d'approches variées
dans des langages de programmation multiparadigme1Voir Multiparadigm Programming in Leda de Timothy
Budd (Addison-Wesley 1995)..

Alan Kay résume les cinq caractéristiques principales de Smalltalk, le premier véritable langage de programmation
orienté objet et l'un des langages sur lequel est basé Java. Ces caractéristiques représentent une approche purement
orientée objet :

1 Toute chose est un objet. Il faut penser à un objet comme à une variable améliorée : il stocke des données,
mais on peut « effectuer des requêtes » sur cet objet, lui demander de faire des opérations sur lui-même. En
théorie, on peut prendre n'importe quel composant conceptuel du problème qu'on essaye de résoudre (un
chien, un immeuble, un service administratif, etc.) et le représenter en tant qu'objet dans le programme.
2 Un programme est un ensemble d'objets se disant les uns aux autres quoi faire en s'envoyant des
messages. Pour qu'un objet effectue une requête, on« envoie un message » à cet objet. Plus concrètement,
on peut penser à un message comme à un appel de fonction appartenant à un objet particulier.

- 28 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

3 Chaque objet a son propre espace de mémoire composé d'autres objets. Dit d'une autre manière,
on crée un nouveau type d'objet en créant un paquetage contenant des objets déjà existants. Ainsi, la
complexité d'un programme est cachée par la simplicité des objets mis en œuvre.
4 Chaque objet est d'un type précis. Dans le jargon de la POO, chaque objet est une instance d'une
classe, où « classe » est synonyme de « type ». La plus importante caractéristique distinctive d'une classe
est :« Quels messages peut-on lui envoyer ? »
5 Tous les objets d'un type particulier peuvent recevoir le même message. C'est une caractéristique
lourde de signification, comme vous le verrez plus tard. Parce qu'un objet de type « cercle » est aussi
un objet de type « forme géométrique », un cercle se doit d'accepter les messages destinés aux formes
géométriques. Cela veut dire qu'on peut écrire du code parlant aux formes géométriques qui sera accepté par
tout ce qui correspond à la description d'une forme géométrique. Cette substituabilité est l'un des concepts
les plus puissants de la programmation orientée objet.

III-B - Un objet dispose d'une interface

Aristote fut probablement le premier à commencer une étude approfondie du concept de type ; il parle de « la
classe des poissons et la classe des oiseaux ».L'idée que tous les objets, tout en étant uniques, appartiennent à
une classe d'objets qui ont des caractéristiques et des comportements en commun fut utilisée directement dans le
premier langage orienté objet, Simula-67, avec son mot-clef fondamental class qui introduit un nouveau type dans
un programme.

Simula, comme son nom l'indique, a été conçu pour développer des simulations telles qu'un guichet de banque.
Dans celle-ci, vous avez un ensemble de guichetiers, de clients, de comptes, de transactions et de devises - un tas
« d'objets ». Des objets semblables, leur état durant l'exécution du programme mis à part, sont groupés en tant que
« classes d'objets » et c'est de là que vient le mot-clef class. Créer des types de données abstraits (des classes) est
un concept fondamental dans la programmation orientée objet. On utilise les types de données abstraits exactement
de la même manière que les types de données prédéfinis. On peut créer des variables d'un type particulier (appelées
objets ou instances dans le jargon OO) et manipuler ces variables (ce qu'on appelle envoyer des messages ou des
requêtes ; on envoie un message et l'objet se débrouille pour le traiter). Les membres (éléments) d'une même classe
partagent des caractéristiques communes : chaque compte dispose d'un solde, chaque guichetier peut accepter un
dépôt, etc. Cependant, chaque élément a son propre état : chaque compte a un solde différent, chaque guichetier a
un nom. Ainsi, les guichetiers, clients, comptes, transactions, etc. peuvent tous être représentés par la même entité
au sein du programme. Cette entité est l'objet, et chaque objet appartient à une classe particulière qui définit ses
caractéristiques et ses comportements.

Donc, comme la programmation orientée objet consiste en la création de nouveaux types de données, quasiment
tous les langages orientés objet utilisent le mot-clef « class ». Quand vous voyez le mot « type » pensez « classe »
et inversement (2) .

Comme une classe décrit un ensemble d'objets partageant des caractéristiques communes (données) et des
comportements (fonctionnalités), une classe est réellement un type de données. En effet, un nombre en virgule
flottante par exemple, dispose d'un ensemble de caractéristiques et de comportements. La différence est qu'un
programmeur définit une classe pour représenter un problème au lieu d'être forcé d'utiliser un type de données conçu
pour représenter une unité de stockage de l'ordinateur. Le langage de programmation est étendu en ajoutant de
nouveaux types de données spécifiques à nos besoins. Le système de programmation accepte la nouvelle classe et
lui donne toute l'attention et le contrôle de type qu'il fournit aux types prédéfinis.

L'approche orientée objet n'est pas limitée aux simulations. Que vous pensiez ou non que tout programme n'est
qu'une simulation du système qu'on représente, l'utilisation des techniques de la POO peut facilement réduire un
ensemble de problèmes à une solution simple.

Une fois qu'une classe est créée, on peut créer autant d'objets de cette classe qu'on veut et les manipuler comme
s'ils étaient les éléments du problème qu'on tente de résoudre. En fait, l'une des difficultés de la programmation
orientée objet est de créer une association un à un entre les éléments de l'espace problème et les éléments de
l'espace solution.

- 29 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Mais comment utiliser un objet ? Il faut pouvoir lui demander d'exécuter une requête, telle que terminer une
transaction, dessiner quelque chose à l'écran, ou allumer un interrupteur. Et chaque objet ne peut traiter que certaines
requêtes. Les requêtes qu'un objet est capable de traiter sont définies par son interface, et son type est ce qui
détermine son interface. Prenons l'exemple d'une ampoule électrique :

Ampoule amp = new Ampoule();


amp.allumer();

L'interface précise quelles opérations on peut effectuer sur un objet particulier. Cependant, il doit exister du code
quelque part pour satisfaire cette requête. Ceci, avec les données cachées, constitue l'implémentation. Du point
de vue de la programmation procédurale, ce n'est pas si compliqué. Un type dispose d'une fonction associée à
chaque requête possible, et quand on effectue une requête particulière sur un objet, cette fonction est appelée. Ce
mécanisme est souvent résumé en disant qu'on « envoie un message » (fait une requête) à un objet, et l'objet se
débrouille pour l'interpréter (il exécute le code associé).

Ici, le nom du type/de la classe est Ampoule, le nom de l'objet Ampoule créé est amp, et on peut demander à un
objet Ampoule de s'allumer, de s'éteindre, d'intensifier ou de diminuer sa luminosité. Un objet Ampoule est créé en
définissant une « référence » (amp) pour cet objet et en appelant new pour créer un nouvel objet de ce type. Pour
envoyer un message à cet objet, il suffit de spécifier le nom de l'objet suivi de la requête avec un point entre les
deux. Du point de vue de l'utilisateur d'une classe prédéfinie, c'est tout ce qu'il est besoin de savoir pour programmer
avec des objets.

L'illustration ci-dessus reprend le formalisme UML (Unified Modeling Language). Chaque classe est représentée
par une boîte, avec le nom du type dans la partie supérieure, les données membres qu'on décide de décrire dans la
partie du milieu et les fonctions membres (les fonctions appartenant à cet objet qui reçoivent les messages envoyés
à cet objet) dans la partie du bas de la boîte. Souvent on ne montre dans les diagrammes UML que le nom de la
classe et les fonctions publiques, et la partie du milieu n'existe donc pas. Si seul le nom de la classe nous intéresse,
alors la portion du bas n'a pas besoin d'être montrée non plus.

III-C - L'implémentation cachée

Il est plus facile de diviser les personnes en créateurs de classe (ceux qui créent les nouveaux types de données)
et programmeurs clients3Je suis reconnaissant envers mon ami Scott Meyers pour cette expression. (ceux
qui utilisent ces types de données dans leurs applications). Le but des programmeurs clients est de se monter une
boîte à outils pleine de classes réutilisables pour le développement rapide d'applications (RAD, Rapid Application
Development en anglais). Les créateurs de classes, eux, se focalisent sur la construction d'une classe qui n'expose
que le nécessaire aux programmeurs clients et cache tout le reste. Pourquoi cela ? Parce que si c'est caché, le
programmeur client ne peut l'utiliser, et le créateur de la classe peut changer la portion cachée comme il l'entend sans
se préoccuper de l'impact que cela pourrait avoir chez les utilisateurs de sa classe. La portion cachée correspond
en général aux données de l'objet qui pourraient facilement être corrompues par un programmeur client négligent ou
mal informé. Ainsi, cacher l'implémentation réduit considérablement les bogues.

Le concept d'implémentation cachée ne saurait être trop loué : dans chaque relation il est important de fixer des
frontières respectées par toutes les parties concernées. Quand on crée une bibliothèque, on établit une relation avec

- 30 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

un programmeur client, programmeur qui crée une application (ou une bibliothèque plus volumineuse) en utilisant
notre bibliothèque.

Si tous les membres d'une classe sont accessibles pour tout le monde, alors le programmeur client peut faire ce qu'il
veut avec cette classe et il n'y a aucun moyen de faire respecter certaines règles. Même s'il est vraiment préférable
que l'utilisateur de la classe ne manipule pas directement certains membres de la classe, sans contrôle d'accès il n'y
a aucun moyen de l'empêcher : tout est exposé à tout le monde.

La raison première du contrôle d'accès est donc d'empêcher les programmeurs clients de toucher à certaines portions
auxquelles ils ne devraient pas avoir accès - les parties qui sont nécessaires pour les manipulations internes du type
de données, mais n'appartiennent pas à l'interface dont les utilisateurs ont besoin pour résoudre leur problème. C'est
en réalité un service rendu aux utilisateurs, car ils peuvent voir facilement ce qui est important pour leurs besoins
et ce qu'ils peuvent ignorer.

La deuxième raison d'être du contrôle d'accès est de permettre au concepteur de la bibliothèque de changer le
fonctionnement interne de la classe sans se soucier des effets que cela peut avoir sur les programmeurs clients. Par
exemple, on peut implémenter une classe particulière d'une manière simpliste afin d'accélérer le développement, et se
rendre compte plus tard qu'on a besoin de la réécrire afin de gagner en performances. Si l'interface et l'implémentation
sont clairement séparées et protégées, cela peut être réalisé facilement.

Java utilise trois mots-clefs pour fixer des limites au sein d'une classe : public, private et protected. Leur signification
et leur utilisation sont relativement explicites. Ces spécificateurs d'accès déterminent qui peut utiliser les définitions
qui suivent. public veut dire que les définitions suivantes sont disponibles pour tout le monde. Le mot-clef private,
au contraire, veut dire que personne, le créateur de la classe et les fonctions internes de ce type mis à part, ne peut
accéder à ces définitions. private est un mur de briques entre le créateur de la classe et le programmeur client. Si
quelqu'un tente d'accéder à un membre défini comme private, ils récupèreront une erreur lors de la compilation.
protected se comporte comme private, en moins restrictif : une classe dérivée a accès aux membres protected,
mais pas aux membres private. L'héritage sera introduit bientôt.

Java dispose enfin d'un accès « par défaut », utilisé si aucun de ces spécificateurs n'est mentionné. Cet accès est
souvent appelé accès « amical », car les classes peuvent accéder aux membres amicaux des autres classes du même
package, mais en dehors du package ces mêmes membres amicaux se comportent comme des attributs private.

III-D - Réutilisation de l'implémentation

Une fois qu'une classe a été créée et testée, elle devrait (idéalement) représenter une partie de code utile. Il s'avère
que cette réutilisabilité n'est pas aussi facile à obtenir que cela ; cela demande de l'expérience et de l'anticipation
pour produire un bon design. Mais une fois bien conçue, cette classe ne demande qu'à être réutilisée. La réutilisation
de code est l'un des plus grands avantages que les langages orientés objet fournissent.

La manière la plus simple de réutiliser une classe est d'utiliser directement un objet de cette classe, mais on peut
aussi placer un objet de cette classe à l'intérieur d'une nouvelle classe. On appelle cela « créer un objet membre ».
La nouvelle classe peut être constituée de n'importe quel nombre d'objets d'autres types, selon la combinaison
nécessaire pour que la nouvelle classe puisse réaliser ce pour quoi elle a été conçue. Parce que la nouvelle classe est
composée à partir de classes existantes, ce concept est appelé composition (ou, plus généralement, agrégation).
On se réfère souvent à la composition comme à une relation « possède-un », comme dans « une voiture possède
un moteur ».

(Le diagramme UML ci-dessus indique la composition avec le losange rempli, qui indique qu'il y a un moteur dans
une voiture. J'utiliserai une forme plus simple : juste une ligne, sans le losange, pour indiquer une association (3) .)

- 31 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

La composition s'accompagne d'une grande flexibilité : les objets membres de la nouvelle classe sont généralement
privés, ce qui les rend inaccessibles aux programmeurs clients de la classe. Cela permet de modifier ces membres
sans perturber le code des clients existants. On peut aussi changer les objets membres lors la phase d'exécution,
pour changer dynamiquement le comportement du programme. L'héritage, décrit juste après, ne dispose pas de cette
flexibilité, car le compilateur doit placer des restrictions lors de la compilation sur les classes créées avec héritage.

Parce que la notion d'héritage est très importante au sein de la programmation orientée objet, elle est trop souvent
martelée, et le nouveau programmeur pourrait croire que l'héritage doit être utilisé partout. Cela mène à des
conceptions ultracompliquées et cauchemardesques. La composition est la première approche à examiner lorsqu'on
crée une nouvelle classe, car elle est plus simple et plus flexible. Le design de la classe en sera plus propre. Avec
de l'expérience, les endroits où utiliser l'héritage deviendront raisonnablement évidents.

III-E - Héritage : réutilisation de l'interface

L'idée d'objet en elle-même est un outil efficace. Elle permet de fournir des données et des fonctionnalités liées entre
elles par concept, afin de représenter une idée de l'espace problème plutôt que d'être forcé d'utiliser les idiomes
internes de la machine. Ces concepts sont exprimés en tant qu'unité fondamentale dans le langage de programmation
en utilisant le mot-clef class.

Il serait toutefois dommage, après s'être donné beaucoup de mal pour créer une classe de devoir en créer une toute
nouvelle qui aurait des fonctionnalités similaires. Ce serait mieux si on pouvait prendre la classe existante, la cloner, et
faire des ajouts ou des modifications à ce clone. C'est ce que l'héritage permet de faire, avec la restriction suivante :
si la classe originale (aussi appelée classe de base, superclasse ou classe parent) est changée, le « clone » modifié
(appelé classe dérivée, héritée, enfant ou sous-classe) répercutera aussi ces changements.

(La flèche dans le diagramme UML ci-dessus pointe de la classe dérivée vers la classe de base. Comme vous le
verrez, il peut y avoir plus d'une classe dérivée.)

Prenons l'exemple d'une machine de recyclage qui trie les détritus. Le type de base serait « détritus », caractérisé
par un poids, une valeur, etc., et peut-être concassé, fondu, ou décomposé. À partir de ce type de base sont dérivés
des types de détritus plus spécifiques qui peuvent avoir des caractéristiques supplémentaires (une bouteille a une
couleur) ou des actions additionnelles (une canette peut être découpée, un conteneur d'acier est magnétique). De
plus, des comportements peuvent être différents (la valeur du papier dépend de son type et de son état général). En
utilisant l'héritage, on peut bâtir une hiérarchie qui exprime le problème avec ses propres termes.

Un autre exemple classique : les « formes géométriques »,utilisées entre autres dans les systèmes d'aide à la
conception ou dans les jeux vidéo. Le type de base est la « forme géométrique », et chaque forme a une taille, une
couleur, une position, etc. Chaque forme peut être dessinée, effacée, déplacée, peinte, etc. À partir de ce type de
base, des types spécifiques sont dérivés (hérités) : des cercles, des carrés, des triangles et autres, chacun avec des
caractéristiques et des comportements additionnels (certaines figures peuvent être inversées par exemple). Certains
comportements peuvent être différents, par exemple quand on veut calculer l'aire de la forme. La hiérarchie des types
révèle à la fois les similarités et les différences entre les formes.

- 32 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Représenter la solution avec les mêmes termes que ceux du problème est extraordinairement bénéfique, car on n'a
pas besoin de modèles intermédiaires pour passer de la description du problème à la description de la solution. Avec
les objets, la hiérarchie de types est le modèle primaire, on passe donc du système dans le monde réel directement
au système du code. En fait, l'une des difficultés à laquelle les gens se trouvent confrontés lors de la conception
orientée objet est que c'est trop simple de passer du début à la fin. Les esprits habitués à des solutions compliquées
sont toujours stupéfaits par cette simplicité.

Quand on hérite d'un certain type, on crée un nouveau type. Ce nouveau type non seulement contient tous les
membres du type existant (bien que les membres privés soient cachés et inaccessibles), mais plus important, il
duplique aussi l'interface de la classe de la base. Autrement dit, tous les messages acceptés par les objets de la
classe de base seront acceptés par les objets de la classe dérivée. Comme on connaît le type de la classe par les
messages qu'on peut lui envoyer, cela veut dire que la classe dérivée est du même type que la classe de base.
Dans l'exemple précédent, « un cercle est une forme ». Cette équivalence de type via l'héritage est l'une des notions
fondamentales dans la compréhension de la programmation orientée objet.

Comme la classe de base et la classe dérivée ont toutes les deux la même interface, certaines implémentations
accompagnent cette interface. C'est-à-dire qu'il doit y avoir du code à exécuter quand un objet reçoit un message
particulier. Si on ne fait qu'hériter une classe sans rien lui rajouter, les méthodes de l'interface de la classe de base
sont importées dans la classe dérivée. Cela veut dire que les objets de la classe dérivée n'ont pas seulement le
même type, ils ont aussi le même comportement, ce qui n'est pas particulièrement intéressant.

Il y a deux façons de différencier la nouvelle classe dérivée de la classe de base originale. La première est relativement
directe : il suffit d'ajouter de nouvelles fonctions à la classe dérivée. Ces nouvelles fonctions ne font pas partie de
la classe parente. Cela veut dire que la classe de base n'était pas assez complète pour ce qu'on voulait en faire,
on a donc ajouté de nouvelles fonctions. Cet usage simple de l'héritage se révèle souvent être une solution idéale.
Cependant, il faut tout de même vérifier s'il ne serait pas souhaitable d'intégrer ces fonctions dans la classe de base
qui pourrait aussi en avoir l'usage. Ce processus de découverte et d'itération dans la conception est fréquent dans
la programmation orientée objet.

- 33 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Bien que l'héritage puisse parfois impliquer (spécialement en Java, où le mot-clef qui indique l'héritage est extends)
que de nouvelles fonctions vont être ajoutées à l'interface, ce n'est pas toujours vrai. La seconde et plus importante
manière de différencier la nouvelle classe est de changer le comportement d'une des fonctions existantes de la
superclasse. Cela s'appelle redéfinir cette fonction.

Pour redéfinir une fonction, il suffit de créer une nouvelle définition pour la fonction dans la classe dérivée. C'est
comme dire : « j'utilise la même interface ici, mais je la traite d'une manière différente dans ce nouveau type ».

III-E-1 - Les relations est-un vs est-comme-un

Un certain débat est récurrent à propos de l'héritage : l'héritage ne devrait-il pas seulement redéfinir les fonctions de
la classe de base (et ne pas ajouter de nouvelles fonctions membres qui ne font pas partie de la superclasse) ? Cela
voudrait dire que le type dérivé serait exactement le même que celui de la classe de base puisqu'il aurait exactement
la même interface. Avec comme conséquence logique le fait qu'on puisse exactement substituer un objet de la classe
dérivée à un objet de la classe de base. On fait souvent référence à cette substitution pure sous le nom de principe
de substitution. Dans un sens, c'est la manière idéale de traiter l'héritage. La relation entre la classe de base et la

- 34 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

classe dérivée dans ce cas est une relation est-un, parce qu'on peut dire « un cercle est une forme ». Un test pour
l'héritage est de déterminer si la relation est-un entre les deux classes considérées a un sens.

Mais parfois il est nécessaire d'ajouter de nouveaux éléments à l'interface d'un type dérivé, et donc étendre l'interface
et créer un nouveau type. Le nouveau type peut toujours être substitué au type de base, mais la substitution n'est
plus parfaite parce que les nouvelles fonctions ne sont pas accessibles à partir de la classe parente. On appelle cette
relation une relation est-comme-un5Invention personnelle. ; le nouveau type dispose de l'interface de l'ancien
type, mais il contient aussi d'autres fonctions, on ne peut donc pas réellement dire que ce soient exactement les
mêmes. Prenons le cas d'un système de climatisation. Supposons que notre maison dispose des tuyaux et des
systèmes de contrôle pour le refroidissement, autrement dit elle dispose d'une interface qui nous permet de contrôler
le refroidissement. Imaginons que le système de climatisation tombe en panne et qu'on le remplace par une pompe
à chaleur, qui peut à la fois chauffer et refroidir. La pompe à chaleur est-comme-un système de climatisation, mais
il peut faire plus de choses. Parce que le système de contrôle n'a été conçu que pour contrôler le refroidissement,
il en est restreint à ne communiquer qu'avec la partie refroidissement du nouvel objet. L'interface du nouvel objet a
été étendue, mais le système existant ne connaît rien qui ne soit dans l'interface originale.

Bien sûr, quand on voit cette modélisation, il est clair que la classe de base « Système de refroidissement » n'est
pas assez générale, et devrait être renommée en« Système de contrôle de température » afin de pouvoir inclure le
chauffage - auquel cas le principe de substitution marcherait. Cependant, le diagramme ci-dessus est un exemple
de ce qui peut arriver dans le monde réel.

Quand on considère le principe de substitution, il est tentant de se dire que cette approche (la substitution pure) est la
seule manière correcte de modéliser, et de fait c'est appréciable si la conception fonctionne ainsi. Mais dans certains
cas il est tout aussi clair qu'il faut ajouter de nouvelles fonctions à l'interface d'une classe dérivée. En examinant le
problème, les deux cas deviennent relativement évidents.

III-F - Polymorphisme : des objets interchangeables

Il arrive qu'on veuille traiter un objet non en tant qu'objet du type spécifique qu'il est, mais en tant qu'objet de son type
de base. Cela permet d'écrire du code indépendant des types spécifiques. Dans l'exemple de la forme géométrique,
les fonctions manipulent des formes génériques sans se soucier de savoir si ce sont des cercles, des carrés, des
triangles ou même des formes non encore définies. Toutes les formes peuvent être dessinées, effacées, et déplacées,
donc ces fonctions envoient simplement un message à un objet forme, elles ne se soucient pas de la manière dont
l'objet traite le message.

Un tel code n'est pas affecté par l'addition de nouveaux types, et ajouter de nouveaux types est la façon la plus
commune d'étendre un programme orienté objet pour traiter de nouvelles situations. Par exemple, on peut dériver
un nouveau type de forme appelé pentagone sans modifier les fonctions qui traitent des formes génériques. Cette
capacité à étendre facilement un programme en dérivant de nouveaux sous-types est importante, car il améliore
considérablement la conception tout en réduisant le coût de maintenance.

- 35 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Un problème se pose cependant en voulant traiter les types dérivés comme leur type de base générique (les cercles
comme des formes géométriques, les vélos comme des véhicules, les cormorans comme des oiseaux, etc.). Si une
fonction demande à une forme générique de se dessiner, ou à un véhicule générique de tourner, ou à un oiseau
générique de se déplacer, le compilateur ne peut savoir précisément lors de la phase de compilation quelle portion
de code sera exécutée. C'est d'ailleurs le point crucial : quand le message est envoyé, le programmeur ne veut pas
savoir quelle portion de code sera exécutée ; la fonction dessiner peut être appliquée aussi bien à un cercle qu'à un
carré ou un triangle, et l'objet va exécuter le bon code suivant son type spécifique. Si on n'a pas besoin de savoir
quelle portion de code est exécutée, alors le code exécuté lorsqu'on ajoute un nouveau sous-type peut être différent
sans exiger de modification dans l'appel de la fonction. Le compilateur ne peut donc précisément savoir quelle partie
de code sera exécutée, donc que va-t-il faire ? Par exemple, dans le diagramme suivant, l'objet Contrôleur d'oiseaux
travaille seulement avec des objets Oiseaux génériques, et ne sait pas de quel type ils sont. Cela est pratique du
point de vue de Contrôleur d'oiseaux, car il n'a pas besoin d'écrire du code spécifique pour déterminer le type exact
d'Oiseau avec lequel il travaille, ou le comportement de cet Oiseau. Comment se fait-il donc que, lorsque bouger()
est appelé tout en ignorant le type spécifique de l'Oiseau, on obtienne le bon comportement (une Oie court, vole ou
nage, et un Pingouin court ou nage) ?

La réponse constitue l'astuce fondamentale de la programmation orientée objet : le compilateur ne peut faire un appel
de fonction au sens traditionnel du terme. Un appel de fonction généré par un compilateur non orienté objet crée ce
qu'on appelle une association prédéfinie, un terme que vous n'avez sans doute jamais entendu auparavant, car vous
ne pensiez pas qu'on puisse faire autrement. En d'autres termes, le compilateur génère un appel à un nom de fonction
spécifique, et l'éditeur de liens résout cet appel à l'adresse absolue du code à exécuter. En POO, le programme ne
peut déterminer l'adresse du code avant la phase d'exécution, un autre mécanisme est donc nécessaire quand un
message est envoyé à un objet générique.

Pour résoudre ce problème, les langages orientés objet utilisent le concept d'association tardive. Quand un objet
reçoit un message, le code appelé n'est pas déterminé avant l'exécution. Le compilateur s'assure que la fonction
existe et vérifie le type des arguments et de la valeur de retour (un langage omettant ces vérifications est dit
faiblement typé), mais il ne sait pas exactement quel est le code à exécuter.

Pour créer une association tardive, Java utilise une portion spéciale de code en lieu et place de l'appel absolu. Ce
code calcule l'adresse du corps de la fonction, en utilisant des informations stockées dans l'objet (ce mécanisme est
couvert plus en détail dans le titre IX). Ainsi, chaque objet peut se comporter différemment suivant le contenu de cette
portion spéciale de code. Quand un objet reçoit un message, l'objet sait quoi faire de ce message.

Dans certains langages (en particulier le C++), il faut préciser explicitement qu'on souhaite bénéficier de la flexibilité de
l'association tardive pour une fonction. Dans ces langages, les fonctions membres ne sont pas liées dynamiquement
par défaut. Cela pose des problèmes, donc en Java l'association dynamique est le défaut et aucun mot-clef
supplémentaire n'est requis pour bénéficier du polymorphisme.

Reprenons l'exemple de la forme géométrique. Le diagramme de la hiérarchie des classes (toutes basées sur la
même interface) se trouve plus haut dans ce chapitre. Pour illustrer le polymorphisme, écrivons un bout de code
qui ignore les détails spécifiques du type et parle uniquement à la classe de base. Ce code est déconnecté des
informations spécifiques au type, donc plus facile à écrire et à comprendre. Et si un nouveau type - un Hexagone,

- 36 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

par exemple - est ajouté grâce à l'héritage, le code continuera de fonctionner aussi bien pour ce nouveau type de
Forme qu'il le faisait avec les types existants. Le programme est donc extensible.

Si nous écrivons une méthode en Java (comme vous allez bientôt apprendre à le faire) :

void faireQuelqueChose(Forme f) {
f.effacer();
// …
f.dessiner();
}

Cette fonction s'adresse à n'importe quelle Forme, elle est donc indépendante du type spécifique de l'objet qu'elle
dessine et efface. Si nous utilisons ailleurs dans le programme cette fonction faireQuelqueChose() :

Cercle c = new Cercle();


Triangle t = new Triangle();
Ligne l = new Ligne();
faireQuelqueChose(c);
faireQuelqueChose(t);
faireQuelqueChose(l);

Les appels à faireQuelqueChose() fonctionnent correctement, sans se préoccuper du type exact de l'objet.

En fait c'est une manière de faire très élégante. Considérons la ligne :

faireQuelqueChose(c);

Un Cercle est ici passé à une fonction qui attend une Forme. Comme un Cercle est-une Forme, il peut être
traité comme tel par faireQuelqueChose(). C'est-à-dire qu'un Cercle peut accepter tous les messages que
faireQuelqueChose() pourrait envoyer à une forme. C'est donc une façon parfaitement logique et sûre de faire.

Traiter un type dérivé comme s'il était son type de base est appelé transtypage ascendant, surtypage ou
généralisation (upcasting). L'adjectif ascendant vient du fait que dans un diagramme d'héritage typique, le type de
base est représenté en haut, les classes dérivées s'y rattachant par le bas. Ainsi, changer un type vers son type de
base revient à remonter dans le diagramme d'héritage : transtypage « ascendant ».

Un programme orienté objet contient obligatoirement des transtypages ascendants, car c'est de cette manière que
le type spécifique de l'objet peut être délibérément ignoré. Examinons le code de faireQuelqueChose() :

f.effacer();
// …
f.dessiner();

Remarquez qu'il ne dit pas « Si tu es un Cercle, fais ceci, si tu es un Carré, fais cela, etc. ». Ce genre de code qui
vérifie tous les types possibles que peut prendre une Forme est confus et il faut le changer à chaque extension de

- 37 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

la classe Forme. Ici, il suffit de dire :« Tu es une forme géométrique, je sais que tu peux te dessiner() et t'effacer(),
alors fais-le et occupe-toi des détails spécifiques ».

Ce qui est impressionnant dans le code de faireQuelqueChose(), c'est que tout fonctionne comme on le souhaite.
Appeler dessiner() pour un Cercle exécute une portion de code différente de celle exécutée lorsqu'on appelle
dessiner() pour un Carré ou une Ligne, mais lorsque le message dessiner() est envoyé à une Forme anonyme,
on obtient le comportement idoine basé sur le type réel de la Forme. Cela est impressionnant dans la mesure où le
compilateur Java ne sait pas à quel type d'objet il a affaire lors de la compilation du code de faireQuelqueChose().
On serait en droit de s'attendre à un appel aux versions dessiner() et effacer() de la classe de base Forme, et
non celles des classes spécifiques Cercle, Carré et Ligne. Mais quand on envoie un message à un objet, il fera ce
qu'il a à faire, même quand la généralisation est impliquée. C'est ce qu'implique le polymorphisme. Le compilateur
et le système d'exécution s'occupent des détails, et c'est tout ce que vous avez besoin de savoir, en plus de savoir
comment modéliser avec.

III-F-1 - Classes de base abstraites et interfaces

Dans une modélisation, il est souvent souhaitable qu'une classe de base ne présente qu'une interface pour ses
classes dérivées. C'est-à-dire qu'on ne souhaite pas qu'il soit possible de créer un objet de cette classe de base,
mais seulement pouvoir surtyper jusqu'à elle pour pouvoir utiliser son interface. Cela est possible en rendant cette
classe abstraite en utilisant le mot-clef abstract. Le compilateur se plaindra si une tentative est faite de créer un
objet d'une classe définie comme abstract. C'est un outil utilisé pour forcer une certaine conception.

Le mot-clef abstract est aussi utilisé pour décrire une méthode qui n'a pas encore été implémentée - comme un
panneau indiquant « voici une fonction de l'interface dont les types dérivés ont hérité, mais actuellement je n'ai
aucune implémentation pour elle ». Une méthode abstract peut seulement être créée au sein d'une classe abstract.
Quand cette classe est dérivée, cette méthode doit être implémentée, ou la classe dérivée devient abstract elle
aussi. Créer une méthode abstract permet de l'inclure dans une interface sans être obligé de fournir une portion de
code éventuellement dépourvue de sens pour cette méthode.

Le mot-clef interface pousse le concept de classe abstract un cran plus loin en évitant toute définition de fonction.
Une interface est un outil très pratique et très largement répandu, car il fournit une séparation parfaite entre l'interface
et l'implémentation. De plus, on peut combiner plusieurs interfaces, alors qu'hériter de multiples classes normales
ou abstraites est impossible.

III-G - Environnement et durée de vie des objets

Techniquement, les spécificités de la programmation orientée objet se résument au typage abstrait des données, à
l'héritage et au polymorphisme, mais d'autres particularités peuvent se révéler aussi importantes. Le reste de cette
section traite de ces particularités.

L'une des particularités les plus importantes est la façon dont les objets sont créés et détruits. Où se trouvent les
données d'un objet et comment sa durée de vie est-elle contrôlée ? Différentes philosophies existent. En C++,
qui prône que l'efficacité est le facteur le plus important, le programmeur a le choix. Pour une vitesse optimum à
l'exécution, le stockage et la durée de vie peuvent être déterminés quand le programme est écrit, en plaçant les objets
sur la pile (ces variables sont parfois appelées automatiques ou de portée) ou dans l'espace de stockage statique.
La vitesse d'allocation et de libération est dans ce cas prioritaire et leur contrôle peut être vraiment appréciable dans
certaines situations. Cependant, cela se fait aux dépens de la flexibilité, car il faut connaître la quantité exacte, la
durée de vie et le type des objets pendant qu'on écrit le programme. Si le problème à résoudre est plus général,
tel que de la modélisation assistée par ordinateur, de la gestion d'entrepôts ou du contrôle de trafic aérien, cela se
révèle beaucoup trop restrictif.

La deuxième approche consiste à créer les objets dynamiquement dans un pool de mémoire appelé le segment.
Dans cette approche, le nombre d'objets nécessaires n'est pas connu avant l'exécution, de même que leur durée de
vie ou leur type exact. Ces paramètres sont déterminés sur le coup, au moment où le programme s'exécute. Si on a
besoin d'un nouvel objet, il est simplement créé dans le segment au moment où on en a besoin. Comme le stockage

- 38 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

est géré de manière dynamique lors de l'exécution, le temps de traitement requis pour allouer de la place dans le
segment est plus important que le temps mis pour stocker sur la pile (stocker sur la pile se résume souvent à une
instruction assembleur pour déplacer le pointeur de pile vers le bas, et une autre pour le redéplacer vers le haut).
L'approche dynamique fait la supposition généralement justifiée que les objets ont tendance à être compliqués, et
que le surcoût de temps dû à la recherche d'une place de stockage et à sa libération n'aura pas d'impact significatif
sur la création d'un objet. De plus, la plus grande flexibilité qui en résulte est essentielle pour résoudre le problème
modélisé par le programme.

Une autre particularité importante est la durée de vie d'un objet. Avec les langages qui autorisent la création d'objets
dans la pile, le compilateur détermine combien de temps l'objet est amené à vivre et peut le détruire automatiquement.
Mais si l'objet est créé dans le segment, le compilateur n'a aucune idée de sa durée de vie. Dans un langage comme
le C++, il faut déterminer dans le programme quand détruire l'objet, ce qui peut mener à des fuites de mémoire si cela
n'est pas fait correctement (et c'est un problème courant en C++). Java propose une fonctionnalité appelée ramasse-
miettes (garbage collector) qui découvre automatiquement quand un objet n'est plus utilisé et le détruit. Java propose
donc un niveau plus élevé d'assurance contre les fuites de mémoire. Disposer d'un ramasse-miettes est pratique,
car cela réduit le code à écrire et, plus important, le nombre de problèmes liés à la gestion de la mémoire (qui ont
mené à l'abandon de plus d'un projet C++).

Le reste de cette section s'attarde sur des facteurs additionnels concernant l'environnement et la durée de vie des
objets.

III-G-1 - Collections et itérateurs

Si le nombre d'objets nécessaires à la résolution d'un problème est inconnu, ou combien de temps on va en avoir
besoin, on ne peut pas non plus savoir comment les stocker. Comment déterminer l'espace nécessaire pour créer
ces objets ? C'est impossible, car cette information n'est connue que lors de l'exécution.

La solution à la plupart des problèmes en conception orientée objet est simple : il suffit de créer un nouveau type
d'objet. Le nouveau type d'objets qui résout ce problème particulier contient des références aux autres objets. Bien
sûr, un tableau ferait aussi bien l'affaire. Mais il y a plus. Ce nouvel objet, appelé conteneur (ou collection, mais
la bibliothèque Java utilise ce terme dans un autre sens ; nous utiliserons donc le terme « conteneur » dans la
suite de ce livre), grandira automatiquement pour accepter tout ce qu'on place dedans. Connaître le nombre d'objets
qu'on désire stocker dans un conteneur n'est donc plus nécessaire. Il suffit de créer un objet conteneur et le laisser
s'occuper des détails.

Heureusement, les langages orientés objet décents fournissent ces conteneurs. En C++, ils font partie de
la bibliothèque standard (STL, Standard Template Library). Le Pascal Objet dispose des conteneurs dans sa
Bibliothèque de Composants Visuels (VCL, Visual Component Library). Smalltalk propose un ensemble vraiment
complet de conteneurs. Java aussi propose des conteneurs dans sa bibliothèque standard. Dans certaines
bibliothèques, un conteneur générique est jugé suffisant pour tous les besoins, et dans d'autres (Java par exemple), la
bibliothèque dispose de différents types de conteneurs suivant les besoins : des vecteurs (appelé ArrayList en Java)
pour un accès pratique à tous les éléments, des listes chaînées pour faciliter l'insertion, par exemple, on peut donc
choisir le type particulier qui convient le mieux. Les bibliothèques de conteneurs peuvent aussi inclure les ensembles,
les files, les dictionnaires, les arbres, les piles, etc.

Tous les conteneurs disposent de moyens pour y stocker des choses et les récupérer ; ce sont habituellement des
fonctions pour ajouter des éléments dans un conteneur et d'autres pour les y retrouver. Mais retrouver des éléments
peut être problématique, car une fonction de sélection unique peut se révéler trop restrictive. Comment manipuler ou
comparer un ensemble d'éléments dans le conteneur ?

La réponse à cette question prend la forme d'un itérateur, qui est un objet dont le travail est de choisir les éléments
d'un conteneur et de les présenter à l'utilisateur de l'itérateur. En tant que classe, il fournit de plus un niveau
d'abstraction supplémentaire. Cette abstraction peut être utilisée pour séparer les détails du conteneur du code qui
utilise ce conteneur. Le conteneur, via l'itérateur, est perçu comme une séquence. L'itérateur permet de parcourir cette
séquence sans se préoccuper de sa structure sous-jacente - qu'il s'agisse d'une ArrayList (vecteur), une LinkedList
(liste chaînée), une Stack (pile) ou autre. Cela permet de changer facilement la structure de données sous-jacente

- 39 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

sans perturber le code du programme. Java commença (dans les versions 1.0 et 1.1) avec un itérateur standard,
appelé Enumeration, pour toutes ses classes conteneurs. Java 2 est accompagné d'une bibliothèque de conteneurs
beaucoup plus complète qui contient entre autres un itérateur appelé Iterator bien plus puissant que l'ancienne
Enumeration.

Du point de vue du design, tout ce dont on a besoin est une séquence qui peut être manipulée pour résoudre le
problème. Si un seul type de séquence satisfaisait tous les besoins, il n'y aurait pas de raison d'en avoir de types
différents. Il y a deux raisons qui font qu'on a besoin d'un choix de conteneurs. Tout d'abord, les conteneurs fournissent
différents types d'interfaces et de comportements. Une pile a une interface et un comportement différents de ceux
d'une file, qui sont différents de ceux fournis par un ensemble ou une liste. L'un de ces conteneurs peut se révéler
plus flexible qu'un autre pour la résolution du problème considéré. Deuxièmement, les conteneurs ne sont pas d'une
même efficacité pour les mêmes opérations. Prenons le cas d'une ArrayList et d'une LinkedList. Les deux sont
de simples séquences qui peuvent avoir la même interface et comportement. Mais certaines opérations ont des
coûts radicalement différents. Accéder à des éléments au hasard dans une ArrayList est une opération qui demande
toujours le même temps, quel que soit l'élément auquel on souhaite accéder. Mais dans une LinkedList, il est coûteux
de se déplacer dans la liste pour rechercher un élément, et cela prend plus de temps pour trouver un élément qui
se situe plus loin dans la liste. Par contre, si on souhaite insérer un élément au milieu d'une séquence, c'est bien
plus efficace dans une LinkedList que dans une ArrayList. Ces opérations et d'autres ont des efficacités différentes
suivant la structure sous-jacente de la séquence. Dans la phase de conception, on peut débuter avec une LinkedList
et lorsqu'on se penche sur l'optimisation, changer pour une ArrayList. Grâce à l'abstraction fournie par les itérateurs,
on peut passer de l'une à l'autre avec un impact minime sur le code.

En définitive, un conteneur n'est qu'un espace de stockage où placer des objets. Si ce conteneur couvre tous nos
besoins, son implémentation réelle n'a pas grande importance (un concept de base pour la plupart des objets). Mais il
arrive que la différence de coûts entre une ArrayList et une LinkedList ne soit pas à négliger, suivant l'environnement
du problème et d'autres facteurs. On peut n'avoir besoin que d'un seul type de séquence. On peut même imaginer
le conteneur « parfait », qui changerait automatiquement son implémentation selon la manière dont on l'utilise.

III-G-2 - La hiérarchie de classes unique

L'une des controverses en POO devenue proéminente depuis le C++ demande si toutes les classes doivent être
finalement dérivées d'une classe de base unique. En Java (et comme dans pratiquement tous les autres langages
OO) la réponse est « oui » et le nom de cette classe de base ultime est tout simplement Object. Les bénéfices d'une
hiérarchie de classes unique sont multiples.

Tous les objets dans une hiérarchie unique ont une interface commune, ils sont donc tous du même type fondamental.
L'alternative (proposée par le C++) est qu'on ne sait pas que tout est du même type fondamental. Du point de vue de
la compatibilité ascendante, cela épouse plus le modèle du C et peut se révéler moins restrictif, mais lorsqu'on veut
programmer en tout objet il faut reconstruire sa propre hiérarchie de classes pour bénéficier des mêmes avantages
fournis par défaut par les autres langages OO. Et dans chaque nouvelle bibliothèque de classes qu'on récupère, une
interface différente et incompatible sera utilisée. Cela demande des efforts (et éventuellement l'utilisation de l'héritage
multiple) pour intégrer la nouvelle interface dans la conception. Est-ce que la « flexibilité » que le C++ fournit en vaut
réellement le coup ? Si on en a besoin - par exemple si on dispose d'un gros investissement en C - alors oui. Mais
si on démarre de zéro, d'autres alternatives telles que Java se révèlent beaucoup plus productives.

Tous les objets dans une hiérarchie de classes unique (comme celle que propose Java) sont garantis d'avoir
certaines fonctionnalités. Un certain nombre d'opérations élémentaires peuvent être effectuées sur tous les objets
du système. Une hiérarchie de classes unique, accompagnée de la création des objets dans le segment, simplifie
considérablement le passage d'arguments (l'un des sujets les plus complexes en C++).

Une hiérarchie de classes unique facilite aussi l'implémentation d'un ramasse-miettes (qui est fourni en standard
en Java). Le support nécessaire est implanté dans la classe de base, et le ramasse-miettes peut donc envoyer le
message idoine à tout objet du système. Sans une hiérarchie de classe unique et un système permettant de manipuler
un objet via une référence, il est difficile d'implémenter un ramasse-miettes.

- 40 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Comme tout objet dispose en lui d'informations dynamiques, on ne peut se retrouver avec un objet dont on ne peut
déterminer le type. Ceci est particulièrement important avec les opérations du niveau système, telles que le traitement
des exceptions, et cela permet une plus grande flexibilité dans la programmation.

III-G-3 - Bibliothèques de collections et support pour l'utilisation aisée des collections

Parce qu'un conteneur est un outil qu'on utilise fréquemment, il est logique d'avoir une bibliothèque de conteneurs
conçus de manière à être réutilisables, afin de pouvoir en prendre un et l'insérer dans le programme. Java fournit
une telle bibliothèque, qui devrait satisfaire tous les besoins.

III-G-3-a - Transtypages descendants vs patrons génériques

Pour rendre ces conteneurs réutilisables, ils stockent le type universel en Java précédemment mentionné : Object.
La hiérarchie de classe unique implique que tout est un Object, un conteneur stockant des Objects peut donc stocker
n'importe quoi. Cela rend les conteneurs aisément réutilisables.

Pour utiliser ces conteneurs, il suffit d'y ajouter des références à des objets, et les redemander plus tard. Mais comme
le conteneur ne stocke que des Objects, quand une référence à un objet est ajoutée dans le conteneur, il subit un
transtypage ascendant en Object, perdant alors son identité. Quand il est recherché par la suite, on récupère une
référence à un Object, et non une référence au type qu'on a inséré. Comment le récupérer et retrouver l'interface
de l'objet qu'on a stocké dans le conteneur ?

On assiste ici aussi à un transtypage, mais cette fois-ci il ne remonte pas dans la hiérarchie de classe à un type
plus général, mais descend dans la hiérarchie jusqu'à un type plus spécifique, c'est un transtypage descendant ou
spécialisation, ou sous-typage. Avec la généralisation, on sait par exemple qu'un Cercle est un type de Forme, et
que le transtypage est donc sans danger ; mais on ne sait pas qu'un Object est aussi un Cercle ou une Forme, il
est donc rarement sûr d'appliquer une spécialisation à moins de savoir exactement à quoi on a affaire.

Ce n'est pas trop dangereux cependant, car si une spécialisation est tentée jusqu'à un type incompatible le système
d'exécution générera une erreur appelée exception, qui sera décrite plus loin. Quand une référence d'objet est
rapatriée d'un conteneur, il faut donc un moyen de se rappeler exactement son type afin de pouvoir le spécialiser
correctement.

La spécialisation et les contrôles à l'exécution génèrent un surcoût de temps pour le programme, et des efforts
supplémentaires de la part du programmeur. Il semblerait plus logique de créer le conteneur de façon à ce qu'il
connaisse le type de l'objet stocké, éliminant du coup la spécialisation et la possibilité d'erreur. La solution est fournie
par les types paramétrés, qui sont des classes que le compilateur peut personnaliser pour les faire fonctionner avec
des types particuliers. Par exemple, avec un conteneur paramétré, le compilateur peut personnaliser ce conteneur
de façon à ce qu'il n'accepte que des Formes et ne renvoie que des Formes.

Les types paramétrés sont importants en C++, en particulier parce que le C++ ne dispose pas d'une hiérarchie de
classe unique. En C++, le mot-clef qui implémente les types paramétrés est « template ». Java ne propose pas
actuellement de types paramétrés, car c'est possible de les simuler - bien que difficilement - via la hiérarchie de
classes unique. Une solution de types paramétrés basée sur la syntaxe des templates C++ est actuellement en cours
de proposition.

III-G-4 - Le dilemme du nettoyage : qui en est responsable ?

Chaque objet requiert des ressources, en particulier de la mémoire. Quand un objet n'est plus utilisé, il doit être
nettoyé afin de rendre ces ressources pour les réutiliser. Dans la programmation de situations simples, la question
de savoir comment un objet est libéré n'est pas trop compliquée : il suffit de créer l'objet, l'utiliser aussi longtemps que
désiré, et ensuite le détruire. Il n'est pas rare par contre de se trouver dans des situations beaucoup plus complexes.

- 41 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Supposons qu'on veuille concevoir un système pour gérer le trafic aérien d'un aéroport (ou pour gérer des caisses
dans un entrepôt, ou un système de location de cassettes, ou un chenil pour animaux). Cela semble simple de prime
abord : créer un conteneur pour stocker les avions, puis créer un nouvel avion et le placer dans le conteneur pour
chaque avion qui entre dans la zone de contrôle du trafic aérien. Pour le nettoyage, il suffit de détruire l'objet avion
correspondant lorsqu'un avion quitte la zone.

Mais supposons qu'une autre partie du système s'occupe d'enregistrer des informations à propos des avions, ces
données ne requérant pas autant d'attention que la fonction principale de contrôle. Il s'agit peut-être d'enregistrer les
plans de vol de tous les petits avions quittant l'aéroport. On dispose donc d'un second conteneur des petits avions, et
quand on crée un objet avion on doit aussi le stocker dans le deuxième conteneur si c'est un petit avion. Une tâche
de fond s'occupe de traiter les objets de ce conteneur durant les moments d'inactivité du système.

Le problème est maintenant plus compliqué : comment savoir quand détruire les objets ? Quand on en a fini avec
un objet, une autre partie du système peut ne pas en avoir terminé avec. Ce genre de problème arrive dans un
grand nombre de situations, et dans les systèmes de programmation (comme le C++) où les objets doivent être
explicitement détruits cela peut devenir relativement complexe.

Avec Java, le ramasse-miettes est conçu pour s'occuper du problème de la libération de la mémoire (bien que cela
n'inclut pas les autres aspects du nettoyage de l'objet). Le ramasse-miettes « sait » quand un objet n'est plus utilisé, et
il libère automatiquement la mémoire utilisée par cet objet. Ceci (associé avec le fait que tous les objets sont dérivés
de la classe de base fondamentale Object et que les objets sont créés dans le segment) rend la programmation Java
plus simple que la programmation C++. Il y a beaucoup moins de décisions à prendre et d'obstacles à surmonter.

III-G-4-a - Ramasse-miettes vs efficacité et flexibilité

Si cette idée est si bonne, pourquoi le C++ n'intègre-t-il pas ce mécanisme ? Bien sûr, car il y a un prix à payer pour
cette facilité de programmation, et ce surcoût se traduit par du temps système. Comme on l'a vu, en C++ on peut créer
des objets dans la pile et dans ce cas ils sont automatiquement nettoyés (mais dans ce cas on n'a pas la flexibilité de
créer autant d'objets que voulu lors de l'exécution). Créer des objets dans la pile est la façon la plus efficace d'allouer
de l'espace pour des objets et de libérer cet espace. Créer des objets dans le segment est bien plus coûteux. Hériter
de la même classe de base et rendre tous les appels de fonctions polymorphes prélèvent aussi un tribut. Mais le
ramasse-miettes est un problème à part, car on ne sait pas quand il va démarrer ou combien de temps il va prendre.
Cela veut dire qu'il y a une inconsistance dans le temps d'exécution de programmes Java ; on ne peut donc l'utiliser
dans certaines situations, comme celles où le temps d'exécution d'un programme est critique (appelés programmes
en temps réel, bien que tous les problèmes de programmation en temps réel ne soient pas aussi astreignants).

Les concepteurs du langage C++, en voulant amadouer les programmeurs C, ne voulurent pas ajouter de nouvelles
fonctionnalités au langage qui puissent impacter la vitesse ou défavoriser l'utilisation du C++ dans des situations
où le C se serait révélé acceptable. Cet objectif a été atteint, mais au prix d'une plus grande complexité lorsqu'on
programme en C++. Java est plus simple que le C++, mais la contrepartie en est l'efficacité et quelquefois son champ
d'applications. Pour un grand nombre de problèmes de programmation cependant, Java constitue le meilleur choix.

III-H - Traitement des exceptions : gérer les erreurs

Depuis les débuts des langages de programmation, le traitement des erreurs s'est révélé l'un des problèmes les plus
ardus. Parce qu'il est difficile de concevoir un bon mécanisme de gestion des erreurs, beaucoup de langages ignorent
ce problème et le délèguent aux concepteurs de bibliothèques qui fournissent des mécanismes qui fonctionnent dans
beaucoup de situations, mais peuvent être facilement contournés, généralement en les ignorant. L'une des faiblesses
de la plupart des mécanismes d'erreur est qu'ils reposent sur la vigilance du programmeur à suivre des conventions
non imposées par le langage. Si le programmeur n'est pas assez vigilant - ce qui est souvent le cas s'il est pressé
- ces mécanismes peuvent facilement être oubliés.

Le système des exceptions pour gérer les erreurs se situe au niveau du langage de programmation et parfois même
au niveau du système d'exploitation. Une exception est un objet qui est « émis » depuis l'endroit où l'erreur est
apparue et peut être intercepté par un gestionnaire d'exception conçu pour gérer ce type particulier d'erreur. C'est

- 42 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

comme si la gestion des exceptions était un chemin d'exécution parallèle à suivre quand les choses se gâtent. Et
parce qu'elle utilise un chemin d'exécution séparé, elle n'interfère pas avec le code s'exécutant normalement. Cela
rend le code plus simple à écrire, car on n'a pas à vérifier constamment si des erreurs sont survenues. De plus, une
exception émise n'est pas comme une valeur de retour d'une fonction signalant une erreur ou un drapeau positionné
par une fonction pour indiquer une erreur - ils peuvent être ignorés. Une exception ne peut pas être ignorée, on a donc
l'assurance qu'elle sera traitée quelque part. Enfin, les exceptions permettent de revenir d'une mauvaise situation
assez facilement. Plutôt que terminer un programme, il est souvent possible de remettre les choses en place et de
restaurer son exécution, ce qui produit des programmes plus robustes.

Le traitement des exceptions de Java se distingue parmi les langages de programmes, car en Java le traitement
des exceptions a été intégré depuis le début et on est forcé de l'utiliser. Si le code produit ne gère pas correctement
les exceptions, le compilateur générera des messages d'erreur. Cette consistance rend la gestion des erreurs bien
plus aisée.

Il est bon de noter que le traitement des exceptions n'est pas une caractéristique orientée objet, bien que dans les
langages OO une exception soit normalement représentée par un objet. Le traitement des exceptions existait avant
les langages orientés objet.

III-I - Multithreading

L'un des concepts fondamentaux dans la programmation des ordinateurs est l'idée de traiter plus d'une tâche à la fois.
Beaucoup de problèmes requièrent que le programme soit capable de stopper ce qu'il est en train de faire, traite un
autre problème puis retourne à sa tâche principale. Le problème a été abordé de beaucoup de manières différentes.
Au début, les programmeurs ayant des connaissances sur le fonctionnement de bas niveau de la machine écrivaient
des routines d'interruption de service et l'interruption de la tâche principale était initiée par une interruption matérielle.
Bien que cela fonctionne correctement, c'était difficile et non portable, et cela rendait le portage d'un programme sur
un nouveau type de machine lent et cher.

Quelquefois les interruptions sont nécessaires pour gérer les tâches critiques, mais il existe une large classe de
problèmes dans lesquels on tente juste de partitionner le problème en parties séparées et indépendantes afin que le
programme soit plus réactif. Dans un programme, ces parties séparées sont appelées threads et le concept général
est appelé multithreading. Un exemple classique de multithreading est l'interface utilisateur. En utilisant les threads,
un utilisateur peut appuyer sur un bouton et obtenir une réponse plus rapide que s'il devait attendre que le programme
termine sa tâche courante.

Généralement, les threads sont juste une façon d'allouer le temps d'un seul processeur. Mais si le système
d'exploitation supporte les multiprocesseurs, chaque thread peut être assigné à un processeur différent et ils peuvent
réellement s'exécuter en parallèle. L'une des caractéristiques intéressantes du multithreading au niveau du langage
est que le programmeur n'a pas besoin de se préoccuper du nombre de processeurs. Le programme est divisé
logiquement en threads et si la machine dispose de plusieurs processeurs, le programme tourne plus vite, sans
aucun ajustement.

Tout ceci pourrait faire croire que le multithreading est simple. Il y a toutefois un point d'achoppement : les ressources
partagées. Un problème se pose si plus d'un thread s'exécutant veut accéder à la même ressource. Par exemple,
deux tâches ne peuvent envoyer simultanément de l'information à une imprimante. Pour résoudre ce problème, les
ressources pouvant être partagées, comme l'imprimante, doivent être verrouillées avant d'être utilisées. Un thread
verrouille donc une ressource, accomplit ce qu'il a à faire, et ensuite relâche le verrou posé afin que quelqu'un d'autre
puisse utiliser cette ressource.

III-J - Persistance

Quand un objet est créé, il existe aussi longtemps qu'on en a besoin, mais en aucun cas il ne continue d'exister après
que le programme se termine. Bien que cela semble logique de prime abord, il existe des situations où il serait très
pratique si un objet pouvait continuer d'exister et garder son information même quand le programme ne tourne plus.
À l'exécution suivante du programme, l'objet serait toujours là et il aurait la même information dont il disposait dans

- 43 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

la session précédente. Bien sûr, on peut obtenir ce comportement en écrivant l'information dans un fichier ou une
base de données, mais dans l'esprit du tout objet, il serait pratique d'être capable de déclarer un objet persistant et
que tous les détails soient pris en charge.

Java fournit un support pour la « persistance légère », qui signifie qu'on peut facilement stocker des objets sur disque
et les récupérer plus tard. La raison pour laquelle on parle de « persistance légère » est qu'on est toujours obligé
de faire des appels explicites pour le stockage et la récupération. De plus, JavaSpaces (décrit au titre XVII) fournit
un type de stockage persistant des objets. Un support plus complet de la persistance peut être amené à apparaître
dans de futures versions.

III-K - Java et l'Internet

Java n'étant qu'un autre langage de programmation, on peut se demander pourquoi il est si important et pourquoi
il est présenté comme une étape révolutionnaire de la programmation. La réponse n'est pas immédiate si on se
place du point de vue de la programmation classique. Bien que Java soit très pratique pour résoudre des problèmes
traditionnels, il est aussi important, car il permet de résoudre des problèmes liés au web.

III-K-1 - Qu'est-ce que le Web ?

Le Web peut sembler un peu mystérieux au début, avec tout ce vocabulaire de « surf », « page personnelle », etc. Il
y a même eu une réaction importante contre cette « Internet-mania », se questionnant sur la valeur économique et
les revenus d'un tel engouement. Il peut être utile de revenir en arrière et voir de quoi il retourne, mais auparavant il
faut comprendre le modèle client/serveur, un autre aspect de l'informatique relativement confus.

III-K-1-a - Le concept Client/Serveur

L'idée primitive d'un système client/serveur est qu'on dispose d'un dépôt centralisé de l'information - souvent dans une
base de données - qu'on veut distribuer à un ensemble de personnes ou de machines. L'un des concepts majeurs du
client/serveur est que le dépôt d'informations est centralisé afin qu'elles puissent être changées facilement et que ces
changements se propagent jusqu'aux consommateurs de ces informations. Pris ensemble, le dépôt d'informations,
le programme qui distribue l'information et la (les) machine(s) où résident informations et programme sont appelés
le serveur. Le programme qui réside sur la machine distante, communique avec le serveur, récupère l'information, la
traite et l'affiche sur la machine distante est appelé le client.

Le concept de base du client/serveur n'est donc pas si compliqué. Les problèmes surviennent, car un seul serveur
doit servir de nombreux clients à la fois. Généralement, un système de gestion de base de données est impliqué afin
que le concepteur répartisse les informations dans des tables pour une utilisation optimale. De plus, les systèmes
permettent généralement aux utilisateurs d'ajouter de nouvelles informations au serveur. Cela veut dire qu'ils doivent
s'assurer que les nouvelles données d'un client ne contredisent pas les nouvelles données d'un autre client, ou que
ces nouvelles données ne soient pas perdues pendant leur inscription dans la base de données (cela fait appel aux
transactions). Comme les programmes d'application client changent, ils doivent être créés, débogués, et installés
sur les machines clientes, ce qui se révèle plus compliqué et onéreux que ce à quoi on pourrait s'attendre. C'est
particulièrement problématique dans les environnements hétérogènes comprenant différents types de matériels et
de systèmes d'exploitation. Enfin, se pose toujours le problème des performances : on peut se retrouver avec des
centaines de clients exécutant des requêtes en même temps, et donc un petit délai multiplié par le nombre de clients
peut être particulièrement pénalisant. Pour minimiser les temps de latence, les programmeurs travaillent dur pour
réduire la charge de travail des tâches incriminées, parfois jusque sur les machines clientes, mais aussi sur d'autres
machines du site serveur, utilisant ce qu'on appelle le middleware (le middleware est aussi utilisé pour améliorer
la maintenabilité).

L'idée relativement simple de distribuer de l'information aux gens a de si nombreux niveaux de complexité dans son
implémentation que le problème peut sembler désespérément insoluble. Et pourtant il est crucial : le client/serveur
compte pour environ la moitié des activités de programmation. On le retrouve pour tout ce qui va des transactions de
cartes de crédit à la distribution de n'importe quel type de données - économiques, scientifiques, gouvernementales,
il suffit de choisir. Dans le passé, on en est arrivé à des solutions particulières aux problèmes particuliers, obligeant

- 44 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

à réinventer une solution à chaque fois. Elles étaient difficiles à créer et à utiliser, et l'utilisateur devait apprendre une
nouvelle interface pour chacune. Le problème devait être repris dans son ensemble.

III-K-1-b - Le Web en tant que serveur géant

Le Web est en fait un système client/serveur géant. C'est encore pire que ça, puisque tous les serveurs et les clients
coexistent en même temps sur un seul réseau. Vous n'avez pas besoin de le savoir d'ailleurs, car tout ce dont vous
vous souciez est de vous connecter et d'interagir avec un serveur à la fois (même si vous devez parcourir le monde
pour trouver le bon serveur).

Initialement, c'était un processus à une étape. On faisait une requête à un serveur qui renvoyait un fichier, que le
logiciel (i.e. le client) interprétait en le formatant sur la machine locale. Mais les gens en voulurent plus : afficher des
pages d'un serveur ne leur suffisait plus. Ils voulaient bénéficier de toutes les fonctionnalités du client/serveur afin
que le client puisse renvoyer des informations au serveur, par exemple pour faire des requêtes précises dans la base
de données, ajouter de nouvelles informations au serveur, ou passer des commandes (ce qui nécessitait plus de
sécurité que ce que le système primitif offrait). Nous assistons à ces changements dans le développement du Web.

Le browser Web fut un grand bond en avant en avançant le concept qu'une information pouvait être affichée
indifféremment sur n'importe quel ordinateur. Cependant, les browsers étaient relativement primitifs et ne
remplissaient pas toutes les demandes des utilisateurs. Ils n'étaient pas particulièrement interactifs, et avaient
tendance à saturer le serveur et l'Internet, car à chaque fois qu'on avait besoin de faire quelque chose qui requérait
un traitement il fallait renvoyer les informations au serveur pour que celui-ci les traite. Cela pouvait prendre plusieurs
secondes ou minutes pour finalement se rendre compte qu'on avait fait une faute de frappe dans la requête. Comme
le browser n'était qu'un afficheur, il ne pouvait pas effectuer le moindre traitement (d'un autre côté, cela était beaucoup
plus sûr, car il ne pouvait pas de ce fait exécuter sur la machine locale de programmes contenant des bogues ou
des virus).

Pour résoudre ce problème, différentes solutions ont été approchées. En commençant par les standards graphiques
qui ont été améliorés pour mettre des animations et de la vidéo dans les browsers. Le reste du problème ne peut
être résolu qu'en incorporant la possibilité d'exécuter des programmes sur le client, dans le browser. C'est ce qu'on
appelle la programmation côté client.

III-K-2 - La programmation côté client

Le concept initial du Web (serveur-browser) fournissait un contenu interactif, mais l'interactivité était uniquement le
fait du serveur. Le serveur produisait des pages statiques pour le browser client, qui ne faisait que les interpréter
et les afficher. Le HTML de base contient des mécanismes simples pour récupérer de l'information : des boîtes de
texte, des cases à cocher, des listes à options et des listes de choix, ainsi qu'un bouton permettant de réinitialiser
le contenu du formulaire ou d'envoyer les données du formulaire au serveur. Cette soumission de données passe
par CGI (Common Gateway Interface), un mécanisme fourni par tous les serveurs web. Le texte de la soumission
indique à CGI quoi faire avec ces données. L'action la plus commune consiste à exécuter un programme situé sur
le serveur dans un répertoire typiquement appelé« cgi-bin » (si vous regardez l'adresse en haut de votre browser
quand vous appuyez sur un bouton dans une page web, vous verrez certainement « cgi-bin » quelque part au milieu
de tous les caractères). Ces programmes peuvent être écrits dans la plupart des langages. Perl est souvent préféré,
car il a été conçu pour la manipulation de texte et est interprété, et peut donc être installé sur n'importe quel serveur
sans tenir compte du matériel ou du système d'exploitation.

Beaucoup de sites Web populaires sont aujourd'hui bâtis strictement sur CGI, et de fait on peut faire ce qu'on
veut avec. Cependant, les sites web bâtis sur des programmes CGI peuvent rapidement devenir ingérables et trop
compliqués à maintenir, et se pose de plus le problème du temps de réponse. La réponse d'un programme CGI
dépend de la quantité de données à envoyer, ainsi que de la charge du serveur et de l'Internet (de plus, le démarrage
d'un programme CGI a tendance à être long). Les concepteurs du Web n'avaient pas prévu que la bande passante
serait trop petite pour le type d'applications que les gens développèrent. Par exemple, tout type de graphisme
dynamique est impossible à réaliser correctement, car un fichier GIF doit être créé et transféré du serveur au client
pour chaque version de ce graphe. Et vous avez certainement déjà fait l'expérience de quelque chose d'aussi simple

- 45 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

que la validation de données sur un formulaire. Vous appuyez sur le bouton « submit » d'une page, les données sont
envoyées sur le serveur, le serveur démarre le programme CGI qui y découvre une erreur, formate une page HTML
vous informant de votre erreur et vous la renvoie ; vous devez alors revenir en arrière d'une page et réessayer. Non
seulement c'est lent et frustrant, mais c'est inélégant.

La solution est la programmation côté client. La plupart des machines qui font tourner des browsers Web sont des
ordinateurs puissants capables de beaucoup de choses, et avec l'approche originale du HTML statique, elles ne font
qu'attendre que le serveur leur envoie parcimonieusement la page suivante. La programmation côté client implique
que le browser Web prenne en charge la partie du travail qu'il est capable de traiter, avec comme résultat pour
l'utilisateur une interactivité et une vitesse inégalées.

Les problèmes de la programmation côté client ne sont guère différents des discussions de la programmation en
général. Les paramètres sont quasiment les mêmes, mais la plateforme est différente : un browser Web est comme
un système d'exploitation limité. Finalement, on est toujours obligé de programmer, et ceci explique le nombre de
problèmes rencontrés dans la programmation côté client. Le reste de cette section présente les différentes approches
de la programmation côté client.

III-K-2-a - Les plug-ins

L'une des plus importantes avancées en termes de programmation orientée client a été le développement du plug-in.
C'est une façon pour le programmeur d'ajouter de nouvelles fonctionnalités au browser en téléchargeant une partie de
logiciel qui s'enfiche à l'endroit adéquat dans le browser. Il indique au browser : « à partir de maintenant tu peux réaliser
cette nouvelle opération » (on n'a besoin de télécharger le plug-in qu'une seule fois). De nouveaux comportements
puissants sont donc ajoutés au browser via les plug-ins, mais écrire un plug-in n'est pas une tâche facile, et ce n'est
pas quelque chose qu'on souhaiterait faire juste pour bâtir un site Web particulier. La valeur d'un plug-in pour la
programmation côté client est qu'il permet à un programmeur expérimenté de développer un nouveau langage et
d'intégrer ce langage au browser sans la permission du distributeur du browser. Ainsi, les plug-ins fournissent une
« porte dérobée » qui permet la création de nouveaux langages de programmation côté client (bien que tous les
langages ne soient pas implémentés en tant que plug-ins).

III-K-2-b - Les langages de script

Les plug-ins ont déclenché une explosion de langages de script. Avec un langage de script, du code source est
intégré directement dans la page HTML, et le plug-in qui interprète ce langage est automatiquement activé quand
le page HTML est affichée. Les langages de script tendent à être relativement aisés à comprendre ; et parce qu'ils
sont du texte faisant partie de la page HTML, ils se chargent très rapidement dans la même requête nécessaire pour
se procurer la page auprès du serveur. La contrepartie en est que le code est visible pour tout le monde (qui peut
donc le voler). Mais généralement on ne fait pas des choses extraordinairement sophistiquées avec les langages de
script et ce n'est donc pas trop pénalisant.

Ceci montre que les langages de script utilisés dans les browsers Web sont vraiment spécifiques à certains types
de problèmes, principalement la création d'interfaces utilisateurs plus riches et attrayantes. Cependant, un langage
de script permet de résoudre 80 pour cent des problèmes rencontrés dans la programmation côté client. La plupart
de vos problèmes devraient se trouver parmi ces 80 pour cent, et puisque les langages de script sont plus faciles à
mettre en œuvre et permettent un développement plus rapide, vous devriez d'abord vérifier si un langage de script ne
vous suffirait pas avant de vous lancer dans une solution plus complexe telle que la programmation Java ou ActiveX.

Les langages de script les plus répandus parmi les browsers sont JavaScript (qui n'a rien à voir avec Java ; le nom a
été choisi uniquement pour bénéficier de l'engouement marketing pour Java du moment), VBScript (qui ressemble à
Visual Basic), et Tcl/Tk, qui vient du fameux langage de construction d'interfaces graphiques. Il y en a d'autres bien
sûr, et sans doute encore plus en développement.

JavaScript est certainement le plus commun d'entre eux. Il est présent dès l'origine dans Netscape Navigator et
Microsoft Internet Explorer (IE). De plus, il y a certainement plus de livres disponibles sur JavaScript que sur les
autres langages, et certains outils créent automatiquement des pages utilisant JavaScript. Cependant, si vous parlez

- 46 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

couramment Visual Basic ou Tcl/Tk, vous serez certainement plus productif en utilisant ces langages qu'en en
apprenant un nouveau (vous aurez déjà largement de quoi faire avec les problèmes soulevés par le Web).

III-K-2-c - Java

Si un langage de script peut résoudre 80 pour cent des problèmes de la programmation côté client, qu'en est-il
des 20 pour cent restants ? La solution la plus populaire aujourd'hui est Java. C'est non seulement un langage
de programmation puissant conçu pour être sûr, interplateforme et international, mais Java est continuellement
étendu pour fournir un langage proposant des caractéristiques et des bibliothèques permettant de gérer de manière
élégante des problèmes traditionnellement complexes dans les langages de programmation classiques tels que le
multithreading, les accès aux bases de données, la programmation réseau, l'informatique répartie Java permet la
programmation côté client via les applets.

Une applet est un miniprogramme qui ne tourne que dans un browser Web. L'applet est téléchargée automatiquement
en tant que partie d'une page Web (comme une image est automatiquement téléchargée). Quand l'applet est activée
elle exécute un programme. Là se trouve la beauté de la chose : cela vous permet de distribuer le logiciel client à partir
du serveur au moment où l'utilisateur en a besoin et pas avant. L'utilisateur récupère toujours la dernière version en
date du logiciel et sans avoir besoin de le réinstaller. De par la conception même de Java, le programmeur n'a besoin
de créer qu'un seul programme, et ce programme tournera automatiquement sur tous les browsers disposant d'un
interpréteur interne (ce qui inclut la grande majorité des machines). Puisque Java est un langage de programmation
complet, on peut déporter une grande partie des traitements sur le client avant et après avoir envoyé les requêtes
au serveur. Par exemple, une requête comportant une erreur dans une date ou utilisant un mauvais paramètre n'a
plus besoin d'être envoyée sur Internet pour se voir refusée par le serveur ; un client peut très bien aussi s'occuper
de gérer l'affichage d'un nouveau point sur un graphe plutôt que d'attendre que le serveur ne s'en occupe, crée une
nouvelle image et l'envoie au client. On gagne ainsi non seulement en vitesse et confort d'utilisation, mais le trafic
engendré sur le réseau et la charge résultante sur les serveurs peut être réduite, ce qui est bénéfique pour l'Internet
dans son ensemble.

L'un des avantages qu'une applet Java a sur un programme écrit dans un langage de script est qu'il est fourni sous
une forme précompilée, et donc le code source n'est pas disponible pour le client. D'un autre côté, une applet Java
peut être rétroingéniérée sans trop de problèmes, mais cacher son code n'est pas souvent une priorité absolue. Deux
autres facteurs peuvent être importants. Comme vous le verrez plus tard dans ce livre, une applet Java compilée peut
comprendre plusieurs modules et nécessiter plusieurs accès au serveur pour être téléchargée (à partir de Java 1.1,
cela est minimisé par les archives Java ou fichiers JAR, qui permettent de paqueter tous les modules requis ensemble
dans un format compressé pour un téléchargement unique). Un programme scripté sera juste inséré dans le texte de
la page Web (et sera généralement plus petit et réduira le nombre d'accès au serveur). Cela peut être important pour
votre site Web. Un autre facteur à prendre en compte est la courbe d'apprentissage. Indépendamment de tout ce que
vous avez pu entendre, Java n'est pas un langage trivial et facile à apprendre. Si vous avez l'habitude de programmer
en Visual Basic, passer à VBScript sera beaucoup plus rapide et comme cela permet de résoudre la majorité des
problèmes typiques du client/serveur, il pourrait être difficile de justifier l'investissement de l'apprentissage de Java.
Si vous êtes familier avec un langage de script, vous serez certainement gagnant en vous tournant vers JavaScript
ou VBScript avant Java, car ils peuvent certainement combler vos besoins et vous serez plus productif plus tôt.

III-K-2-d - ActiveX

À un certain degré, le compétiteur de Java est ActiveX de Microsoft, bien qu'il s'appuie sur une approche radicalement
différente. ActiveX était au départ une solution disponible uniquement sur Windows, bien qu'il soit actuellement
développé par un consortium indépendant pour devenir interplateforme. Le concept d'ActiveX clame : « si votre
programme se connecte à son environnement de cette façon, il peut être inséré dans une page Web et exécuté par
un browser qui supporte ActiveX » (IE supporte ActiveX en natif et Netscape utilise un plug-in). Ainsi, ActiveX ne vous
restreint pas à un langage particulier. Si par exemple vous êtes un programmeur Windows expérimenté utilisant un
langage tel que le C++, Visual Basic ou Delphi de Borland, vous pouvez créer des composants ActiveX sans avoir à
tout réapprendre. ActiveX fournit aussi un mécanisme pour la réutilisation de code dans les pages Web.

- 47 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

III-K-2-e - La sécurité

Le téléchargement automatique et l'exécution de programmes sur Internet ressemblent au rêve d'un concepteur de
virus. ActiveX en particulier pose la question épineuse de la sécurité dans la programmation côté client. Un simple
clic sur un site Web peut déclencher le téléchargement d'un certain nombre de fichiers en même temps que la
page HTML : des images, du code scripté, du code Java compilé, et des composants ActiveX. Certains d'entre eux
sont sans importance : les images ne peuvent causer de dommages, et les langages de script sont généralement
limités dans les opérations qu'ils sont capables de faire. Java a été conçu pour exécuter ses applets à l'intérieur d'un
périmètre de sécurité (appelé bac à sable), qui l'empêche d'aller écrire sur le disque ou d'accéder à la mémoire en
dehors de ce périmètre de sécurité.

ActiveX se trouve à l'opposé du spectre. Programmer avec ActiveX est comme programmer sous Windows - on peut
faire ce qu'on veut. Donc un composant ActiveX téléchargé en même temps qu'une page Web peut causer bien des
dégâts aux fichiers du disque. Bien sûr, les programmes téléchargés et exécutés en dehors du browser présentent
les mêmes risques. Les virus téléchargés depuis les BBS ont pendant longtemps été un problème, mais la vitesse
obtenue sur Internet accroît encore les difficultés.

La solution semble être les « signatures digitales », où le code est vérifié pour montrer qui est l'auteur. L'idée est
basée sur le fait qu'un virus se propage parce que son concepteur peut rester anonyme, et si cet anonymat lui est
retiré, l'individu devient responsable de ses actions. Mais si le programme contient un bogue fatal bien que non
intentionnel cela pose toujours problème.

L'approche de Java est de prévenir ces problèmes via le périmètre de sécurité. L'interpréteur Java du browser Web
examine l'applet pendant son chargement pour y détecter les instructions interdites. En particulier, les applets ne
peuvent écrire sur le disque ou effacer des fichiers (ce que font la plupart des virus). Les applets sont généralement
considérées comme sûres ; et comme ceci est essentiel pour bénéficier d'un système client/serveur fiable, les bogues
découverts dans Java permettant la création de virus sont très rapidement corrigés (il est bon de noter que le browser
renforce ces restrictions de sécurité, et que certains d'entre eux permettent de sélectionner différents niveaux de
sécurité afin de permettre différents niveaux d'accès au système).

On pourrait s'interroger sur cette restriction draconienne contre les accès en écriture sur le disque local. Par exemple,
on pourrait vouloir construire une base de données locale ou sauvegarder des données pour un usage futur en mode
déconnecté. La vision initiale obligeait tout le monde à se connecter pour réaliser la moindre opération, mais on s'est
vite rendu compte que cela était impraticable. La solution a été trouvée avec les « applets signées » qui utilisent le
chiffrement avec une clef publique pour vérifier qu'une applet provient bien de là où elle dit venir. Une applet signée
peut toujours endommager vos données et votre ordinateur, mais on en revient à la théorie selon laquelle la perte de
l'anonymat rend le créateur de l'applet responsable de ses actes, il ne fera donc rien de préjudiciable. Java fournit
un environnement pour les signatures digitales afin de permettre à une applet de sortir du périmètre de sécurité si
besoin est.

Les signatures digitales ont toutefois oublié un paramètre important, qui est la vitesse à laquelle les gens bougent
sur Internet. Si on télécharge un programme bogué et qu'il accomplit ses méfaits, combien de temps se passera-t-il
avant que les dommages ne soient découverts ? Cela peut se compter en jours ou en semaines. Et alors, comment
retrouver le programme qui les a causés ? Et en quoi cela vous aidera à ce point ?

Le Web est la solution la plus générique au problème du client/serveur, il est donc logique de vouloir appliquer la même
technologie pour résoudre ceux liés au client/serveur à l'intérieur d'une entreprise. Avec l'approche traditionnelle du
client/serveur se pose le problème de l'hétérogénéité du parc de clients, de même que les difficultés pour installer les
nouveaux logiciels clients. Ces problèmes sont résolus par les browsers Web et la programmation côté client. Quand
la technologie du Web est utilisée dans le système d'information d'une entreprise, on s'y réfère en tant qu'intranet. Les
intranets fournissent une plus grande sécurité qu'Internet puisqu'on peut contrôler les accès physiques aux serveurs
à l'intérieur de l'entreprise. En termes d'apprentissage, il semblerait qu'une fois que les utilisateurs se sont familiarisés
avec le concept d'un browser il leur est plus facile de gérer les différences de conception entre les pages et applets,
et le coût d'apprentissage de nouveaux systèmes semble se réduire.

- 48 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Le problème de la sécurité nous mène à l'une des divisions qui semblent se former automatiquement dans le monde
de la programmation côté client. Si un programme est distribué sur Internet, on ne sait pas sur quelle plateforme il va
tourner et il faut être particulièrement vigilant pour ne pas diffuser du code bogué. Il faut une solution multiplateforme
et sûre, comme un langage de script ou Java.

Dans le cas d'un intranet, les contraintes peuvent être complètement différentes. Le temps passé à installer les
nouvelles versions est la raison principale qui pousse à passer aux browsers, car les mises à jour sont invisibles et
automatiques. Il n'est pas rare que tous les clients soient des plateformes Wintel (Intel/Windows). Dans un intranet,
on est responsable de la qualité du code produit et on peut corriger les bogues quand ils sont découverts. De plus, on
dispose du code utilisé dans une approche plus traditionnelle du client/serveur où il fallait installer physiquement le
client à chaque mise à jour du logiciel. Dans le cas d'un tel intranet, l'approche la plus raisonnable consiste à choisir
la solution qui permettra de réutiliser le code existant plutôt que de repartir de zéro dans un nouveau langage.

Quand on est confronté au problème de la programmation côté client, la meilleure chose à faire est une analyse
coûts-bénéfices. Il faut prendre en compte les contraintes du problème, et la solution qui serait la plus rapide à mettre
en œuvre. En effet, comme la programmation côté client reste de la programmation, c'est toujours une bonne idée
de choisir l'approche permettant un développement rapide.

III-K-3 - La programmation côté serveur

Toute cette discussion a passé sous silence la programmation côté serveur. Que se passe-t-il lorsqu'un serveur reçoit
une requête ? La plupart du temps cette requête est simplement « envoie-moi ce fichier ». Le browser interprète
alors ce fichier d'une manière particulière : comme une page HTML, une image graphique, une applet Java, un
programme script, etc. Une requête plus compliquée à un serveur implique généralement une transaction vers une
base de données. Un scénario classique consiste en une requête complexe de recherche d'enregistrements dans
une base de données que le serveur formate dans une page HTML et renvoie comme résultat (bien sûr, si le client
est « intelligent » via Java ou un langage de script, la phase de formatage peut être réalisée par le client et le
serveur n'aura qu'à envoyer les données brutes, ce qui allégera la charge et le trafic engendré). Ou alors un client
peut vouloir s'enregistrer dans une base de données quand il joint un groupe ou envoie une commande, ce qui
implique des changements dans la base de données. Ces requêtes doivent être traitées par du code s'exécutant sur
le serveur, c'est ce qu'on appelle la programmation côté serveur. Traditionnellement, la programmation côté serveur
s'est appuyée sur Perl et les scripts CGI, mais des systèmes plus sophistiqués sont en train de voir le jour. Cela
inclut des serveurs Web écrits en Java qui permettent de réaliser toute la programmation côté serveur en Java en
écrivant ce qu'on appelle des servlets. Les servlets et leur progéniture, les JSP, sont les deux raisons principales qui
poussent les entreprises qui développent un site Web à se tourner vers Java, en particulier parce qu'ils éliminent les
problèmes liés aux différences de capacité des browsers.

III-K-4 - Une scène séparée : les applications

La plupart de la publicité faite autour de Java se référait aux applets. Mais Java est aussi un langage de
programmation à vocation plus générale qui peut résoudre n'importe quel type de problème - du moins en théorie.
Et comme précisé plus haut, il peut y avoir des moyens plus efficaces de résoudre la plupart des problèmes client/
serveur. Quand on quitte la scène des applets (et les restrictions qui y sont liées telles que les accès en écriture sur le
disque), on entre dans le monde des applications qui s'exécutent sans le soutien d'un browser, comme n'importe quel
programme. Les atouts de Java sont là encore non seulement sa portabilité, mais aussi sa facilité de programmation.
Comme vous allez le voir tout au long de ce livre, Java possède beaucoup de fonctionnalités qui permettent de créer
des programmes robustes dans un laps de temps plus court qu'avec d'autres langages de programmation.

Mais il faut bien être conscient qu'il s'agit d'un compromis. Le prix à payer pour ces améliorations est une vitesse
d'exécution réduite (bien que des efforts significatifs soient mis en œuvre dans ce domaine - JDK 1.3, en particulier,
introduit le concept d'amélioration de performances « hotspot »). Comme tout langage de programmation, Java a
des limitations internes qui peuvent le rendre inadéquat pour résoudre certains types de problèmes. Java évolue
rapidement cependant, et à chaque nouvelle version il permet d'adresser un spectre de plus en plus large de
problèmes.

- 49 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

III-L - Analyse et conception

Le paradigme de la POO constitue une approche nouvelle et différente de la programmation. Beaucoup de personnes
rencontrent des difficultés pour appréhender leur premier projet orienté objet. Une fois compris que tout est supposé
être un objet, et au fur et à mesure qu'on se met à penser dans un style plus orienté objet, on commence à créer de
« bonnes »conceptions qui s'appuient sur tous les avantages que la POO offre.

Une méthode (ou méthodologie) est un ensemble de processus et d'heuristiques utilisés pour réduire la complexité
d'un problème. Beaucoup de méthodes orientées objet ont été formulées depuis l'apparition de la POO. Cette section
vous donne un aperçu de ce que vous essayez d'accomplir en utilisant une méthode.

Une méthodologie s'appuie sur un certain nombre d'expériences, il est donc important de comprendre quel problème
la méthode tente de résoudre avant d'en adopter une. Ceci est particulièrement vrai avec Java, qui a été conçu pour
réduire la complexité (comparé au C) dans l'expression d'un programme. Cette philosophie supprime le besoin de
méthodologies toujours plus complexes. Des méthodologies simples peuvent se révéler tout à fait suffisantes avec
Java pour une classe de problèmes plus large que ce qu'elles ne pourraient traiter avec des langages procéduraux.

Il est important de réaliser que le terme « méthodologie » est trompeur et promet trop de choses. Tout ce qui est mis
en œuvre quand on conçoit et réalise un programme est une méthode. Ça peut être une méthode personnelle, et on
peut ne pas en être conscient, mais c'est une démarche qu'on suit au fur et à mesure de l'avancement du projet. Si
cette méthode est efficace, elle ne nécessitera sans doute que quelques petites adaptations pour fonctionner avec
Java. Si vous n'êtes pas satisfait de votre productivité ou du résultat obtenu, vous serez peut-être tenté d'adopter
une méthode plus formelle, ou d'en composer une à partir de plusieurs méthodes formelles.

Au fur et à mesure que le projet avance, le plus important est de ne pas se perdre, ce qui est malheureusement
très facile. La plupart des méthodes d'analyse et de conception sont conçues pour résoudre même les problèmes
les plus gros. Il faut donc bien être conscient que la plupart des projets ne rentrant pas dans cette catégorie, on
peut arriver à une bonne analyse et conception avec juste une petite partie de ce qu'une méthode recommande
href="#fn8" name="fnB8"> (4) . Une méthode de conception, même limitée, met sur la voie bien mieux que si on
commence à coder directement.

Il est aussi facile de rester coincé et tomber dans la « paralysie analytique » où on se dit qu'on ne peut passer à la
phase suivante, car on n'a pas traqué le moindre petit détail de la phase courante. Il faut bien se dire que, quelle que
soit la profondeur de l'analyse, certains aspects d'un problème ne se révéleront qu'en phase de conception, et d'autres
en phase de réalisation, voire pas avant que le programme ne soit achevé et exécuté. À cause de ceci, il est crucial
d'avancer relativement rapidement dans l'analyse et la conception, et d'implémenter un test du système proposé.

Il est bon de développer un peu ce point. À cause des déboires rencontrés avec les langages procéduraux, il est
louable qu'une équipe veuille avancer avec précautions et comprendre tous les détails avant de passer à la conception
et l'implémentation. Il est certain que lors de la création d'une base de données, il est capital de comprendre à fond
les besoins du client. Mais la conception d'une base de données fait partie d'une classe de problèmes bien définie
et bien comprise ; dans ce genre de programmes, la structure de la base de données est le problème à résoudre.
Les problèmes traités dans ce chapitre font partie de la classe de problèmes « joker » (invention personnelle), dans
laquelle la solution n'est pas une simple reformulation d'une solution déjà éprouvée de nombreuses fois, mais implique
un ou plusieurs « facteurs joker » - des éléments pour lesquels il n'existe aucune solution préétablie connue, et
qui nécessitent de pousser les recherches (5) . Tenter d'analyser à fond un problème joker avant de passer à la
conception et l'implémentation mène à la paralysie analytique parce qu'on ne dispose pas d'assez d'informations
pour résoudre ce type de problèmes durant la phase d'analyse. Résoudre ce genre de problèmes requiert de répéter
le cycle complet, et cela demande de prendre certains risques (ce qui est sensé, car on essaie de faire quelque chose
de nouveau et les revenus potentiels en sont plus élevés). On pourrait croire que le risque est augmenté par cette
ruée vers une première implémentation, mais elle peut réduire le risque dans un projet joker, car on peut tout de
suite se rendre compte si telle approche du problème est viable ou non. Le développement d'un produit s'apparente
à de la gestion de risque.

Souvent cela se traduit par « construire un prototype qu'il va falloir jeter ». Avec la POO, on peut encore avoir à
en jeter une partie, mais comme le code est encapsulé dans des classes, on aura inévitablement produit durant la

- 50 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

première passe quelques classes qui valent la peine d'être conservées et développé des idées sur la conception du
système. Ainsi, une première passe rapide sur un problème non seulement fournit des informations critiques pour la
prochaine passe d'analyse, de conception et d'implémentation, mais elle produit aussi une base du code.

Ceci dit, si on cherche une méthode qui contient de nombreux détails et suggère de nombreux étapes et documents,
il est toujours difficile de savoir où s'arrêter. Il faut garder à l'esprit ce qu'on essaye de découvrir :

1 Quels sont les objets ? (Comment partitionner le projet en ses composants élémentaires ?)
2 Quelle en est leur interface ? (Quels sont les messages qu'on a besoin d'envoyer à chaque objet ?)

Si on arrive à trouver quels sont les objets et leur interface, alors on peut commencer à coder. On pourra avoir besoin
d'autres descriptions et documents, mais on ne peut pas faire avec moins que ça.

Le développement peut être décomposé en cinq phases, et une Phase 0 qui est juste l'engagement initial à respecter
une structure de base.

III-L-1 - Phase 0 : Faire un plan

Il faut d'abord décider quelles étapes on va suivre dans le développement. Cela semble simple (en fait, tout semble
simple), et malgré tout, les gens ne prennent cette décision qu'après avoir commencé à coder. Si le plan se résume à
« retroussons nos manches et codons », alors ça ne pose pas de problème (quelquefois c'est une approche valable
quand on a affaire à un problème bien connu). Mais il faut néanmoins accepter que c'est le plan.

On peut aussi décider dans cette phase qu'une structure additionnelle est nécessaire. Certains programmeurs aiment
travailler en « mode vacances », sans structure imposée sur le processus de développement de leur travail : « Ce
sera fait lorsque ce sera fait ». Cela peut être séduisant un moment, mais disposer de quelques jalons aide à se
concentrer et focalise les efforts sur ces jalons au lieu d'être obnubilé par le but unique de « finir le projet ». De plus,
cela divise le projet en parties plus petites, ce qui le rend moins redoutable (sans compter que les jalons offrent des
opportunités de fête).

Quand j'ai commencé à étudier la structure des histoires (afin de pouvoir un jour écrire un roman), j'étais réticent au
début à l'idée de structure, trouvant que j'écrivais mieux quand je laissais juste la plume courir sur le papier. Mais j'ai
réalisé plus tard que quand j'écris à propos des ordinateurs, la structure est suffisamment claire pour moi pour que
je n'aie pas besoin de trop y réfléchir. Mais je structure tout de même mon travail, bien que ce soit inconsciemment
dans ma tête. Même si on pense que le plan est juste de commencer à coder, on passe tout de même par les phases
successives en se posant certaines questions et en y répondant.

III-L-1-a - L'exposé de la mission

Tout système qu'on construit, quelle que soit sa complexité, a un but, un besoin fondamental qu'il satisfait. Si on
peut voir au-delà de l'interface utilisateur, des détails spécifiques au matériel - ou au système -, des algorithmes de
codage et des problèmes d'efficacité, on arrive finalement au cœur du problème - simple et nu. Comme le soi-disant
concept fondamental d'un film hollywoodien, on peut le décrire en une ou deux phrases. Cette description pure
est le point de départ.

Le concept fondamental est assez important, car il donne le ton du projet ; c'est l'exposé de la mission. Ce ne sera
pas nécessairement le premier jet qui sera le bon (on peut être dans une phase ultérieure du projet avant qu'il ne soit
complètement clair), mais il faut continuer d'essayer jusqu'à ce que ça sonne bien. Par exemple, dans un système
de contrôle de trafic aérien, on peut commencer avec un concept fondamental basé sur le système qu'on construit :
« Le programme tour de contrôle garde la trace d'un avion ». Mais cela n'est plus valable quand le système se réduit
à un petit aérodrome, avec un seul contrôleur, ou même aucun. Un modèle plus utile ne décrira pas tant la solution
qu'on crée que le problème :« Des avions arrivent, déchargent, partent en révision, rechargent et repartent ».

- 51 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

III-L-2 - Phase 1 : Que construit-on ?

Dans la génération précédente de conception de programmes (conception procédurale), cela s'appelait « l'analyse
des besoins et les spécifications du système ». C'étaient des endroits où on se perdait facilement, avec des
documents au nom intimidant qui pouvaient occulter le projet. Leurs intentions étaient bonnes, pourtant. L'analyse
des besoins consiste à « faire une liste des indicateurs qu'on utilisera pour savoir quand le travail sera terminé et le
client satisfait ». Les spécifications du système consistent en « une description de ce que le programme fera (sans
se préoccuper du comment) pour satisfaire les besoins ». L'analyse des besoins est un contrat entre le développeur
et le client (même si le client travaille dans la même entreprise, ou se trouve être un objet ou un autre système).
Les spécifications du système sont une exploration générale du problème, et en un sens permettent de savoir s'il
peut être résolu et en combien de temps. Comme ils requièrent des consensus entre les intervenants sur le projet (et
parce qu'ils changent au cours du temps), il vaut mieux les garder aussi bruts que possible - idéalement en tant que
listes et diagrammes - pour ne pas perdre de temps. Il peut y avoir d'autres contraintes qui demandent de produire
de gros documents, mais en gardant les documents initiaux petits et concis, cela permet de les créer en quelques
sessions de brainstorming avec un leader qui affine la description dynamiquement. Cela permet d'impliquer tous les
acteurs du projet, et encourage la participation de toute l'équipe. Plus important encore, cela permet de lancer un
projet dans l'enthousiasme.

Il est nécessaire de rester concentré sur ce qu'on essaye d'accomplir dans cette phase : déterminer ce que le système
est supposé faire. L'outil le plus utile pour cela est une collection de ce qu'on appelle « cas d'utilisation ». Les cas
d'utilisation identifient les caractéristiques-clefs du système qui vont révéler certaines des classes fondamentales
qu'on utilisera. Ce sont essentiellement des réponses descriptives à des questions comme (6) :

• « Qui utilisera le système ? » ;


• « Que peuvent faire ces personnes avec le système ? » ;
• « Comment tel acteur fait-il cela avec le système ? » ;
• « Comment cela pourrait-il fonctionner si quelqu'un d'autre faisait cela, ou si le même acteur avait un objectif
différent ? » (pour trouver les variations) ;
• « Quels problèmes peuvent apparaître quand on fait cela avec le système ? » (pour trouver les exceptions).

Si on conçoit un guichet automatique, par exemple, le cas d'utilisation pour un aspect particulier des fonctionnalités
du système est capable de décrire ce que le guichet fait dans chaque situation possible. Chacune de ces situations
est appelée un scénario, et un cas d'utilisation peut être considéré comme une collection de scénarios. On peut
penser à un scénario comme à une question qui commence par « Qu'est-ce que le système fait si... ? ». Par exemple,
« Qu'est que le guichet fait si un client vient de déposer un chèque dans les dernières 24 heures, et qu'il n'y a pas
assez dans le compte sans que le chèque soit encaissé pour fournir le retrait demandé ? ».

Les diagrammes de cas d'utilisations sont voulus simples pour ne pas se perdre prématurément dans les détails de
l'implémentation du système :

- 52 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Chaque bonhomme représente un « acteur », typiquement une personne ou une autre sorte d'agent (cela peut même
être un autre système informatique, comme c'est le cas avec « ATM »). La boîte représente les limites du système.
Les ellipses représentent les cas d'utilisation, qui sont les descriptions des actions qui peuvent être réalisées avec le
système. Les lignes entre les acteurs et les cas d'utilisation représentent les interactions.

Tant que le système est perçu ainsi par l'utilisateur, son implémentation n'est pas importante.

Un cas d'utilisation n'a pas besoin d'être complexe, même si le système sous-jacent l'est. Il est seulement destiné à
montrer le système tel qu'il apparaît à l'utilisateur. Par exemple :

Les cas d'utilisation produisent les spécifications des besoins en déterminant toutes les interactions que l'utilisateur
peut avoir avec le système. Il faut trouver un ensemble complet de cas d'utilisations du système, et cela terminé, on se
retrouve avec le cœur de ce que le système est censé faire. La beauté des cas d'utilisation est qu'ils ramènent toujours
aux points essentiels et empêchent de se disperser dans des discussions non essentielles à la réalisation du travail
à faire. Autrement dit, si on dispose d'un ensemble complet de cas d'utilisation, on peut décrire le système et passer
à la phase suivante. Tout ne sera pas parfaitement clair dès le premier jet, mais ça ne fait rien. Tout se décantera
avec le temps, et si on cherche à obtenir des spécifications du système parfaites à ce point on se retrouvera coincé.

Si on est bloqué, on peut lancer cette phase en utilisant un outil d'approximation grossier : décrire le système en
quelques paragraphes et chercher les noms et les verbes. Les noms suggèrent les acteurs, le contexte des cas
d'utilisation ou les objets manipulés dans les cas d'utilisation. Les verbes suggèrent les interactions entre les acteurs
et les cas d'utilisation, et spécifient les étapes à l'intérieur des cas d'utilisation. On verra aussi que les noms et les
verbes produisent des objets et des messages durant la phase de design (on peut noter que les cas d'utilisation
décrivent les interactions entre les sous-systèmes, donc la technique « des noms et des verbes » ne peut être utilisée
qu'en tant qu'outil de brainstorming car il ne fournit pas les cas d'utilisation) (7) .

Bien que cela tienne plus de l'art obscur, à ce point un calendrier de base est important. On dispose maintenant d'une
vue d'ensemble de ce qu'on construit, on peut donc se faire une idée du temps nécessaire à sa réalisation. Un grand
nombre de facteurs entrent en jeu ici. Si on estime un calendrier trop important, l'entreprise peut décider d'abandonner
le projet (et utiliser leurs ressources sur quelque chose de plus raisonnable - ce qui est une bonne chose). Ou un

- 53 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

directeur peut avoir déjà décidé du temps que le projet devrait prendre et voudra influencer les estimations. Mais il
vaut mieux proposer un calendrier honnête et prendre les décisions importantes au début. Beaucoup de techniques
pour obtenir des calendriers précis ont été proposées (de même que pour prédire l'évolution de la bourse), mais la
meilleure approche est probablement de se baser sur son expérience et son intuition. Proposer une estimation du
temps nécessaire pour réaliser le système, puis doubler cette estimation et ajouter 10 pour cent. L'estimation initiale
est probablement correcte, on peut obtenir un système fonctionnel avec ce temps. Le doublement transforme le délai
en quelque chose de décent, et les 10 pour cent permettront de poser le vernis final et de traiter les détails (8) . Peu
importe comment on l'explique et les gémissements obtenus quand on révèle un tel planning, il semble juste que
ça fonctionne de cette façon.

III-L-3 - Phase 2 : Comment allons-nous le construire ?

Dans cette phase on doit fournir une conception qui décrive ce à quoi les classes ressemblent et comment elles
interagissent. Un bon outil pour déterminer les classes et les interactions est la méthode des cartes Classes-
Responsabilités-Collaboration (CRC). L'un des avantages de cet outil est sa simplicité : on prend des cartes vierges
et on écrit dessus au fur et à mesure. Chaque carte représente une classe, et sur la carte on écrit :

1 Le nom de la classe. Il est important que le nom de cette classe reflète l'essence de ce que la classe fait, afin
que sa compréhension soit immédiate.
2 Les « responsabilités » de la classe : ce qu'elle doit faire. Typiquement, cela peut être résumé par le nom
des fonctions membres (puisque ces noms doivent être explicites dans une bonne conception), mais
cela n'empêche pas de compléter par d'autres notes. Pour s'aider, on peut se placer du point de vue d'un
programmeur fainéant : quels objets voudrait-on voir apparaître pour résoudre le problème ?
3 Les « collaborations » de la classe : avec quelles classes interagit-elle ? « Interagir » est intentionnellement
évasif, il peut se référer à une agrégation ou indiquer qu'un autre objet existant va travailler pour le compte
d'un objet de la classe. Les collaborations doivent aussi prendre en compte l'audience de cette classe.
Par exemple, si on crée une classe Pétard, qui va l'observer, un Chimiste ou un Spectateur ? Le premier
voudra connaître la composition chimique, tandis que le deuxième sera préoccupé par les couleurs et le bruit
produits quand il explose.

On pourrait se dire que les cartes devraient être plus grandes à cause de toutes les informations qu'on aimerait mettre
dessus, mais il vaut mieux les garder les plus petites possible, non seulement pour concevoir de petites classes, mais
aussi pour éviter de plonger trop tôt dans les détails. Si on ne peut pas mettre toutes les informations nécessaires à
propos d'une classe sur une petite carte, la classe est trop complexe (soit le niveau de détails est trop élevé, soit il
faut créer plus d'une classe). La classe idéale doit être comprise en un coup d'œil. L'objectif des cartes CRC est de
fournir un premier jet de la conception afin de saisir le plan général pour pouvoir ensuite affiner cette conception.

L'un des avantages des cartes CRC réside dans la communication. Il vaut mieux les réaliser en groupe, sans
ordinateur. Chacun prend le rôle d'une ou plusieurs classes (qui au début n'ont pas de nom ni d'information associée).
Il suffit alors de dérouler une simulation impliquant un scénario à la fois, et décider quels messages sont envoyés
aux différents objets pour satisfaire chaque scénario. Au fur et à mesure du processus, on découvre quelles sont les
classes nécessaires, leurs responsabilités et collaborations, et on peut remplir les cartes. Quand tous les scénarios
ont été couverts, on devrait disposer d'une bonne approximation de la conception.

Avant d'utiliser les cartes CRC, la meilleure conception initiale que j'ai fournie sur un projet fut obtenue en dessinant
des objets sur un tableau devant une équipe - qui n'avait jamais participé à un projet de POO auparavant. Nous
avons discuté de la communication entre ces objets, effacé et remplacé certains d'entre eux par d'autres objets. De
fait, je recréais la méthode des cartes CRC au tableau. L'équipe (qui connaissait ce que le projet était censé faire) a
effectivement créé la conception ; et de ce fait ils la contrôlaient. Je me contentais de guider le processus en posant les
bonnes questions, proposant quelques hypothèses et utilisant les réponses de l'équipe pour modifier ces hypothèses.
La beauté de la chose fut que l'équipe a appris à bâtir une conception orientée objet non en potassant des exemples
abstraits, mais en travaillant sur la conception qui les intéressait au moment présent : celle de leur projet.

Une fois qu'on dispose d'un ensemble de cartes CRC, on peut vouloir une description plus formelle de la conception
en utilisant UML (9) . L'utilisation d'UML n'est pas une obligation, mais cela peut être utile, surtout si on veut afficher au

- 54 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

mur un diagramme auquel tout le monde puisse se référer, ce qui est une bonne idée. Une alternative à UML est une
description textuelle des objets et de leur interface, ou suivant le langage de programmation, le code lui-même (10) .

UML fournit aussi une notation pour décrire le modèle dynamique du système. Cela est pratique dans les cas où les
états de transition d'un système ou d'un sous-sytème sont suffisamment importants pour nécessiter leurs propres
diagrammes (dans un système de contrôle par exemple). On peut aussi décrire les structures de données, pour les
systèmes ou sous-systèmes dans lesquels les données sont le facteur dominant (comme une base de données).

On sait que la Phase 2 est terminée quand on dispose de la description des objets et de leur interface. Ou du moins
de la majorité d'entre eux - il y en a toujours quelques-uns qu'on ne découvre qu'en Phase 3, mais cela ne fait rien. La
préoccupation principale est de découvrir tous les objets. Il est plus agréable de les découvrir le plus tôt possible, mais
la POO est assez souple pour pouvoir s'adapter si on en découvre de nouveaux par la suite. En fait, la conception
d'un objet se fait en cinq étapes.

III-L-3-a - Les cinq étapes de la conception d'un objet

La conception d'un objet n'est pas limitée à la phase de codage du programme. En fait, la conception d'un objet
passe par une suite d'étapes. Garder cela à l'esprit permet d'éviter de prétendre à la perfection immédiate. On
réalise que la compréhension de ce que fait un objet et de ce à quoi il doit ressembler se fait progressivement. Ceci
s'applique d'ailleurs aussi à la conception de nombreux types de programmes ; le modèle d'un type de programme
n'émerge qu'après s'être confronté encore et encore au problème (se référer au livre Thinking in Patterns with
Java, téléchargeable sur www.BruceEckel.com). Les objets aussi ne se révèlent à la compréhension qu'après un
long processus.

1. Découverte de l'objet. Cette étape se situe durant l'analyse initiale du programme. Les objets peuvent être
découverts en cherchant les facteurs extérieurs et les frontières, la duplication d'éléments dans le système, et les
plus petites unités conceptuelles. Certains objets sont évidents si on dispose d'un ensemble de bibliothèques de
classes. La ressemblance entre les classes peut suggérer des classes de base et l'héritage peut en être déduit
immédiatement, ou plus tard dans la phase de conception.

2. Assemblage des objets. Lors de la construction d'un objet, on peut découvrir le besoin de nouveaux membres
qui n'était pas apparu durant l'étape de découverte. Les besoins internes d'un objet peuvent requérir d'autres classes
pour les supporter.

3. Construction du système. Une fois de plus, un objet peut révéler des besoins supplémentaires durant cette
étape. Au fur et à mesure de l'avancement du projet, les objets évoluent. Les besoins de la communication et
de l'interconnexion avec les autres objets du système peuvent changer les besoins des classes ou demander de
nouvelles classes. Par exemple, on peut découvrir le besoin de classes d'utilitaires, telles que des listes chaînées,
qui contiennent peu ou pas d'information et sont juste là pour aider les autres classes.

4. Extension du système. Si on ajoute de nouvelles fonctionnalités au système, on peut se rendre compte que
sa conception ne facilite pas l'extension du système. Avec cette nouvelle information, on peut restructurer certaines
parties du système, éventuellement en ajoutant de nouvelles classes ou de nouvelles hiérarchies de classes.

5. Réutilisation des objets. Ceci est le test final pour une classe. Si quelqu'un tente de réutiliser une classe dans
une situation entièrement différente, il y découvrira certainement des imperfections. La modification de la classe pour
s'adapter à de nouveaux programmes va en révéler les principes généraux, jusqu'à l'obtention d'un type vraiment
réutilisable. Cependant, il ne faut pas s'attendre à ce que tous les objets d'un système soient réutilisables - il est
tout à fait légitime que la majorité des objets soient spécifiques au système. Les classes réutilisables sont moins
fréquentes, et doivent traiter de problèmes plus génériques pour être réutilisables.

III-L-3-b - Indications quant au développement des objets

Ces étapes suggèrent quelques règles de base concernant le développement des classes :

- 55 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

1 Quand un problème spécifique génère une classe, la laisser grandir et mûrir durant la résolution d'autres
problèmes.
2 Se rappeler que la conception du système consiste principalement à découvrir les classes dont on a besoin
(et leurs interfaces). Si on dispose déjà de ces classes, le projet ne devrait pas être compliqué.
3 Ne pas vouloir tout savoir dès le début ; compléter ses connaissances au fur et à mesure de l'avancement du
projet. La connaissance viendra de toute façon tôt ou tard.
4 Commencer à programmer ; obtenir un prototype qui marche afin de pouvoir approuver la conception ou au
contraire la dénoncer. Ne pas avoir peur de se retrouver avec du code-spaghetti à la procédurale - les classes
partitionnent le problème et aident à contrôler l'anarchie. Les mauvaises classes n'affectent pas les classes
bien conçues.
5 Toujours rester le plus simple possible. De petits objets propres avec une utilité apparente sont toujours
mieux conçus que ceux disposant de grosses interfaces compliquées. Quand une décision doit être prise,
utiliser l'approche d'Occam's Razor : choisir la solution la plus simple, car les classes simples sont presque
toujours les meilleures. Commencer petit et simple, et étendre l'interface de la classe quand on la comprend
mieux. Il est toujours plus difficile d'enlever des éléments d'une classe.

Phase 3 : Construire le cœur du système

Ceci est la conversion initiale de la conception brute en portion de code compilable et exécutable qui peut être testée,
et surtout qui va permettre d'approuver ou d'invalider l'architecture retenue. Ce n'est pas un processus qui se fait
en une passe, mais plutôt le début d'une série d'étapes qui vont construire le système au fur et à mesure comme
le montre la Phase 4.

Le but ici est de trouver le cœur de l'architecture du système qui a besoin d'être implémenté afin de générer
un système fonctionnel, sans se soucier de l'état de complétion du système dans cette passe initiale. Il s'agit ici
de créer un cadre sur lequel on va pouvoir s'appuyer pour les itérations suivantes. On réalise aussi la première
des nombreuses intégrations et phases de tests, et on donne les premiers retours aux clients sur ce à quoi leur
système ressemblera et son état d'avancement. Idéalement, on découvre quelques-uns des risques critiques. Des
changements ou des améliorations sur l'architecture originelle seront probablement découverts - des choses qu'on
n'aurait pas découvertes avant l'implémentation du système. Une partie de la construction du système consiste à
confronter le système avec l'analyse des besoins et les spécifications du système (quelle que soit la forme sous
laquelle ils existent). Il faut s'assurer en effet que les tests vérifient les besoins et les cas d'utilisations. Quand le cœur
du système est stable, on peut passer à la suite et ajouter des fonctionnalités supplémentaires.

III-L-5 - Phase 4 : Itérer sur les cas d'utilisation

Une fois que le cadre de base fonctionne, chaque fonctionnalité ajoutée est un petit projet en elle-même. On ajoute
une fonctionnalité durant une itération, période relativement courte du développement.

Combien de temps dure une itération ? Idéalement, chaque itération dure entre une et trois semaines (ceci peut
varier suivant le langage d'implémentation choisi). À la fin de cette période, on dispose d'un système intégré et testé
avec plus de fonctionnalités que celles dont il disposait auparavant. Mais ce qu'il est intéressant de noter, c'est qu'un
simple cas d'utilisation constitue la base d'une itération. Chaque cas d'utilisation est un ensemble de fonctionnalités
qu'on ajoute au système toutes en même temps, durant une itération. Non seulement cela permet de se faire une
meilleure idée de ce que recouvre ce cas d'utilisation, mais cela permet de le valider, puisqu'il n'est pas abandonné
après l'analyse et la conception, mais sert au contraire tout au long du processus de création.

Les itérations s'arrêtent quand on dispose d'un système comportant toutes les fonctionnalités souhaitées ou qu'une
date limite arrive et que le client se contente de la version courante (se rappeler que les commanditaires dirigent
l'industrie du logiciel). Puisque le processus est itératif, on dispose de nombreuses opportunités pour délivrer une
version intermédiaire plutôt qu'un produit final ; les projets open source travaillent uniquement dans un environnement
itératif avec de nombreux retours, ce qui précisément les rend si productifs.

Un processus de développement itératif est intéressant pour de nombreuses raisons. Cela permet de révéler et de
résoudre des risques critiques très tôt, les clients ont de nombreuses opportunités pour changer d'avis, la satisfaction

- 56 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

des programmeurs est plus élevée, et le projet peut être piloté avec plus de précision. Mais un bénéfice additionnel
particulièrement important est le retour aux commanditaires du projet, qui peuvent voir grâce à l'état courant du
produit où le projet en est. Ceci peut réduire ou éliminer le besoin de réunions soporifiques sur le projet, et améliore
la confiance et le support des commanditaires.

III-L-6 - Phase 5 : Évolution

Cette phase du cycle de développement a traditionnellement été appelée « maintenance », un terme fourre-tout qui
peut tout vouloir dire depuis « faire marcher le produit comme il était supposé le faire dès le début » à « ajouter
de nouvelles fonctionnalités que le client a oublié de mentionner » au plus traditionnel « corriger les bogues qui
apparaissent » et « ajouter de nouvelles fonctionnalités quand le besoin s'en fait sentir ». Le terme « maintenance » a
été la cause de si nombreux malentendus qu'il en est arrivé à prendre un sens péjoratif, en partie parce qu'il suggère
qu'on a fourni un programme parfait et que tout ce qu'on a besoin de faire est d'en changer quelques parties, le
graisser et l'empêcher de rouiller. Il existe peut-être un meilleur terme pour décrire ce qu'il en est réellement.

J'utiliserai plutôt le terme évolution13Au moins un aspect de l'évolution est couvert dans le livre de Martin
Fowler Refactoring : improving the design of existing code (Addison-Wesley 1999), qui utilise exclusivement
des exemples Java.. C'est-à-dire, « Tout ne sera pas parfait dès le premier jet, il faut se laisser la latitude d'apprendre
et de revenir en arrière pour faire des modifications ». De nombreux changements seront peut-être nécessaires au
fur et à mesure que l'appréhension et la compréhension du problème augmentent. Si on continue d'évoluer ainsi
jusqu'au bout, l'élégance obtenue sera payante, à la fois à court et long termes. L'évolution permet de passer d'un
bon à un excellent programme, et clarifie les points restés obscurs durant la première passe. C'est aussi dans cette
phase que les classes passent d'un statut d'utilité limitée au système à ressources réutilisables.

Ici, « jusqu'au bout » ne veut pas simplement dire que le programme fonctionne suivant les exigences et les cas
d'utilisation. Cela veut aussi dire que la structure interne du code présente une logique d'organisation et semble bien
s'assembler, sans abus de syntaxe, d'objets surdimensionnés ou de code inutilement exposé. De plus, il faut s'assurer
que la structure du programme puisse s'adapter aux changements qui vont inévitablement arriver pendant sa durée
vie, et que ces changements puissent se faire aisément et proprement. Ceci n'est pas une petite caractéristique. Il
faut comprendre non seulement ce qu'on construit, mais aussi comment le programme va évoluer (ce que j'appelle le
vecteur changement). Heureusement, les langages de programmation orientés objet sont particulièrement adaptés
à ce genre de modifications continuelles - les frontières créées par les objets sont ce qui empêche la structure
du programme de s'effondrer. Ils permettent aussi de faire des changements - même ceux qui seraient considérés
comme sévères dans un programme procédural - sans causer de ravages dans l'ensemble du code. En fait le support
de l'évolution pourrait bien être le bénéfice le plus important de la programmation orientée objet.

Avec l'évolution, on crée quelque chose qui approche ce qu'on croit avoir construit, on le compare avec les exigences
et on repère les endroits où cela coince. On peut alors revenir en arrière et corriger cela en remodélisant et
réimplémentant les portions du programme qui ne fonctionnaient pas correctement (11) . De fait, on peut avoir besoin
de résoudre le problème ou un de ses aspects un certain nombre de fois avant de trouver la bonne solution (une
étude de Design Patterns s'avère généralement utile ici). On pourra trouver plus d'informations dans Thinking in
Patterns with Java, téléchargeable à www.BruceEckel.com).

Il faut aussi évoluer quand on construit un système, qu'on voit qu'il remplit les exigences et qu'on découvre finalement
que ce n'était pas ce qu'on voulait. Quand on se rend compte après avoir vu le système en action qu'on essayait de
résoudre un autre problème. Si on pense que ce genre d'évolution est à prendre en considération, alors on se doit
de construire une première version aussi rapidement que possible afin de déterminer au plus tôt si c'est réellement
ce qu'on veut.

La chose la plus importante à retenir est que par défaut - par définition, plutôt - si on modifie une classe, ses
classes parentes et dérivées continueront de fonctionner. Il ne faut pas craindre les modifications (surtout si on
dispose d'un ensemble de tests qui permettent de vérifier les modifications apportées). Les modifications ne vont
pas nécessairement casser le programme, et tout changement apporté sera limité aux sous-classes et/ou aux
collaborateurs spécifiques de la classe qu'on change.

- 57 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

III-L-7 - Les plans sont payants

Bien sûr on ne bâtirait pas une maison sans une multitude de plans dessinés avec attention. Si on construit un pont
ou une niche, les plans ne seront pas aussi élaborés, mais on démarre avec quelques esquisses pour se guider.
Le développement de logiciels a connu les extrêmes. Longtemps les gens ont travaillé sans structure, mais on a
commencé à assister à l'effondrement de gros projets. En réaction, on en est arrivé à des méthodologies comprenant
un luxe de structure et de détails, destinées justement à ces gros projets. Ces méthodologies étaient trop intimidantes
pour qu'on les utilise - on avait l'impression de passer son temps à écrire des documents et aucun moment à coder
(ce qui était souvent le cas). J'espère que ce que je vous ai montré ici suggère un juste milieu. Utilisez une approche
qui corresponde à vos besoins (et votre personnalité). Même s'il est minimal, la présence d'un plan vous apportera
beaucoup dans la gestion de votre projet. Rappelez-vous que selon la plupart des estimations, plus de 50 pour cent
des projets échouent (certaines estimations vont jusqu'à 70 pour cent).

En suivant un plan - de préférence un qui soit simple et concis - et en produisant une modélisation de la structure avant
de commencer à coder, vous découvrirez que les choses s'arrangent bien mieux que si on se lance comme ça dans
l'écriture. Vous en retirerez aussi une plus grande satisfaction. Suivant mon expérience, arriver à une solution élégante
procure une satisfaction à un niveau entièrement différent ; cela ressemble plus à de l'art qu'à de la technologie.
Et l'élégance est toujours payante, ce n'est pas une vaine poursuite. Non seulement on obtient un programme plus
facile à construire et déboguer, mais qui est aussi plus facile à comprendre et maintenir, et c'est là que sa valeur
financière réside.

J'ai étudié à différentes reprises les techniques d'analyse et de conception depuis que je suis sorti de l'école. Le
concept de Programmation Extreme (XP) est le plus radical et divertissant que j'ai vu. Il est rapporté dans Extreme
Programming Explained de Kent Beck (Addison-Wesley, 2000) et sur le web à www.xprogramming.com.

XP est à la fois une philosophie à propos de la programmation et un ensemble de règles de base. Certaines de
ces règles sont reprises dans d'autres méthodologies récentes, mais les deux contributions les plus importantes
et novatrices, sont à mon sens « commencer par écrire les tests » et « programmation en binôme ». Bien qu'il
soutienne et argumente l'ensemble de la théorie, Beck insiste sur le fait que l'adoption de ces deux pratiques améliore
grandement la productivité et la fiabilité.

III-L-8 - Commencer par écrire les tests

Les tests ont traditionnellement été relégués à la dernière partie d'un projet, une fois que « tout marche, mais c'est
juste pour s'en assurer ». Ils ne sont généralement pas prioritaires et les gens qui se spécialisent dedans ne sont pas
reconnus à leur juste valeur et se sont souvent vus cantonnés dans un sous-sol, loin des « véritables programmeurs ».
Les équipes de test ont réagi en conséquence, allant jusqu'à porter des vêtements de deuil et glousser joyeusement
quand ils trouvaient des erreurs (pour être honnête, j'ai eu moi aussi ce genre de sentiments lorsque je mettais des
compilateurs en faute).

XP révolutionne complètement le concept du test en lui donnant une priorité aussi importante (ou même plus forte)
que le code. En fait, les tests sont écrits avant le code qui sera testé, et les tests restent tout le temps avec le code.
Ces tests doivent être exécutés avec succès à chaque nouvelle intégration dans le projet (ce qui peut arriver plus
d'une fois par jour).

Écrire les tests d'abord a deux effets extrêmement importants.

Premièrement, cela nécessite une définition claire de l'interface d'une classe. J'ai souvent suggéré que les gens
« imaginent la classe parfaite qui résolve un problème particulier » comme outil pour concevoir le système. La stratégie
de test de XP va plus loin - elle spécifie exactement ce à quoi la classe doit ressembler pour le client de cette classe,
et comment la classe doit se comporter. Dans des termes non ambigus. On peut écrire tout ce qu'on veut, ou créer
tous les diagrammes qu'on veut, décrivant comment une classe devrait se comporter et ce à quoi elle ressemble,
mais rien n'est aussi réel qu'une batterie de tests. Le premier est une liste de vœux, mais les tests sont un contrat
certifié par un compilateur et un programme qui marche. Il est dur d'imaginer une description plus concrète d'une
classe que des tests.

- 58 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

En créant les tests, on est forcé de penser complètement la classe et souvent on découvre des fonctionnalités
nécessaires qui ont pu être manquées lors de l'utilisation des diagrammes UML, des cartes CRC, des cas d'utilisation,
etc.

Le deuxième effet important dans l'écriture des tests en premier vient du fait qu'on peut lancer les tests à chaque
nouvelle version du logiciel. Cela permet d'obtenir l'autre moitié des tests réalisés par le compilateur. Si on regarde
l'évolution des langages de programmation de ce point de vue, on se rend compte que les améliorations réelles dans
la technologie ont en fait tourné autour du test. Les langages assembleur vérifiaient uniquement la syntaxe, puis le
C a imposé des restrictions sémantiques, et cela permettait d'éviter certains types d'erreurs. Les langages orientés
objet imposent encore plus de restrictions sémantiques, qui sont quand on y pense des formes de test. « Est-ce que
ce type de données est utilisé correctement ? » et « Est-ce que cette fonction est appelée correctement ? » sont le
genre de tests effectués par le compilateur ou le système d'exécution. On a pu voir le résultat d'avoir ces tests dans
le langage même : les gens ont été capables de construire des systèmes plus complexes, et de les faire marcher,
et ce en moins de temps et d'efforts. Je me suis souvent demandé pourquoi, mais maintenant je réalise que c'est
grâce aux tests : si on fait quelque chose de faux, le filet de sécurité des tests intégré au langage prévient qu'il y a
un problème et montre même où il réside.

Mais les tests intégrés permis par la conception du langage ne peuvent aller plus loin. À partir d'un certain point, il est
de notre responsabilité de produire une suite complète de tests (en coopération avec le compilateur et le système
d'exécution) qui vérifie tout le programme. Et, de même qu'il est agréable d'avoir un compilateur qui vérifie ce qu'on
code, ne serait-il pas préférable que ces tests soient présents depuis le début ? C'est pourquoi on les écrit en premier,
et qu'on les exécute automatiquement à chaque nouvelle version du système. Les tests deviennent une extension
du filet de sécurité fourni par le langage.

L'utilisation de langages de programmation de plus en plus puissants m'a permis de tenter plus de choses
audacieuses, parce que je sais que le langage m'empêchera de perdre mon temps à chasser les bogues. La stratégie
de tests de XP réalise la même chose pour l'ensemble du projet. Et parce qu'on sait que les tests vont révéler tous
les problèmes introduits (et on ajoute de nouveaux tests au fur et à mesure qu'on les imagine), on peut faire de
gros changements sans se soucier de mettre le projet complet en déroute. Ceci est une approche particulièrement
puissante.

III-L-9 - Programmation en binôme

La programmation en binôme va à l'encontre de l'individualisme farouche endoctriné, depuis l'école (où on réussit
ou échoue suivant nos mérites personnels, et où travailler avec ses voisins est considéré comme « tricher »), et
jusqu'aux médias, en particulier les films hollywoodiens dans lesquels le héros se bat contre la conformité (12) . Les
programmeurs aussi sont considérés comme des parangons d'individualisme - des « codeurs cowboy » comme aime
à le dire Larry Constantine. Et XP, qui se bat lui-même contre la pensée conventionnelle, soutient que le code devrait
être écrit avec deux personnes par station de travail. Et cela devrait être fait dans un endroit regroupant plusieurs
stations de travail, sans les barrières dont raffolent les gens des Moyens Généraux. En fait, Beck dit que la première
tâche nécessaire pour implémenter XP est de venir avec des tournevis et d'enlever tout ce qui se trouve dans le
passage (13) (cela nécessite un responsable qui puisse absorber la colère du département des Moyens Généraux).

Dans la programmation en binôme, une personne produit le code tandis que l'autre y réfléchit. Le penseur garde la
conception générale à l'esprit - la description du problème, mais aussi les règles de XP à portée de main. Si deux
personnes travaillent, il y a moins de chance que l'une d'entre elles s'en aille en disant « Je ne veux pas commencer
en écrivant les tests », par exemple. Et si le codeur reste bloqué, ils peuvent changer leur place. Si les deux restent
bloqués, leurs songeries peuvent être remarquées par quelqu'un d'autre dans la zone de travail qui peut venir les
aider. Travailler en binôme permet de garder une bonne productivité et de rester sur la bonne pente. Probablement
plus important, cela rend la programmation beaucoup plus sociable et amusante.

J'ai commencé à utiliser la programmation en binôme durant les périodes d'exercice dans certains de mes séminaires
et il semblerait que cela enrichisse l'expérience personnelle de chacun.

- 59 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

III-M - Les raisons du succès de Java

Java est si populaire actuellement, car son but est de résoudre beaucoup de problèmes auxquels les programmeurs
doivent faire face aujourd'hui. Le but de Java est d'améliorer la productivité. La productivité vient de différents
horizons, mais le langage a été conçu pour aider un maximum tout en entravant le moins possible avec des règles
arbitraires ou l'obligation d'utiliser un ensemble particulier de caractéristiques. Java a été conçu pour être pratique ; les
décisions concernant la conception de Java furent prises afin que le programmeur en retire le maximum de bénéfices.

III-M-1 - Les systèmes sont plus faciles à exprimer et comprendre

Les classes conçues pour résoudre le problème sont plus faciles à exprimer. La solution est mise en œuvre dans le
code avec des termes de l'espace problème (« Mets le fichier à la poubelle ») plutôt qu'en termes machine, l'espace
solution (« Positionne le bit à 1 ce qui veut dire que le relais va se fermer »). On traite de concepts de plus haut
niveau et une ligne de code est plus porteuse de sens.

L'autre aspect bénéfique de cette facilité d'expression se retrouve dans la maintenance, qui représente (s'il faut en
croire les rapports) une grosse part du coût d'un programme. Si un programme est plus facile à comprendre, il est
forcément plus facile à maintenir. Cela réduit aussi le coût de création et de maintenance de la documentation.

III-M-2 - Puissance maximale grâce aux bibliothèques

La façon la plus rapide de créer un programme est d'utiliser du code déjà écrit : une bibliothèque. Un des buts
fondamentaux de Java est de faciliter l'emploi des bibliothèques. Ce but est obtenu en convertissant ces bibliothèques
en nouveaux types de données (classes), et utiliser une bibliothèque revient à ajouter de nouveaux types au langage.
Comme le compilateur Java s'occupe de l'interfaçage avec la bibliothèque - garantissant une initialisation et un
nettoyage propres, et s'assurant que les fonctions sont appelées correctement - on peut se concentrer sur ce qu'on
attend de la bibliothèque, et non sur les moyens de le faire.

III-M-3 - Traitement des erreurs

L'une des difficultés du C est la gestion des erreurs, problème connu et largement ignoré - le croisement de doigts
est souvent impliqué. Si on construit un programme gros et complexe, il n'y a rien de pire que de trouver une erreur
enfouie quelque part sans qu'on sache d'où elle vient. Le traitement des exceptions de Java est une façon de
garantir qu'une erreur a été remarquée, et que quelque chose est mis en œuvre pour la traiter.

III-M-4 - Mise en œuvre de gros projets

Beaucoup de langages traditionnels imposent des limitations internes sur la taille des programmes et leur complexité.
BASIC, par exemple, peut s'avérer intéressant pour mettre en œuvre rapidement des solutions pour certains types de
problèmes ; mais si le programme dépasse quelques pages de long, ou s'aventure en dehors du domaine du langage,
cela revient à tenter de nager dans un liquide encore plus visqueux. Aucune limite ne prévient que le cadre du langage
est dépassé, et même s'il en existait, elle serait probablement ignorée. On devrait se dire : « Mon programme BASIC
devient trop gros, je vais le réécrire en C ! », mais à la place on tente de glisser quelques lignes supplémentaires
pour implémenter cette nouvelle fonctionnalité. Le coût total continue donc à augmenter.

Java a été conçu pour pouvoir mettre en œuvre toutes les tailles de projets - c'est-à-dire, pour supprimer ces
frontières liées à la complexité croissante d'un gros projet. L'utilisation de la programmation orientée objet n'est
certainement pas nécessaire pour écrire un programme utilitaire du style « Hello world ! », mais les fonctionnalités
sont présentes quand on en a besoin. Et le compilateur ne relâche pas son attention pour dénicher les bogues -
produisant indifféremment des erreurs pour les petits comme pour les gros programmes.

- 60 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

III-N - Stratégies de transition

Si on décide d'investir dans la POO, la question suivante est généralement : « Comment convaincre mes directeur/
collègues/département/collaborateurs d'utiliser les objets ? » Il faut se mettre à leur place et réfléchir comment on
ferait s'il fallait apprendre un nouveau langage et un nouveau paradigme de programmation. Ce cas s'est sûrement
déjà présenté de par le passé. Il faut commencer par des cours et des exemples ; puis lancer un petit projet d'essai
pour inculquer les bases sans les perdre dans les détails. Ensuite, passer à un projet « réel » qui réalise quelque
chose d'utile. Au cours du premier projet, continuer l'apprentissage par la lecture, poser des questions à des experts
et échanger des astuces avec des amis. Cette approche est celle recommandée par de nombreux programmeurs
expérimentés pour passer à Java. Si toute l'entreprise décide de passer à Java, cela entraînera bien sûr une
dynamique de groupe, mais cela aide de se rappeler à chaque étape comment une personne seule opérerait.

III-N-1 - Règles de base

Voici quelques indications à prendre en compte durant la transition vers la programmation orientée objet et Java.

III-N-1-a - Cours

La première étape comprend une formation. Il ne faut pas jeter la confusion pendant six ou neuf mois dans
l'entreprise, le temps que tout le monde comprenne comment fonctionnent les interfaces. Il vaut mieux se contenter
d'un petit groupe d'endoctrinement, composé de préférence de personnes curieuses, s'entendant bien entre elles et
suffisamment indépendantes pour créer leur propre réseau de support concernant l'apprentissage de Java.

Une approche alternative suggérée quelquefois comprend la formation de tous les niveaux de l'entreprise à la fois, en
incluant à la fois des cours de présentation pour les responsables et des cours de conception et de programmation
pour les développeurs. Ceci est particulièrement valable pour les petites entreprises qui n'hésitent pas à introduire
des changements radicaux dans leurs manières de faire, ou au niveau division des grosses entreprises. Cependant,
comme le coût résultant est plus important, certains choisiront de commencer avec des cours, de réaliser un projet
pilote (si possible avec un mentor extérieur), et de laisser l'équipe du projet devenir les professeurs pour le reste
de l'entreprise.

III-N-1-b - Projet à faible risque

Tester sur un projet à faible risque qui autorise les erreurs. Une fois gagnée une certaine expérience, on peut soit
répartir les membres de cette première équipe sur les autres projets ou utiliser cette équipe comme support technique
de la POO. Le premier projet peut ne pas fonctionner correctement dès le début, il ne faut donc pas qu'il soit critique
pour l'entreprise. Il doit être simple, indépendant et instructif : cela veut dire qu'il doit impliquer la création de classes
qui soient compréhensibles aux autres programmeurs quand arrivera leur tour d'apprendre Java.

III-N-1-c - S'inspirer de bonnes conceptions

Rechercher des exemples de bonnes conceptions orientées objet avant de partir de zéro. Il y a de fortes chances
que quelqu'un ait déjà résolu le problème, et s'ils ne l'ont pas résolu exactement modifier le système existant (grâce
à l'abstraction, cf. plus haut) pour qu'il remplisse nos besoins. C'est le concept général des patrons génériques,
couverts dans Thinking in Patterns with Java, téléchargeable à www.BruceEckel.com.

III-N-1-d - Utiliser les bibliothèques de classes existantes

La motivation économique première pour passer à la POO est la facilité de réutilisation de code existant sous la
forme de bibliothèques de classes (en particulier, les Bibliothèques Standard Java, couvertes tout au long de ce
livre). On arrive au cycle de développement le plus court quand on crée et utilise des objets directement tirés des
bibliothèques. Cependant, de nouveaux programmeurs ne saisissent pas ce point, ne connaissent pas l'existence

- 61 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

de telles bibliothèques ou, fascinés par le langage, veulent réécrire des classes qui existent déjà. Le succès de la
transition vers Java et la POO passe par des efforts pour encourager les gens à réutiliser le plus possible le code
des autres.

III-N-1-e - Ne pas traduire du code existant en Java

Ce n'est généralement pas le meilleur usage de son temps qu'on puisse trouver que de prendre du code existant
et fonctionnel et de le traduire en Java (si on doit le transformer en objets, on peut s'interfacer avec du code C ou
C++ en utilisant l'Interface Native Java - JNI - décrite dans l'annexe B). Il y a bien sûr des avantages à le faire,
particulièrement si ce code est destiné à être réutilisé. Mais il y a de fortes chances pour qu'on passe à côté de la
spectaculaire amélioration de productivité espérée sauf si ce premier projet en est un nouveau. Java et la POO sont
mis en valeur quand on suit un projet de la conception à la mise en œuvre.

III-N-2 - Les obstacles au niveau du management

Si on se situe du côté des responsables, le travail consiste à acquérir des ressources pour l'équipe, surmonter les
obstacles pouvant gêner l'équipe, et en général tenter de fournir l'environnement le plus productif et agréable afin
que l'équipe puisse accomplir ces miracles qu'on vous demande toujours de réaliser. Le passage à Java entre dans
ces trois catégories, et ce serait merveilleux si de plus cela ne coûtait rien. Bien que le passage à Java puisse être
moins onéreux - suivant les contraintes - que d'autres alternatives de POO pour une équipe de programmeurs C (et
probablement pour les développeurs dans d'autres langages), ce coût n'est pas nul, et il y a des obstacles dont il faut
être conscient avant de promouvoir le passage à Java à l'intérieur de l'entreprise et de s'embarquer dans la transition.

III-N-2-a - Coûts de mise en œuvre

Le coût du passage à Java recouvre plus que l'acquisition d'un compilateur Java (le compilateur Java fourni par Sun
est gratuit, cela n'est donc pas un obstacle). Les coûts à moyen et long termes seront minimisés si on investit dans la
formation (et éventuellement dans la participation d'un consultant pour le premier projet), de même que si on identifie
et achète des bibliothèques de classes qui résolvent les problèmes plutôt que de tenter de réécrire ces bibliothèques
soi-même. Ce sont des investissements lourds qui doivent être relativisés dans une proposition raisonnable. De plus, il
existe des coûts cachés dans la baisse de productivité liée à l'apprentissage d'un nouveau langage et éventuellement
d'un nouvel environnement de développement. La formation et l'encadrement peuvent certainement les réduire, mais
les membres de l'équipe devront mener leur propre combat pour maîtriser la nouvelle technologie. Durant cette phase
ils feront plus d'erreurs (c'est prouvé, et les erreurs comprises constituent le meilleur moyen de progresser) et seront
moins productifs. Cependant, avec certains types de problèmes, les bonnes classes et le bon environnement de
développement, il est possible d'être plus productif pendant l'apprentissage de Java (même en considérant qu'on fait
plus d'erreurs et qu'on écrit moins de lignes de code par jour) que si on en était resté au C.

III-N-2-b - Problèmes de performances

Une question qui revient souvent est : « Est-ce que la POO ne rend pas obligatoirement mes programmes plus gros
et plus lents ? » La réponse est « Ça dépend ». Les fonctionnalités de vérification introduites dans Java ont prélevé
leur tribut sur la performance comparé à un langage comme le C++. Des technologies telles que le «hotspot » et les
techniques de compilation ont significativement amélioré la vitesse dans la plupart des cas, et les efforts pour des
performances accrues continuent.

Quand on se concentre sur le prototypage rapide, on assemble des composants aussi vite que possible en ignorant les
problèmes liés à l'efficacité. Si on utilise des bibliothèques extérieures, celles-ci ont généralement été optimisées par
leurs distributeurs ; de toute façon ce n'est pas la préoccupation première quand on est en phase de développement
rapide. Quand on dispose d'un système qui nous satisfait et s'il est suffisamment petit et rapide, alors le tour est
joué. Sinon, on tente de mettre au point avec un outil de profilage, en cherchant en premier des améliorations qui
peuvent être faites en réécrivant de petites portions de code. Si cela ne suffit pas, il faut chercher si on peut apporter
quelques changements à l'implémentation sous-jacente afin qu'aucune classe particulière n'ait besoin de modifier
son code. Il ne faut toucher à la conception que si rien d'autre ne résout le problème. Le fait que les performances

- 62 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

soient si critiques dans cette phase de la conception est un indicateur que ce doit être un des critères essentiels de
la conception. On a le bénéfice de s'en rendre compte relativement tôt en utilisant le prototypage rapide.

Si on trouve une fonction qui est un goulot d'étranglement, on peut la réécrire en C ou en C++ en utilisant les
méthodes natives de Java, sujet de l'annexe B.

III-N-2-c - Erreurs classiques de conception

Quand l'équipe commencera la programmation orientée objet et Java, les programmeurs vont typiquement passer par
une série d'erreurs classiques de conception. Ceci est souvent dû à des retours insuffisants de la part d'experts durant
la conception et l'implémentation des premiers projets, puisqu'aucun expert n'existe encore au sein de l'entreprise
et qu'il peut y avoir des réticences à engager des consultants. Il est facile de se dire trop tôt qu'on maîtrise la POO
et partir sur de mauvaises bases. Quelque chose d'évident pour une personne expérimentée peut être le sujet d'un
débat interne intense pour un novice. La plupart de ces difficultés peuvent être évitées en utilisant un expert extérieur
pour la formation.

Java ressemble beaucoup au C++, et il semblerait naturel que le C++ soit remplacé par Java. Mais je commence à
m'interroger sur cette logique. D'une part, C++ dispose toujours de fonctionnalités que Java n'a pas, et bien que de
nombreuses promesses aient été faites sur le fait que Java soit un jour aussi rapide, voire plus, que le C++, on a vu de
grosses améliorations, mais pas de révolutions spectaculaires. De plus, il semblerait que le C++ intéresse une large
communauté passionnée, et je ne pense donc pas que ce langage puisse disparaître prochainement (les langages
semblent résister au cours du temps. Allen Hollub a affirmé durant l'un de mes « Séminaires Java Intermédiaire/
Avancé » que les deux langages les plus utilisés étaient Rexx et COBOL, dans cet ordre).

Je commence à croire que la force de Java réside dans une optique différente de celle du C++. C++ est un langage
qui n'essaie pas de se fondre dans un moule. Il a déjà été adapté un certain nombre de fois pour résoudre des
problèmes particuliers. Certains des outils du C++ combinent des bibliothèques, des modèles de composants et des
outils de génération de code pour résoudre les problèmes concernant le développement d'applications fenêtrées
(pour Microsoft Windows). Et pourtant, la vaste majorité des développeurs Windows utilisent Microsoft Visual Basic
(VB). Et ceci malgré le fait que VB produise le genre de code qui devient ingérable quand le programme fait plus de
quelques pages de long (sans compter que la syntaxe peut être profondément mystérieuse). Aussi populaire que soit
VB, ce n'est pas un très bon exemple de conception de langage. Il serait agréable de pouvoir disposer des facilités
et de la puissance fournies par VB sans se retrouver avec ce code ingérable. Et c'est là où je pense que Java va
pouvoir briller : comme le « VB du futur ». On peut frissonner en entendant ceci, mais Java est conçu pour aider le
développeur à résoudre des problèmes comme les applications réseau ou interfaces utilisateur multiplateformes, et
la conception du langage permet la création de portions de code très importantes, mais néanmoins flexibles. Ajoutons
à ceci le fait que Java dispose des systèmes de vérifications de types et de gestion des erreurs les plus robustes
que j'ai jamais rencontrés dans un langage et on se retrouve avec les éléments constitutifs d'un bond significatif dans
l'amélioration de la productivité dans la programmation.

Faut-il utiliser Java en lieu et place du C++ dans les projets ? En dehors des applets Web, il y a deux points à
considérer. Premièrement, si on veut réutiliser un certain nombre de bibliothèques C++ (et on y gagnera certainement
en productivité), ou si on dispose d'une base existante en C ou C++, Java peut ralentir le développement plutôt que
l'accélérer.

Si on développe tout le code en partant de zéro, alors la simplicité de Java comparée au C++ réduira significativement
le temps de développement - des anecdotes (selon des équipes C++ à qui j'ai parlé après qu'ils eurent changé pour
Java) suggèrent un doublement de la vitesse de développement comparé au C++. Si les performances moindres de
Java ne rentrent pas en ligne de compte ou qu'on peut les compenser, les contraintes de temps font qu'il est difficile
de choisir le C++ au détriment de Java.

Le point le plus important est la performance. Java interprété est lent, environ 20 à 50 fois plus lent que le C dans
les interpréteurs Java originels. Ceci a été grandement amélioré avec le temps, mais il restera toujours un important
facteur de différence. Les ordinateurs existent de par leur rapidité ; si ce n'était pas considérablement plus rapide de
réaliser une tâche sur ordinateur, on la ferait à la main. J'ai même entendu suggérer de démarrer avec Java, pour

- 63 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

gagner sur le temps de développement plus court, et ensuite utiliser un outil et des bibliothèques de support pour
traduire le code en C++ si on a un besoin de vitesse d'exécution plus rapide.

La clef pour rendre Java viable dans la plupart des projets consiste en des améliorations de vitesse d'exécution,
grâce à des compilateurs « juste à temps » (« just in time », JIT), la technologie « hotspot » de Sun, et même
des compilateurs de code natif. Bien sûr, les compilateurs de code natif éliminent les possibilités d'exécution
interplateforme du programme compilé, mais la vitesse des exécutables produits se rapprochera de celle du C et du
C++. Et réaliser un programme multiplateforme en Java devrait être beaucoup plus facile qu'en C ou C++ (en théorie,
il suffit de recompiler, mais cette promesse a déjà été faite pour les autres langages).

Vous trouverez des comparaisons entre Java et C++ et des observations sur Java dans les annexes de la première
édition de ce livre (disponible sur le CD ROM accompagnant ce livre, et à www.BruceEckel.com).

III-O - Résumé

Ce chapitre tente de vous donner un aperçu des sujets couverts par la programmation orientée objet et Java
(les raisons qui font que la POO est particulière, de même que Java), les concepts des méthodologies de la
POO, et finalement le genre de problèmes que vous rencontrerez quand vous migrerez dans votre entreprise à la
programmation orientée objet et Java.

La POO et Java ne sont pas forcément destinés à tout le monde. Il est important d'évaluer ses besoins et décider
si Java satisfera au mieux ces besoins, ou si un autre système de programmation ne conviendrait pas mieux (celui
qu'on utilise actuellement y compris). Si on connaît ses besoins futurs et qu'ils impliquent des contraintes spécifiques
non satisfaites par Java, alors on se doit d'étudier les alternatives existantes (14) . Et même si finalement Java est
retenu, on saura au moins quelles étaient les options et les raisons de ce choix.

On sait à quoi ressemble un programme procédural : des définitions de données et des appels de fonctions. Pour
trouver le sens d'un tel programme, il faut se plonger dans la chaîne des appels de fonctions et des concepts de bas
niveau pour se représenter le modèle du programme. C'est la raison pour laquelle on a besoin de représentations
intermédiaires quand on conçoit des programmes procéduraux - par nature, ces programmes tendent à être confus,
car le code utilise des termes plus orientés vers la machine que vers le problème qu'on tente de résoudre.

Parce que Java introduit de nombreux nouveaux concepts par rapport à ceux qu'on trouve dans un langage
procédural, on pourrait se dire que la fonction main() dans un programme Java sera bien plus compliquée que son
équivalent dans un programme C. On sera agréablement surpris de constater qu'un programme Java bien écrit est
généralement beaucoup plus simple et facile à comprendre que son équivalent en C. On n'y voit que les définitions
des objets qui représentent les concepts de l'espace problème (plutôt que leur représentation dans l'espace machine)
et les messages envoyés à ces objets pour représenter les activités dans cet espace. L'un des avantages de la POO
est qu'avec un programme bien conçu, il est facile de comprendre le code en le lisant. De plus, il y a généralement
moins de code, car beaucoup de problèmes sont résolus en réutilisant du code existant dans des bibliothèques.

IV - Tout est « objet »

Bien qu'il soit basé sur C++, Java est un langage orienté objet plus « pur ».

C++ et Java sont tous les deux des langages hybrides, mais dans Java, les concepteurs ont pensé que l'hybridation
est moins importante qu'elle ne l'est en C++. Un langage hybride autorise plusieurs styles de programmation : C
++ est hybride pour assurer la compatibilité avec le langage C. Comme C++ est une extension du langage C, il
contient un grand nombre des particularités indésirables de ce langage, ce qui peut rendre certains aspects du C+
+ particulièrement embrouillés.

Le langage Java suppose qu'on ne veut faire que de la programmation orientée objet (POO). Ceci signifie qu'avant de
pouvoir commencer il faut tourner sa vision des choses vers un monde orienté objet (à moins qu'elle ne le soit déjà).
L'avantage de cet effort préliminaire est la capacité à programmer dans un langage qui est plus simple à apprendre

- 64 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

et à utiliser que beaucoup d'autres langages de POO. Dans ce chapitre, nous verrons les composantes de base d'un
programme Java et nous apprendrons que tout dans Java est objet, même un programme Java.

IV-A - Les objets sont manipulés avec des références

Chaque langage de programmation a ses propres façons de manipuler les données. Parfois le programmeur doit être
constamment conscient du type des manipulations en cours. Manipulez-vous l'objet directement, ou avez-vous affaire
à une sorte de représentation indirecte (un pointeur en C ou C++) qui doit être traitée avec une syntaxe particulière ?

Tout ceci est simplifié en Java. On considère tout comme des objets, ainsi il n'y a qu'une seule syntaxe cohérente
qui est utilisée partout. Bien qu'on traite tout comme des objets, les identificateurs qui sont manipulés sont en réalité
des« références » vers des objets (15) . On pourrait imaginer cette situation comme une télévision (l'objet) avec une
télécommande (la référence). Tant qu'on conserve cette référence, on a une liaison vers la télévision, mais quand
quelqu'un dit « change de chaîne » ou « baisse le volume », ce qu'on manipule est la référence, qui en retour modifie
l'objet. Si on veut se déplacer dans la pièce tout en contrôlant la télévision, on emporte la télécommande/référence,
pas la télévision.

De plus, la télécommande peut exister par elle-même sans télévision. C'est-à-dire que le fait d'avoir une référence
ne signifie pas nécessairement qu'un objet y soit associé. Ainsi, si on veut avoir un mot ou une phrase, on crée une
référence sur une String :

String s;

Mais on a seulement créé la référence, pas un objet. À ce point, si on décidait d'envoyer un message à s, on aurait
une erreur (lors de l'exécution) parce que s n'est pas rattachée à quoi que ce soit (il n'y a pas de télévision). Une
pratique plus sure est donc de toujours initialiser une référence quand on la crée :

String s = "asdf";

Toutefois, ceci utilise une caractéristique spéciale de Java : les chaînes de caractères peuvent être initialisées avec
du texte entre guillemets. Normalement, on doit utiliser un type d'initialisation plus général pour les objets.

IV-B - Vous devez créer tous les objets

Quand on crée une référence, on veut la connecter à un nouvel objet. Ceci se fait, en général, avec le mot-clef new.
new veut dire« fabrique-moi un de ces objets ». Ainsi, dans l'exemple précédent, on peut dire :

String s = new String("asdf");

Ceci ne veut pas seulement dire « fabrique-moi un nouvel objet String », mais cela donne aussi une information sur
comment fabriquer l'objet String en fournissant une chaîne de caractères initiale.

Bien sûr, String n'est pas le seul type qui existe. Java propose une pléthore de types tout prêts. Le plus important est
qu'on puisse créer ses propres types. En fait, c'est l'activité fondamentale en programmation Java et c'est ce qu'on
apprendra à faire dans la suite de ce livre.

IV-B-1 - Où réside la mémoire ?

Il est utile de visualiser certains aspects de comment les choses sont arrangées lorsque le programme tourne, en
particulier comment la mémoire est organisée. Il y a six endroits différents pour stocker les données :

1 Les registres. C'est le stockage le plus rapide, car il se trouve à un endroit différent des autres zones de
stockage : dans le processeur. Toutefois, le nombre de registres est sévèrement limité, donc les registres sont

- 65 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

alloués par le compilateur en fonction de ses besoins. On n'a aucun contrôle direct et il n'y a même aucune
trace de l'existence des registres dans les programmes.
2 La pile. Elle se trouve dans la RAM (random access memory), mais elle est prise en compte directement par
le processeur via son pointeur de pile. Le pointeur de pile est déplacé vers le bas pour créer plus d'espace
mémoire et déplacé vers le haut pour libérer cet espace. C'est un moyen extrêmement efficace et rapide
d'allouer de la mémoire, supplanté seulement par les registres. Le compilateur Java doit connaître, lorsqu'il
crée le programme, la taille et la durée de vie exacte de toutes les données qui sont rangées sur la pile, parce
qu'il doit générer le code pour déplacer le pointeur de pile vers le haut et vers le bas. Cette contrainte met
des limites à la flexibilité des programmes, donc bien qu'il y ait du stockage Java sur la pile - en particulier les
références aux objets - les objets Java eux-mêmes ne sont pas placés sur la pile.
3 Le segment. C'est une réserve de mémoire d'usage général (aussi en RAM) où résident tous les objets
Java. La bonne chose à propos du segment est que, contrairement à la pile, le compilateur n'a pas besoin
de savoir combien de place il a besoin d'allouer sur le segment ni combien de temps cette place doit rester
sur le segment. Ainsi, il y a une grande flexibilité à utiliser la mémoire sur le segment. Lorsqu'on a besoin de
créer un objet, il suffit d'écrire le code pour le créer en utilisant new et la mémoire est allouée sur le segment
lorsque le programme s'exécute. Bien entendu il y a un prix à payer pour cette flexibilité : il faut plus de temps
pour allouer de la mémoire sur le segment qu'il n'en faut pour allouer de la mémoire sur la pile (c'est-à-dire si
on avait la possibilité de créer des objets sur la pile en Java, comme on peut le faire en C++).
4 La mémoire statique. « Statique » est utilisé ici dans le sens « à un endroit fixe » (bien que ce soit aussi
dans la RAM). La mémoire statique contient les données qui sont disponibles pendant tout le temps
d'exécution du programme. On peut utiliser le mot-clef static pour spécifier qu'un élément particulier d'un
objet est statique, mais les objets Java par eux-mêmes ne sont jamais placés dans la mémoire statique.
5 Les constantes. Les valeurs des constantes sont souvent placées directement dans le code du programme,
ce qui est sûr puisqu'elles ne peuvent jamais changer. Parfois les constantes sont isolées de façon à pouvoir
être optionnellement placées dans une mémoire accessible en lecture seulement (ROM).
6 Stockage hors RAM. Si les données résident entièrement hors du programme, elles peuvent exister même
quand le programme ne tourne pas, en dehors du contrôle du programme. Les deux exemples de base sont
les flots de données, pour lesquels les données sont transformées en flots d'octets, généralement pour
être transmises vers une autre machine, et les objets persistants, pour lesquels les objets sont placés sur
disque de façon à ce qu'ils conservent leur état même après que le programme soit terminé. L'astuce avec
ces types de stockage est de transformer les objets en quelque chose qui peut exister sur l'autre support, tout
en pouvant être ressuscité en un objet normal en mémoire, lorsque c'est nécessaire. Java fournit des outils
pour la persistance légère, et les versions futures pourraient fournir des solutions plus complètes pour la
persistance.

IV-B-2 - Cas particulier : les types primitifs

Il y a un ensemble de types qui sont soumis à un traitement particulier ; ils peuvent être considérés comme les types
« primitifs » fréquemment utilisés en programmation. La raison de ce traitement particulier est que la création d'un
objet avec new - en particulier une simple variable - n'est pas très efficace parce que new place les objets sur le
segment. Pour ces types, Java a recours à l'approche retenue en C et en C++. Au lieu de créer la variable en utilisant
new, une variable « automatique », qui n'est pas une référence, est créée. La variable contient la valeur et elle est
placée sur la pile, ce qui est beaucoup plus efficace.

Java fixe la taille de chacun des types primitifs. Ces tailles ne changent pas d'une architecture de machine à une
autre, comme c'est le cas dans la plupart des langages. L'invariance de la taille de ces types est l'une des raisons
pour lesquelles Java est si portable.

- 66 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Type primitif Taille Minimum Maximum Type wrapper


boolean - - - Boolean
char 16-bit Unicode 0 Unicode 216- 1 Character
byte 8-bit -128 +127 Byte
short 16-bit -215 +215-1 Short
int 32-bit -231 +231-1 Integer
long 64-bit -263 +263-1 Long
float 32-bit IEEE754 IEEE754 Float
double 64-bit IEEE754 IEEE754 Double
void - - - Void

Tous les types numériques sont signés, il est donc inutile d'aller chercher après des types non signés.

Les types de données primitifs sont aussi associés à des classes« wrapper ». Ceci signifie que pour faire un objet
non primitif sur le segment pour représenter ce type primitif il faut utiliser le wrapper associé. Par exemple :

char c = 'x';Character C =
new Character(c);

On peut aussi utiliser :

Character C = new
Character('x');

Les raisons pour lesquelles on fait ceci seront indiquées dans un prochain chapitre.

IV-B-2-a - Nombres de grande précision

Java contient deux classes pour effectuer des opérations arithmétiques de grande précision : BigInteger et
BigDecimal. Bien que ceux-ci soient dans la même catégorie que les classes « wrapper », aucun d'eux n'a d'analogue
primitif.

Chacune de ces classes a des méthodes qui fournissent des opérations analogues à celles qu'on peut faire sur les
types primitifs. C'est-à-dire qu'avec un BigInteger ou un BigDecimal on peut faire tout ce qu'on peut faire avec un
int ou un float, seulement il faut utiliser des appels de méthodes au lieu des opérateurs. Par ailleurs, comme elles
en font plus, les opérations sont plus lentes. On échange la vitesse contre la précision.

BigInteger sert aux entiers de précision arbitraire. C'est-à-dire qu'ils permettent de représenter des valeurs entières
de n'importe quelle taille sans perdre aucune information au cours des opérations.

BigDecimal sert aux nombres à virgule fixe de précision arbitraire ; par exemple, on peut les utiliser pour des calculs
monétaires précis.

Il faut se reporter à la documentation en ligne pour obtenir des détails sur les constructeurs et méthodes utilisables
avec ces deux classes.

IV-B-3 - Tableaux en Java

Pratiquement tous les langages de programmation gèrent les tableaux. Utiliser des tableaux en C ou C++ est
dangereux, car ces tableaux ne sont que des blocs de mémoire. Si un programme accède à un tableau en dehors de
son bloc mémoire, ou s'il utilise la mémoire avant initialisation (erreurs de programmation fréquentes) les résultats
seront imprévisibles.

- 67 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Un des principaux objectifs de Java est la sécurité, aussi, un grand nombre des problèmes dont souffrent C et C+
+ ne sont pas répétés en Java. On est assuré qu'un tableau Java est initialisé et qu'il ne peut pas être accédé en
dehors de ses bornes. La vérification des bornes se fait au prix d'un petit excédent de mémoire pour chaque tableau
ainsi que de la vérification de l'index lors de l'exécution, mais on suppose que le gain en sécurité et en productivité
vaut la dépense.

Quand on crée un tableau d'objets, on crée en réalité un tableau de références, et chacune de ces références est
automatiquement initialisée à une valeur particulière avec son propre mot-clé : null. Quand Java voit null, il reconnaît
que la référence en question ne pointe pas vers un objet. Il faut affecter un objet à chaque référence avant de l'utiliser
et si on essaye d'utiliser une référence encore à null, le problème sera signalé lors de l'exécution. Ainsi, les erreurs
typiques sur les tableaux sont évitées en Java.

On peut aussi créer des tableaux de variables de type primitif. À nouveau, le compilateur garantit l'initialisation, car
il met à zéro la mémoire utilisée par ces tableaux.

Les tableaux seront traités plus en détail dans d'autres chapitres.

IV-C - Vous n'avez jamais besoin de détruire un objet

Dans la plupart des langages de programmation, le concept de durée de vie d'une variable monopolise une part
significative des efforts de programmation. Combien de temps une variable existe-t-elle ? S'il faut la détruire, quand
faut-il le faire ? Des erreurs sur la durée de vie des variables peuvent être la source de nombreux bogues et cette
partie montre comment Java simplifie énormément ce problème en faisant le ménage tout seul.

IV-C-1 - Notion de portée

La plupart des langages procéduraux ont le concept de portée. Il fixe simultanément la visibilité et la durée de vie
des noms définis dans cette portée. En C, C++ et Java, la portée est fixée par l'emplacement des accolades {}. Ainsi,
par exemple :

{
int x = 12;
/* seul x est accessible */
{
int q = 96;
/* x & q sont tous les deux accessibles */
}
/* seul x est accessible */
/* q est « hors de portée » */
}

Une variable définie dans une portée n'est accessible que jusqu'à la fin de cette portée.

L'indentation rend le code Java plus facile à lire. Étant donné que Java est un langage indépendant de la mise en
page, les espaces, tabulations et retours chariots supplémentaires ne changent pas le programme.

Il faut remarquer qu'on ne peut pas faire la chose suivante, bien que cela soit autorisé en C et C++ :

{
int x = 12;
{
int x = 96; /* illegal */
}
}

- 68 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Le compilateur annoncera que la variable x a déjà été définie. Ainsi, la faculté du C et du C++ à « cacher » une
variable d'une portée plus étendue n'est pas autorisée parce que les concepteurs de Java ont pensé que ceci mène
à des programmes confus.

IV-C-2 - Portée des objets

Les objets Java n'ont pas la même durée de vie que les variables primitives. Quand on crée un objet Java avec new,
il existe toujours après la fin de la portée. Ainsi, si on fait :

{
String s = new String("a string");
} /* fin de portée */

la référence s disparaît à la fin de la portée. Par contre l'objet String sur lequel s pointait occupe toujours la
mémoire. Dans ce bout de code, il n'y a aucun moyen d'accéder à l'objet parce que son unique référence est hors
de portée. Dans d'autres chapitres, on verra comment la référence à un objet peut être transmise et dupliquée dans
un programme.

Il s'avère que du simple fait qu'un objet créé avec new reste disponible tant qu'on le veut, tout un tas de problèmes de
programmation du C++ disparaissent tout simplement en Java. Il semble que les problèmes les plus durs surviennent
en C++ parce que le langage ne fournit aucune aide pour s'assurer que les objets sont disponibles quand on en
a besoin. Et, encore plus important, en C++ on doit s'assurer qu'on détruit bien les objets quand on en a terminé
avec eux.

Ceci amène une question intéressante. Si Java laisse les objets traîner, qu'est-ce qui les empêche de complètement
remplir la mémoire et d'arrêter le programme ? C'est exactement le problème qui surviendrait dans un programme
C++. C'est là qu'un peu de magie apparaît. Java a un ramasse-miettes qui surveille tous les objets qui ont été créés
avec new et qui arrive à deviner lesquels ne sont plus référencés. Ensuite, il libère la mémoire de ces objets de façon
à ce que cette mémoire puisse être utilisée pour de nouveaux objets. Ceci signifie qu'il ne faut jamais s'embêter à
récupérer la mémoire soi-même. On crée simplement les objets, et quand on n'en a plus besoin, ils disparaissent
d'eux-mêmes. Ceci élimine toute une classe de problèmes de programmation : les soi-disant « fuites de mémoire »
qui arrivent quand un programmeur oublie de libérer la mémoire.

IV-C-2-a - Valeurs par défaut des membres primitifs

Quand une donnée d'un type primitif est membre d'une classe, on est assuré qu'elle a une valeur par défaut si on
ne l'initialise pas :

Type primitif Valeur par défaut


boolean false
char `\u0000' (null)
byte (byte)0
short (short)0
int 0
long 0L
float 0.0f
double 0.0d

Par prudence, il faut remarquer que les valeurs par défaut sont celles que Java garantit quand la variable est utilisée
comme un membre d'une classe. Ceci assure que les variables membres de type primitif sont toujours initialisées
(parfois C++ ne le fait pas), ce qui supprime une source de bogues. Toutefois, cette valeur initiale peut ne pas être
correcte ou même légale pour le programme qui est écrit. Il est préférable de toujours initialiser explicitement les
variables.

- 69 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Cette garantie ne s'applique pas aux variables « locales » - celles qui ne sont pas des champs d'une classe. Ainsi,
si dans la définition d'une fonction, on a :

int x;

Alors x aura une valeur arbitraire (comme en C et C++), il ne sera pas initialisé automatiquement à zéro. On a la
responsabilité d'affecter une valeur appropriée avant d'utiliser x. Si on oublie de le faire, Java est sans aucun doute
mieux conçu que C++ sur ce point : on obtient une erreur de compilation qui dit que la variable pourrait ne pas être
initialisée (avec beaucoup de compilateurs C++, on a des avertissements concernant les variables non initialisées,
mais avec Java ce sont des erreurs).

IV-D - Créer de nouveaux types de données : class

Si tout est objet, qu'est-ce qui définit à quoi ressemble une classe particulière d'objets et comment elle se comporte ?
Autrement dit, qu'est-ce qui constitue le type d'un objet ? On pourrait s'attendre à avoir un mot-clef appelé« type », et
cela serait parfaitement sensé. Historiquement, toutefois, la plupart des langages orientés objet ont utilisé le mot-clef
class qui signifie « je vais décrire à quoi ressemble un nouveau type d'objet ». Le mot-clef class (qui est si commun
qu'il ne sera plus mis en gras dans la suite de ce livre) est suivi par le nom du nouveau type. Par exemple :

class ATypeName { /* le corps de la classe vient ici */ }

Ceci introduit un nouveau type, on peut alors créer un objet de ce type en utilisant new :

ATypeName a = new ATypeName();

Dans ATypeName , le corps de la classe ne consiste qu'en un commentaire (les étoiles et barres obliques et ce
qu'il y a à l'intérieur, ce qui sera décrit ultérieurement dans ce chapitre), donc il n'y pas grand-chose à faire avec.
En fait, on ne peut pas lui dire de faire quoi que ce soit (c'est-à-dire qu'on ne peut pas lui transmettre de message
intéressant) tant qu'on n'y définit pas de méthodes.

Lorsqu'on définit une classe (et tout ce que l'on fait en Java consiste à définir des classes, fabriquer des objets à
partir de ces classes et envoyer des messages à ces objets) on peut mettre deux types d'éléments dans ces classes :
des données membres de la classe (aussi appelées champs) et des fonctions membres de la classe (habituellement
appelées méthodes). Une donnée membre est un objet de n'importe quel type avec lequel on peut communiquer via
sa référence. Il peut aussi s'agir d'un des types primitifs (dans ce cas, ce n'est pas une référence). S'il s'agit d'une
référence à un objet, il faut initialiser cette référence pour la connecter à un objet réel (en utilisant new comme indiqué
précédemment) grâce à une fonction particulière appelée un constructeur (entièrement décrit dans le titre VI). S'il
s'agit d'un type primitif il est possible de l'initialiser directement lors de sa définition dans la classe (comme on le verra
plus tard, les références peuvent aussi être initialisées lors de la définition).

Chaque objet met ses données membres dans sa zone de mémoire propre, les données membres ne sont pas
partagées entre les objets. Voici un exemple de classe avec des données membres :

class DataOnly {
int i;
float f;
boolean b;
}

Cette classe ne fait rien, mais on peut créer un objet :

DataOnly d = new DataOnly();

On peut affecter des valeurs aux données membres, mais il faut d'abord savoir comment faire référence à un membre
d'un objet. Ceci s'effectue en indiquant le nom de la référence à l'objet, suivi par un point, suivi par le nom du membre
dans l'objet :

- 70 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

objectReference.member

Par exemple :

d.i = 47;
d.f = 1.1f;
d.b = false;

Il est aussi possible que l'objet puisse contenir d'autres objets qui contiennent des données que l'on souhaite modifier.
Pour cela il suffit de continuer à « associer les points ». Par exemple :

myPlane.leftTank.capacity = 100;

La classe DataOnly ne peut pas faire grand-chose à part contenir des données, car elle n'a pas de fonctions membres
(méthodes). Pour comprendre comment celles-ci fonctionnent, il faut d'abord comprendre les notions de paramètres
et de valeurs de retour, qui seront brièvement décrites.

IV-E - Méthodes, paramètres et valeurs de retour

Jusqu'à présent le terme fonction a été employé pour désigner une sous-routine nommée. Le terme qui est plus
généralement employé en Java est méthode, en tant que « moyen de faire quelque chose ». Il est possible, si on le
souhaite, de continuer à raisonner en termes de fonctions. Il s'agit simplement d'une différence de syntaxe, mais à
partir de maintenant on utilisera « méthode » plutôt que fonction, dans ce livre.

Les méthodes en Java définissent les messages qu'un objet peut recevoir. Dans cette partie on verra à quel point
il est simple de définir une méthode.

Les éléments fondamentaux d'une méthode sont le nom, les paramètres, le type de retour et le corps. Voici la forme
de base :

returnType methodName( /* liste de paramètres */ ) {


/* corps de la méthode */
}

Le type de retour est le type de la valeur qui est retournée par la méthode après son appel. La liste de paramètres
donne le type et le nom des informations qu'on souhaite passer à la méthode. L'association du nom de la méthode
et de la liste de paramètres identifie de façon unique la méthode.

En Java, les méthodes ne peuvent être créées que comme une composante d'une classe. Une méthode ne peut
être appelée que pour un objet (16) et cet objet doit être capable de réaliser cet appel de méthode. Si on essaye
d'appeler une mauvaise méthode pour un objet, on obtient un message d'erreur lors de la compilation. On appelle
une méthode pour un objet en nommant l'objet suivi d'un point, suivi du nom de la méthode et de sa liste d'arguments,
comme ça : objectName.methodName(arg1, arg2, arg3). Par exemple, si on suppose qu'on a une méthode f( )
qui ne prend aucun paramètre et qui retourne une valeur de type int. Alors, si on a un objet appelé a pour lequel
f( ) peut être appelé, on peut écrire :

int x = a.f();

Le type de la valeur de retour doit être compatible avec le type dex.

On appelle généralement envoyer un message à un objet cet acte d'appeler une méthode. Dans l'exemple
précédent, le message est f() et l'objet est a. La programmation orientée objet est souvent simplement ramenée à
« envoyer des messages à des objets ».

- 71 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

IV-E-1 - La liste de paramètres

La liste de paramètres de la méthode spécifie quelles informations on passe à la méthode. Comme on peut le
supposer, ces informations -- comme tout le reste en Java -- sont sous la forme d'objets. On doit donc indiquer
dans la liste de paramètres les types des objets à transmettre et les noms à employer pour chacun. Comme dans
toutes les situations où on a l'impression de manipuler des objets, en Java on passe effectivement des références
name="fnB23"> (17) . Toutefois, le type de la référence doit être correct. Si le paramètre est censé être un objet de
type String, ce qu'on transmet doit être de ce type.

Considérons une méthode qui prend un objet de classe String en paramètre. Voici la définition qui doit être mise à
l'intérieur de la définition d'une classe pour qu'elle soit compilée :

int storage(String s) {
return s.length() * 2;
}

Cette méthode indique combien d'octets sont nécessaires pour contenir une String donnée (chaque char dans une
String fait 16 bits, ou deux octets, pour permettre les caractères Unicode). Le paramètre est de type String et il est
appelé s. Une fois que s est passé à une méthode, il peut être traité comme n'importe quel autre objet (on peut lui
envoyer des messages). Ici, on appelle la méthode length( ) qui est une des méthodes de la classe String ; elle
retourne le nombre de caractères que contient la chaîne.

On peut aussi voir l'utilisation du mot-clef return qui fait deux choses. D'abord, il signifie « quitte la méthode, j'ai
terminé ». Ensuite, si la méthode retourne une valeur, cette valeur est placée juste après la déclaration du return.
Dans le cas présent, la valeur de retour est produite en évaluant l'expression s.length( ) * 2.

On peut retourner des valeurs de tous les types qu'on souhaite, mais si on souhaite ne rien retourner du tout on peut
le faire en indiquant que la méthode retourne void. Voici quelques exemples :

boolean flag() { return true; }


float naturalLogBase() { return 2.718f; }
void nothing() { return; }
void nothing2() {}

Quand le type de retour est void, alors le mot-clef return n'est utilisé que pour sortir de la méthode, il n'est donc pas
nécessaire quand on atteint la fin de la méthode. On peut retourner d'une méthode à n'importe quel endroit, mais
si on a indiqué un type de retour qui n'est pas void alors le compilateur imposera (avec des messages d'erreur) un
retour avec une valeur d'un type approprié sans tenir compte de l'endroit auquel le retour se produit.

À ce point, on peut penser qu'un programme n'est qu'un paquet d'objets avec des méthodes qui prennent d'autres
objets en paramètres pour transmettre des messages à ces autres objets. C'est effectivement l'essentiel de ce qui
se passe, mais dans les chapitres suivants on verra comment faire le travail de bas niveau en prenant des décisions
au sein d'une méthode. Pour ce chapitre, envoyer des messages est suffisant.

IV-F - Construction d'un programme Java

Il y a plusieurs autres éléments à comprendre avant de voir le premier programme Java.

IV-F-1 - Visibilité des noms

Un problème commun à tous les langages de programmation est le contrôle des noms. Si on utilise un nom dans un
module du programme et si un autre programmeur utilise le même nom dans un autre module, comment distingue-
t-on un nom d'un autre et comment empêche-t-on les « collisions » de noms ? En C c'est un problème particulier,
car un programme est souvent un océan de noms incontrôlable. Les classes C++ (sur lesquelles les classes Java
sont basées) imbriquent les fonctions dans les classes de telle sorte qu'elles ne peuvent pas entrer en collision avec

- 72 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

les noms de fonctions imbriqués dans d'autres classes. Toutefois, C++ autorise toujours les données et les fonctions
globales, donc les collisions sont toujours possibles. Pour résoudre ce problème, C++ a introduit les domaines de
noms (namespace) en utilisant des mots-clefs supplémentaires.

Java a pu éviter tout cela en employant une approche originale. Pour générer sans ambiguïté un nom pour une
bibliothèque, le spécificateur utilisé n'est pas très différent d'un nom de domaine Internet. En fait, les créateurs de
Java veulent qu'on utilise son propre nom de domaine Internet inversé, puisqu'on est assuré que ceux-ci sont uniques.
Puisque mon nom de domaine est BruceEckel.com, ma bibliothèque d'utilitaires (utility) pour mes marottes (foibles)
devrait être appelée com.bruceeckel.utility.foibles. Après avoir inversé le nom de domaine, les points sont destinés
à représenter des sous-répertoires.

Dans Java 1.0 et Java 1.1 les extensions de domaines com, edu, org, net, etc. étaient mises en lettres capitales
par convention, ainsi la bibliothèque serait :COM.bruceeckel.utility.foibles. Toutefois, au cours du développement
de Java 2, on s'est rendu compte que cela causait des problèmes et par conséquent les noms de packages sont
entièrement en lettres minuscules.

Ce mécanisme signifie que tous les fichiers existent automatiquement dans leur propre domaine de nom et toutes les
classes contenues dans un fichier donné doivent avoir un identificateur unique. Ainsi, on n'a pas besoin d'apprendre
de particularités spécifiques au langage pour résoudre ce problème - le langage s'en occupe à votre place.

IV-F-2 - Utilisation d'autres composantes

Lorsqu'on souhaite utiliser une classe prédéfinie dans un programme, le compilateur doit savoir comment la localiser.
Bien entendu, la classe pourrait déjà exister dans le même fichier source que celui d'où elle est appelée. Dans ce cas
on utilise simplement la classe - même si la classe n'est définie que plus tard dans le fichier. Java élimine le problème
des « références anticipées », il n'y a donc pas à s'en préoccuper.

Qu'en est-il des classes qui existent dans un autre fichier ? On pourrait penser que le compilateur devrait être
suffisamment intelligent pour aller simplement la chercher lui-même, mais il y a un problème. Imaginons que l'on
veuille utiliser une classe ayant un nom spécifique, mais qu'il existe plus d'une classe ayant cette définition (il s'agit
probablement de définitions différentes). Ou pire, imaginons que l'on écrive un programme et qu'en le créant on ajoute
à sa bibliothèque une nouvelle classe qui entre en conflit avec le nom d'une classe déjà existante.

Pour résoudre ce problème, il faut éliminer les ambiguïtés potentielles. Ceci est réalisé en disant exactement au
compilateur Java quelles classes on souhaite, en utilisant le mot-clef import. import dit au compilateur d'introduire
un package qui est une bibliothèque de classes (dans d'autres langages, une bibliothèque pourrait comporter des
fonctions et des données au même titre que des classes, mais il faut se rappeler que tout le code Java doit être
écrit dans des classes).

La plupart du temps, on utilise des composantes des bibliothèques Java standard qui sont fournies avec le
compilateur. Avec celles-ci il n'y a pas à se tracasser à propos des longs noms de domaines inversés ; il suffit de
dire, par exemple :

import java.util.ArrayList;

pour dire au compilateur que l'on veut utiliser la classe JavaArrayList. Toutefois, util contient de nombreuses classes
et on pourrait vouloir utiliser plusieurs d'entre elles sans les déclarer explicitement. Ceci est facilement réalisé en
utilisant '*' pour indiquer un joker :

import java.util.*;

Il est plus courant d'importer une collection de classes de cette manière que d'importer les classes individuellement.

- 73 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

IV-F-3 - Le mot-clef static

Normalement, quand on crée une classe, on décrit ce à quoi ressemblent les objets de cette classe et comment ils
se comportent. Rien n'existe réellement avant de créer un objet de cette classe avec new ; à ce moment la zone de
données est créée et les méthodes deviennent disponibles.

Mais il y a deux situations pour lesquelles cette approche n'est pas suffisante. L'une, si on veut avoir une zone de
stockage pour des données spécifiques, sans tenir compte du nombre d'objets créés, ou même si aucun objet n'a été
créé. L'autre, si on a besoin d'une méthode qui n'est associée à aucun objet particulier de la classe. C'est-à-dire si on a
besoin d'une méthode qui puisse être appelée même si aucun objet n'a été créé. On peut obtenir ces deux effets avec
le mot-clef static. Dire que quelque chose est static signifie que la donnée ou la méthode n'est pas spécifiquement
rattachée à un objet instance de cette classe. Donc, même si aucun objet de cette classe n'a jamais été créé il
est possible d'appeler une méthode static ou d'accéder à une donnée static. Avec des données et des méthodes
non static ordinaires il faut connaître l'objet spécifique avec lequel elles fonctionnent. Bien entendu, étant donné
que les méthodes static n'ont pas besoin qu'un objet soit créé avant d'être utilisées, elles ne peuvent pas accéder
directement à des membres ou des méthodes non static en appelant ces autres membres sans faire référence à
un objet nommé (puisque les membres et méthodes non static doivent être rattachés à un objet spécifique).

Certains langages orientés objet emploient les expressions données de classe et méthodes de classe, ce qui
signifie que les données et les méthodes n'existent que pour la classe en tant que tout et pas pour des objets
particuliers de la classe. Parfois la littérature Java utilise aussi ces expressions.

Pour rendre statique une méthode ou une donnée membre il suffit de mettre le mot-clef static avant la définition. Par
exemple, le code suivant crée une donnée membre static et l'initialise :

class StaticTest {
static int i = 47;
}

Maintenant, même en créant deux objets StaticTest, il n'y aura qu'une seule zone de stockage pour StaticTest.i.
Tous les objets partageront le même i. Considérons :

StaticTest st1 = new StaticTest();


StaticTest st2 = new StaticTest();

à ce point, st1.i et st2.i ont la même valeur 47 puisqu'elles font référence à la même zone mémoire.

Il y a deux façons de faire référence à une variable static. Comme indiqué ci-dessus, il est possible de la nommer
via un objet, en disant par exemple st2.i. Il est aussi possible d'y faire référence directement par le nom de la classe,
ce qui ne peut pas être fait avec un membre non static (c'est le moyen de prédilection pour faire référence à une
variable static puisque cela met en évidence la nature static de la variable).

StaticTest.i++;

L'opérateur ++ incrémente la variable. À ce point, st1.i et st2.i auront tous deux la valeur 48.

Une logique similaire s'applique aux méthodes statiques. On peut faire référence à une méthode statique soit par
l'intermédiaire d'un objet, comme on peut le faire avec n'importe quelle méthode, ou avec la syntaxe spécifique
supplémentaire ClassName.method( ). Une méthode statique est définie de façon similaire :

class StaticFun {
static void incr() { StaticTest.i++; }
}

On peut voir que la méthode incr( ) de StaticFun incrémente la donnée static i. On peut appeler incr( ) de façon
classique, par le biais d'un objet :

- 74 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

StaticFun sf = new StaticFun();


sf.incr();

Ou, parce que incr( ) est une méthode statique, il est possible de l'appeler directement par sa classe :

StaticFun.incr();

Alors que static, lorsqu'il est appliqué à une donnée membre, change sans aucun doute la façon dont la donnée
est créée (une pour chaque classe par opposition à une pour chaque objet dans le cas des données non statiques),
lorsqu'il est appliqué à une méthode, le changement est moins significatif. Un cas important d'utilisation des méthodes
static est de permettre d'appeler cette méthode sans créer d'objet. C'est essentiel, comme nous le verrons, dans la
définition de la méthode main( ) qui est le point d'entrée pour exécuter une application.

Comme pour toute méthode, une méthode statique peut créer ou utiliser des objets nommés de son type, ainsi les
méthodes statiques sont souvent utilisées comme « berger » pour un troupeau d'instances de son propre type.

IV-G - Votre premier programme Java

Voici enfin notre premier programme. Il commence par écrire une chaîne de caractères, puis il écrit la date en utilisant
la classe Date de la bibliothèque standard de Java. Il faut remarquer qu'un style de commentaire supplémentaire est
introduit ici : le '//' qui est un commentaire jusqu'à la fin de la ligne.

// HelloDate.java
import java.util.*;
public class HelloDate {
public static void main(String[] args) {
System.out.println("Hello, it's: ");
System.out.println(new Date());
}
}

Si on retourne au début pour sélectionner java.lang puis System, on voit que la classe System a plusieurs champs
et si on sélectionne out on découvre que c'est un objet staticPrintStream. Puisqu'il est statique, on n'a pas besoin
de créer quoi que ce soit. L'objet out est toujours là et il suffit de l'utiliser. Ce qu'on peut faire avec out est défini par
son type : PrintStream. D'une façon très pratique, PrintStream est affiché dans la description comme un hyperlien,
ainsi, en cliquant dessus on voit la liste de toutes les méthodes qu'on peut appeler pour PrintStream. Il y en a un
certain nombre et elles seront décrites ultérieurement dans ce livre. Pour l'instant nous ne nous intéressons qu'à
println( ), qui veut dire « écrit ce que je te donne sur la console et passe à la ligne ». Ainsi, dans tout programme Java
on peut dire System.out.println("quelque chose") chaque fois qu'on souhaite écrire quelque chose sur la console.

Le nom de la classe est le même que celui du fichier. Quand on crée un programme autonome comme celui-là, une
des classes du fichier doit avoir le même nom que le fichier (le compilateur se plaint si on ne le fait pas). Cette classe
doit contenir une méthode appelée main( ) avec la signature suivante :

public static void main(String[] args);

Le mot-clef public signifie que la méthode est accessible au monde extérieur (décrit en détail dans le titre VII). Le
paramètre de main( ) est un tableau d'objets de type String. Le paramètre args n'est pas utilisé dans ce programme,
mais le compilateur Java insiste pour qu'il soit là, car il contient les paramètres invoqués sur la ligne de commande.

La ligne qui écrit la date est assez intéressante :

System.out.println(new Date());

Considérons le paramètre : un objet Date est créé juste pour transmettre sa valeur à println( ). Dès que cette
instruction est terminée, cette date est inutile et le ramasse-miettes peut venir le récupérer n'importe quand. On n'a
pas à s'occuper de s'en débarrasser.

- 75 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

IV-G-1 - Compilation et exécution

Pour compiler et exécuter ce programme, et tous les autres programmes de ce livre, il faut d'abord avoir un
environnement de programmation Java. Il y a un grand nombre d'environnements de développement, mais dans
ce livre nous supposerons que vous utilisez le JDK de Sun qui est gratuit. Si vous utilisez un autre système de
développement, vous devrez vous reporter à la documentation de ce système pour savoir comment compiler et
exécuter les programmes.

Connectez-vous à Internet et allez sur http://java.sun.com. Là, vous trouverez des informations et des liens qui vous
guideront pour télécharger et installer le JDK pour votre plate-forme.

Une fois que le JDK est installé et que vous avez configuré les informations relatives au chemin sur votre ordinateur
afin qu'il puisse trouver javac et java, téléchargez et décompressez le code source de ce livre (on peut le trouver
sur le CD-ROM qui est livré avec le livre ou sur www.BruceEckel.com). Ceci créera un sous-répertoire pour chacun
des chapitres de ce livre. Allez dans le sous-répertoire c02 et tapez :

javac HelloDate.java

Cette commande ne devrait produire aucune réponse. Si vous obtenez un message d'erreur de quelque sorte que
ce soit cela signifie que vous n'avez pas installé le JDK correctement et que vous devez corriger le problème.

Par contre, si vous obtenez simplement votre invite de commande vous pouvez taper :

java HelloDate

et vous obtiendrez en sortie le message ainsi que la date.

C'est le procédé que vous pouvez employer pour compiler et exécuter chacun des programmes de ce livre. Toutefois,
vous verrez que le code source de ce livre a aussi un fichier appelé makefile dans chaque chapitre, et celui-ci contient
les commandes « make » pour construire automatiquement les fichiers de ce chapitre. Reportez-vous à la page Web
de ce livre sur www.BruceEckel.com pour plus de détails sur la manière d'utiliser ces makefiles.

IV-H - Commentaires et documentation intégrée

Il y a deux types de commentaires en Java. Le premier est le commentaire traditionnel, style C, dont a hérité C
++. Ces commentaires commencent par /* et continuent, éventuellement sur plusieurs lignes, jusqu'à un */. Il faut
remarquer que de nombreux programmeurs commencent chaque ligne de continuation de commentaire avec *, on
voit donc souvent :

/* Ceci est un commentaire


* qui continue
* sur plusieurs lignes
*/

Il faut toutefois se rappeler que tout ce qui se trouve entre /* et */ est ignoré, il n'y a donc aucune différence avec :

/* Ceci est un commentaire qui


continue sur plusieurs lignes */

La seconde forme de commentaires vient du C++. C'est le commentaire sur une seule ligne qui commence avec //
et continue jusqu'à la fin de la ligne. Ce type de commentaire est pratique et souvent rencontré, car il est simple. Il
n'y a pas à se démener sur le clavier pour trouver / puis * (à la place il suffit d'appuyer deux fois sur la même touche)
et il n'est pas nécessaire de fermer le commentaire. On trouve donc fréquemment :

// Ceci est un commentaire sur une seule ligne

- 76 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

IV-H-1 - Commentaires de documentation

Un des plus solides éléments de Java est que les concepteurs n'ont pas considéré que l'écriture du code est la seule
activité importante - ils ont aussi pensé à sa documentation. Le plus gros problème avec la documentation de code
est probablement la maintenance de cette documentation. Si la documentation et le code sont séparés, ça devient
embêtant de changer la documentation chaque fois que le code change. La solution a l'air simple : relier le code et la
documentation. Le moyen le plus simple de le faire est de tout mettre dans le même fichier. Toutefois, pour compléter
le tableau il faut une syntaxe de commentaire particulière pour marquer la documentation particulière et un outil pour
extraire ces commentaires et les mettre sous une forme exploitable. C'est ce que Java a fait.

L'outil pour extraire les commentaires est appelé javadoc. Il utilise certaines technologies du compilateur Java pour
rechercher les marqueurs spécifiques des commentaires qui ont été mis dans les programmes. Il ne se contente pas
d'extraire les informations repérées par ces marqueurs, mais il extrait aussi le nom de classe ou le nom de méthode
adjoint au commentaire. Ainsi on parvient avec un travail minimal à générer une documentation de programme
convenable.

La sortie de javadoc est un fichier HTML qui peut être visualisé avec un browser Web. Cet outil permet de créer et
maintenir un unique fichier source et à générer automatiquement une documentation utile. Grâce à javadoc on a un
standard pour créer la documentation et il est suffisamment simple pour qu'on puisse espérer ou même exiger une
documentation avec toute bibliothèque Java.

IV-H-2 - Syntaxe

Toutes les commandes javadoc n'apparaissent que dans les commentaires /**. Les commentaires finissent avec
*/ comme d'habitude. Il y a deux principales façons d'utiliser javadoc : du HTML intégré ou des « onglets doc ».
Les onglets doc sont des commandes qui commencent avec un '@' et qui sont placées au début d'une ligne de
commentaire (toutefois, un '*' en tête est ignoré).

Il y a trois types de commentaires de documentation qui correspondent aux éléments suivant le commentaire : classe,
variable ou méthode. C'est-à-dire qu'un commentaire de classe apparaît juste avant la définition de la classe, un
commentaire de variable apparaît juste avant la définition de la variable et un commentaire de méthode apparaît juste
avant la définition de la méthode. Voici un exemple simple :

/** Un commentaire de classe */


public class docTest {
/** Un commentaire de variable */
public int i;
/** Un commentaire de méthode */
public void f() {}
}

Il faut noter que javadoc ne traite les commentaires de documentation que pour les membres public et protected. Les
commentaires pour les membres private et « amis » (voir titre VII) sont ignorés et on ne verra aucune sortie (toutefois
on peut utiliser le flag private pour inclure aussi les membres private). Ceci est sensé puisque seuls les membres
public et protected sont accessibles en dehors du fichier, ce qui est la perspective du client du programmeur.
Toutefois, tous les commentaires de classe sont inclus dans le fichier de sortie.

La sortie du code précédent est un fichier HTML qui a le même format standard que tout le reste de la documentation
Java, ainsi les utilisateurs seront à l'aise avec le format et pourront facilement naviguer dans les classes. Ça vaut la
peine de taper le code précédent, de le passer dans javadoc et d'étudier le fichier HTML résultant pour voir le résultat.

IV-H-3 - HTML intégré

Javadoc passe les commandes HTML dans les documents HTML générés. Ceci permet une utilisation complète de
HTML, la motivation principale étant de permettre le formatage du code comme suit :

- 77 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

/**
* <pre>
* System.out.println(new Date());
* </pre>
*/

On peut aussi utiliser HTML comme on pourrait le faire dans n'importe quel autre document Web pour formater du
texte courant dans les descriptions :

/**
* On peut <em>même</em> insérer une liste :
* <ol>
* <li> élément un
* <li> élément deux
* <li> élément trois
* </ol>
*/

Il faut noter que dans les commentaires de documentation, les astérisques en début de ligne sont éliminés par
javadoc, ainsi que les espaces en tête de ligne. Javadoc reformate tout pour assurer la conformité avec l'apparence
des documentations standard. Il ne faut pas utiliser des titres tels que <h1> ou <hr> dans le HTML intégré, car
javadoc insère ses propres titres et il y aurait des interférences.

Tous les types de commentaires de documentation - classes, variables et méthodes - acceptent l'intégration de HTML.

IV-H-4 - @see : faire référence aux autres classes

Les trois types de commentaires de documentation (classes, variables et méthodes) peuvent contenir des onglets
@see, qui permettent de faire référence à de la documentation dans d'autres classes. Javadoc génèrera du HTML
où les onglets @see seront des hyperliens vers d'autres documentations. Les différentes formes sont :

@see classname
@see fully-qualified-classname
@see fully-qualified-classname#method-name

Chacune d'entre elles ajoute un hyperlien de type « Voir aussi » à la documentation générée. Javadoc ne vérifie pas
si l'hyperlien indiqué est valide.

IV-H-5 - Class documentation tags

En plus du HTML intégré et des références @see, les documentations de classe peuvent inclure des onglets pour
les informations de version et pour le nom de l'auteur. Les documentations de classe peuvent aussi être utilisées
pour les interfaces (voir titre X).

IV-H-5-a - @version

Voici le format :

@version version-information

dans lequel version-information est n'importe quelle information significative que l'on souhaite inclure. Quand le flag
-version est mis sur la ligne de commande de javadoc, les informations de version seront exploitées, particulièrement
dans la documentation HTML.

- 78 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

IV-H-5-b - @author

Voici le format :

@author author-information

dans lequel author-information est, a priori, votre nom, mais il peut aussi contenir une adresse e-mail ou toute autre
information appropriée. Quand le flag -author est mis sur la ligne de commande javadoc, les informations sur l'auteur
seront exploitées, particulièrement dans la documentation HTML.

On peut avoir plusieurs onglets d'auteur pour une liste d'auteurs, mais ils doivent être placés consécutivement. Toutes
les informations d'auteurs seront regroupées dans un unique paragraphe dans le code HTML généré.

IV-H-5-c - @since

Cet onglet permet d'indiquer la version du code qui a commencé à utiliser une caractéristique particulière. On la verra
apparaître dans la documentation HTML de Java pour indiquer quelle version de JDK est utilisée.

IV-H-6 - Les onglets de documentation de variables

Les documentations de variables ne peuvent contenir que du HTML intégré et des références @see.

IV-H-7 - Les onglets de documentation de méthodes

En plus du HTML intégré et des références @see, les méthodes acceptent des onglets de documentation pour les
paramètres, les valeurs de retour et les exceptions.

IV-H-7-a - @param

Voici le format :

@param parameter-name description

dans lequel parameter-name est l'identificateur dans la liste de paramètres et description est du texte qui peut
se prolonger sur les lignes suivantes. La description est considérée comme terminée quand un nouvel onglet de
documentation est trouvé. On peut en avoir autant qu'on veut, a priori un pour chaque paramètre.

IV-H-7-b - @return

Voici le format :

@return description

dans lequel description indique la signification de la valeur de retour. Le texte peut se prolonger sur les lignes
suivantes.

IV-H-7-c - @throws

Les exceptions seront introduites dans le titre XII, mais, brièvement, ce sont des objets qui peuvent être émis (thrown)
par une méthode si cette méthode échoue. Bien qu'une seule exception puisse surgir lors de l'appel d'une méthode,

- 79 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

une méthode donnée est susceptible de produire n'importe quel nombre d'exceptions de types différents, chacune
d'entre elles nécessitant une description. Ainsi, le format de l'onglet d'exception est :

@throws fully-qualified-class-name description

dans lequel fully-qualified-class-name indique sans ambiguïté un nom de classe d'exception qui est définie quelque
part, et description (qui peut se prolonger sur les lignes suivantes) précise pourquoi ce type particulier d'exception
peut survenir lors de l'appel de la méthode.

IV-H-7-d - @deprecated

Ceci est utilisé pour marquer des fonctionnalités qui ont été remplacées par d'autres qui sont meilleures. L'onglet
deprecated suggère de ne plus utiliser cette fonctionnalité particulière étant donné qu'elle sera probablement
supprimée ultérieurement. Une méthode marquée @deprecated fait produire un warning par le compilateur si elle
est utilisée.

IV-H-8 - Exemple de documentation

Voici à nouveau le premier programme Java, cette fois après avoir ajouté les commentaires de documentation :

//: c02:HelloDate.java
import java.util.*;
/** Le premier exemple de programme de Thinking in Java.
* Affiche une chaîne de caractères et la date du jour.
* @author Bruce Eckel
* @author http://www.BruceEckel.com
* @version 2.0
*/
public class HelloDate {
/** Unique point d'entrée de la classe et de l'application
* @param args tableau de paramètres sous forme de chaînes de caractères
* @return Pas de valeur de retour
* @exception exceptions Pas d'exceptions émises
*/
public static void main(String[] args) {
System.out.println("Hello, it's: ");
System.out.println(new Date());
}
} ///:~

La première ligne du fichier utilise une technique personnelle qui consiste à mettre un ':' comme marqueur spécifique
pour la ligne de commentaire contenant le nom du fichier source. Cette ligne contient le chemin du fichier (dans ce
cas, c02 indique le Chapitre 2) suivi du nom de fichier (18) . La dernière ligne finit aussi avec un commentaire et
celui-ci indique la fin du listing du code source, ce qui permet de l'extraire automatiquement du texte de ce livre et
de le contrôler avec un compilateur.

IV-I - Style de programmation

Le standard non officiel de Java consiste à mettre en majuscule la première lettre des noms de classes. Si le nom
de classe est composé de plusieurs mots, ils sont accolés (c'est-à-dire qu'on ne sépare pas les noms avec un trait
bas) et la première lettre de chaque mot est mise en majuscule ainsi :

class AllTheColorsOfTheRainbow { // &#8230;

Pour pratiquement tout le reste : méthodes, champs (variables membres) et les noms des références d'objets, le style
retenu est comme pour les classes sauf que la première lettre de l'identificateur est une minuscule. Par exemple :

class AllTheColorsOfTheRainbow {

- 80 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

int anIntegerRepresentingColors;
void changeTheHueOfTheColor(int newHue) {
// &#8230;
}
// &#8230;
}

Bien entendu il faut se rappeler que l'utilisateur doit aussi taper tous ces longs noms, donc soyez clément.

Le code Java qu'on voit dans les bibliothèques de Sun respecte aussi le placement des accolades ouvrantes et
fermantes qui est utilisé dans ce livre.

Dans ce chapitre on en a vu suffisamment sur la programmation Java pour comprendre comment écrire un programme
simple et on a eu une vue d'ensemble du langage et de certaines des idées de base. Toutefois, les exemples vus
jusqu'à présent ont tous été du type « faire ceci, puis faire cela, puis faire autre chose ». Qu'en advient-il si on veut
faire un programme pour réaliser des choix, comme dans « si le résultat de ceci est rouge, faire cela, sinon faire
autre chose » ? Les outils disponibles en Java pour cette activité de programmation fondamentale seront vus dans
le prochain chapitre.

IV-J - Exercices

1 En suivant l'exemple HelloDate.java de ce chapitre, créez un programme « hello, world » qui affiche
simplement cette phrase. Vous n'avez besoin que d'une seule méthode dans la classe (la méthode
« main » qui est exécutée quand le programme démarre). Pensez à la rendre static et à indiquer la liste
de paramètres, même si la liste de paramètres n'est pas utilisée. Compilez ce programme avec javac. Si
vous utilisez un environnement de développement autre que JDK, apprenez à compiler et exécuter les
programmes dans cet environnement.
2 Trouvez le morceau de code concernant ATypeName et faites-en un programme qui compile et s'exécute.
3 Transformez le morceau de code DataOnly en un programme qui compile et qui s'exécute.
4 Modifiez l'exercice 3 de telle sorte que les valeurs des données dans DataOnly soient affectées et affichées
dans main( ).
5 Écrivez un programme qui inclut et appelle la méthode storage( ) définie comme morceau de code dans ce
chapitre.
6 Transformez le morceau de code StaticFun en un programme qui fonctionne.
7 Écrivez un programme qui imprime trois paramètres saisis sur la ligne de commande. Pour faire ceci, il faut
indexer le tableau de String représentant la ligne de commande.
8 Transformez l'exemple AllTheColorsOfTheRainbow en un programme qui compile et s'exécute.
9 Trouvez le code de la seconde version de HelloDate.java qui est le petit exemple de commentaire de
documentation. Exécutez javadoc sur le fichier et visualisez le résultat avec votre browser Web.
10 Transformez docTest en un fichier qui compile et exécutez javadoc dessus. Contrôlez la documentation qui
en résulte avec votre browser Web.
11 Ajoutez une liste d'éléments en HTML, à la documentation de l'exercice 10.
12 Prenez le programme de l'exercice 1 et ajoutez-lui une documentation. Sortez cette documentation dans un
fichier HTML à l'aide de javadoc et visualisez-la avec votre browser Web.

V - Contrôle du flux du programme

Tout comme une créature sensible, un programme doit agir sur son environnement et faire des choix durant sa vie.

En Java les objets et les données sont manipulés au moyen d'opérateurs, et les choix sont faits au moyen des
instructions de contrôle d'exécution. Java a hérité de C++, c'est pourquoi beaucoup d'instructions seront familières
aux programmeurs C et C++. Java a également amené quelques améliorations et aussi quelques simplifications.

Si vous avez l'impression de patauger quelque peu dans ce chapitre, voyez le CD-ROM multimédia fourni avec le
livre : Thinking in C : Foundations for Java and C++. Il contient des cours audio, des diapositives, des exercices,

- 81 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

et des solutions, le tout spécialement conçu pour vous familiariser rapidement avec la syntaxe C nécessaire pour
apprendre Java.

V-A - Utilisation des opérateurs Java

Un opérateur agit sur un ou plusieurs arguments pour produire une nouvelle valeur. Les arguments se présentent
sous une forme différente de celle d'un appel de méthode standard, mais le résultat est le même. Votre expérience
de programmation antérieure a dû vous familiariser avec les concepts généraux des opérateurs. L'addition (+), la
soustraction et le moins unaire (-), la multiplication (*), la division (/), et l'affectation (=) fonctionnent de la même
manière dans tous les langages de programmation.

Tous les opérateurs produisent une valeur à partir de leurs opérandes. En outre, un opérateur peut changer la valeur
de l'un de ses opérandes. C'est ce qu'on appelle un effet de bord. L'utilisation la plus fréquente des opérateurs
modifiant leurs opérandes est justement de générer un effet de bord, mais dans ce cas il faut garder à l'esprit que la
valeur produite est disponible tout comme si on avait utilisé l'opérateur sans chercher à utiliser son effet de bord.

Presque tous les opérateurs travaillent uniquement avec les types primitifs. Les exceptions sont « = », « == » et « !
= », qui fonctionnent avec tous les objets (ce qui est parfois déroutant lorsqu'on traite des objets). De plus, la classe
String admet les opérateurs « + » et « += ».

V-A-1 - Priorité

La priorité des opérateurs régit la manière d'évaluer une expression comportant plusieurs opérateurs. Java a des
règles spécifiques qui déterminent l'ordre d'évaluation. La règle la plus simple est que la multiplication et la division
passent avant l'addition et la soustraction. Souvent les programmeurs oublient les autres règles de priorité, aussi
vaut-il mieux utiliser les parenthèses afin que l'ordre d'évaluation soit explicite. Par exemple :

A = X + Y - 2/2 + Z;

a une signification différente de la même instruction dans laquelle certains termes sont groupés entre parenthèses :

A = X + (Y - 2)/(2 + Z);

V-A-2 - L'affectation

L'affectation est réalisée au moyen de l'opérateur « = ». Elle signifie « prendre la valeur se trouvant du côté droit
(souvent appelée rvalue) et la copier du côté gauche (souvent appelée lvalue) ». Une rvalue représente toute
constante, variable ou expression capable de produire une valeur, mais une lvalue doit être une variable distincte et
nommée (autrement dit, il existe un emplacement physique pour ranger le résultat). Par exemple, on peut affecter
une valeur constante à une variable (A = 4;), mais on ne peut pas affecter quoi que ce soit à une valeur constante
- elle ne peut pas être une lvalue (on ne peut pas écrire 4 =A;).

L'affectation des types primitifs est très simple. Puisque les données de type primitif contiennent une valeur réelle
et non une référence à un objet, en affectant une valeur à une variable de type primitif on copie le contenu d'un
endroit à un autre. Par exemple, si on écrit A = B pour des types primitifs, alors le contenu de B est copié dans A. Si
alors on modifie A, bien entendu B n'est pas affecté par cette modification. C'est ce qu'on rencontre généralement
en programmation.

Toutefois, les choses se passent différemment lorsqu'on affecte des objets. Quand on manipule un objet, on manipule
en fait sa référence, ce qui fait que lorsqu'on effectue une affectation « depuis un objet vers un autre », en réalité on
copie une référence d'un endroit à un autre. En d'autres termes, si on écrit C = D pour des objets, après l'exécution C
et D pointeront tous deux vers l'objet qui, à l'origine, était pointé uniquement par D. L'exemple suivant démontre cela.

Voici l'exemple :

- 82 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

//: c03:Assignment.java
// l'affectation avec des objets n'est pas triviale.

class Number {
int i;
}

public class Assignment {


public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
n1.i = 9;
n2.i = 47;
System.out.println("1: n1.i: " + n1.i +
", n2.i: " + n2.i);
n1 = n2;
System.out.println("2: n1.i: " + n1.i +
", n2.i: " + n2.i);
n1.i = 27;
System.out.println("3: n1.i: " + n1.i +
", n2.i: " + n2.i);
}
} ///:~

La classe Number est simple, main( ) en crée deux instances (n1 étend n2). La valeur i de chaque Number est
initialisée différemment, puis n2 est affecté à n1. Dans beaucoup de langages de programmation, on s'attendrait à
ce que n1 et n2 restent toujours indépendants, mais voici le résultat de ce programme, dû au fait qu'on a affecté
une référence :

1: n1.i: 9, n2.i: 47
2: n1.i: 47, n2.i: 47
3: n1.i: 27, n2.i: 27

Si on modifie l'objet n1, l'objet n2 est lui aussi modifié ! Ceci parce que n1 et n2 contiennent une même référence
pointant vers le même objet. (la référence originale qui se trouvait dans n1 et qui pointait sur un objet contenant la
valeur 9 a été écrasée lors de l'affectation et a été perdue ; l'objet sur lequel elle pointait sera nettoyé par le ramasse-
miettes).

Ce phénomène est souvent appelé aliasing (fausse désignation) et c'est la manière fondamentale de gérer les objets
en Java. Bien. Et si on ne veut pas de l'aliasing ? Alors il ne faut pas utiliser l'affectation directe n1 = n2, il faut écrire :

n1.i = n2.i;

Les deux objets restent indépendants plutôt que d'en perdre un et de faire pointer n1et n2 vers le même objet ; mais
on s'aperçoit très vite que manipuler les champs des objets ne donne pas un code lisible et va à l'encontre des bons
principes de la conception orientée objet. C'est un sujet non trivial, je le laisserai de côté et je le traiterai dans l'Annexe
A, consacrée à l'aliasing. En attendant, gardons à l'esprit que l'affectation des objets peut entraîner des surprises.

V-A-2-a - L'aliasing pendant l'appel des méthodes

L'aliasing peut également se produire en passant un objet à une méthode :

//: c03:PassObject.java
// Le passage d'objets à une méthode peut avoir
// un effet différent de celui qu'on espère

class Letter {
char c;
}

public class PassObject {


static void f(Letter y) {

- 83 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

y.c = 'z';
}
public static void main(String[] args) {
Letter x = new Letter();
x.c = 'a';
System.out.println("1: x.c: " + x.c);
f(x);
System.out.println("2: x.c: " + x.c);
}
} ///:~

Dans beaucoup de langages de programmation, la méthode f( ) est censée faire une copie de son argument Letter
y dans la zone de visibilité de la méthode. Mais, encore une fois, c'est une référence qui est passée et donc la ligne :

y.c = 'z';

modifie en réalité l'objet se trouvant au-dehors de f( ). Voici la sortie :

1: x.c: a
2: x.c: z

L'aliasing et ses conséquences sont un sujet complexe, toutes les réponses à ces questions seront données dans
l'Annexe A, mais il vous faut dès maintenant prendre conscience de son existence afin d'en éviter les pièges.

V-A-3 - Les opérateurs mathématiques

Les opérateurs mathématiques de base sont les mêmes que ceux qu'on trouve dans beaucoup de langages de
programmation : l'addition (+), la soustraction (-), la division (/), la multiplication (*) et le modulo (%, le reste de la
division entière). La division entière tronque le résultat sans l'arrondir.

Java utilise également une notation abrégée pour effectuer en un seul temps une opération et une affectation. Ceci
est compatible avec tous les opérateurs du langage (lorsque cela a un sens), on le note au moyen d'un opérateur
suivi d'un signe égal. Par exemple, pour ajouter 4 à la variable x et affecter le résultat à x, on écrit : x += 4.

Cet exemple montre l'utilisation des opérateurs mathématiques :

//: c03:MathOps.java
// Démonstration des opérateurs mathématiques.
import java.util.*;

public class MathOps {


// raccourci pour éviter des frappes de caractères :
static void prt(String s) {
System.out.println(s);
}
// raccourci pour imprimer une chaîne et un entier :
static void pInt(String s, int i) {
prt(s + " = " + i);
}
// raccourci pour imprimer une chaîne et un nombre en virgule flottante :
static void pFlt(String s, float f) {
prt(s + " = " + f);
}
public static void main(String[] args) {
// Crée un générateur de nombres aléatoires,
// initialisé par défaut avec l'heure actuelle :
Random rand = new Random();
int i, j, k;
// '%' limite la valeur maximale à 99 :
j = rand.nextInt() % 100;
k = rand.nextInt() % 100;
pInt("j",j); pInt("k",k);
i = j + k; pInt("j + k", i);

- 84 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

i = j - k; pInt("j - k", i);


i = k / j; pInt("k / j", i);
i = k * j; pInt("k * j", i);
i = k % j; pInt("k % j", i);
j %= k; pInt("j %= k", j);
// tests sur les nombres en virgule flottante :
float u,v,w; // s'applique aussi aux nombres en double précision
v = rand.nextFloat();
w = rand.nextFloat();
pFlt("v", v); pFlt("w", w);
u = v + w; pFlt("v + w", u);
u = v - w; pFlt("v - w", u);
u = v * w; pFlt("v * w", u);
u = v / w; pFlt("v / w", u);
// ce qui suit fonctionne également avec les types
// char, byte, short, int, long et double :
u += v; pFlt("u += v", u);
u -= v; pFlt("u -= v", u);
u *= v; pFlt("u *= v", u);
u /= v; pFlt("u /= v", u);
}
} ///:~

Tout d'abord on remarque quelques méthodes servant de raccourcis pour imprimer : la méthode prt( ) imprime une
String, pInt( ) imprime une String suivie d'un int et pFlt( ) imprime une String suivie d'un float. Bien entendu toutes
se terminent par un appel à System.out.println( ).

Pour générer des nombres, le programme crée un objet de type Random. Aucun argument n'étant passé à la création,
Java utilise l'heure courante comme semence d'initialisation pour le générateur de nombres aléatoires. Pour générer
des nombres de différents types, le programme appelle tout simplement différentes méthodes de l'objet Random :
nextInt( ), nextLong( ), nextFloat( ) ou nextDouble( ).

L'opérateur modulo, appliqué au résultat du générateur de nombres aléatoires, limite le résultat à un maximum
correspondant à la valeur de l'opérande moins un (dans ce cas, 99).

V-A-3-a - Les opérateurs unaires (à un opérande) moins et plus

Le moins unaire (-) et le plus unaire (+) sont identiques au moins binaire et au plus binaire. Le compilateur les
reconnaît par le contexte de l'expression. Par exemple, l'instruction :

x = -a;

a une signification évidente. Le compilateur est capable d'interpréter correctement :

x = a * -b;

mais le lecteur pourrait être déconcerté, aussi est-il plus clair d'écrire :

x = a * (-b);

Le moins unaire a pour résultat la négation de la valeur. Le plus unaire existe pour des raisons de symétrie, toutefois
il n'a aucun effet.

V-A-4 - Incrémentation et décrémentation automatique

Java, tout comme C, possède beaucoup de raccourcis. Les raccourcis autorisent un code plus concis, ce qui le rend
plus facile ou difficile à lire suivant les cas.

- 85 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Les deux raccourcis les plus agréables sont les opérateurs d'incrémentation et de décrémentation (souvent cités en
tant qu'opérateur d'autoincrémentation et d'autodécrémentation). L'opérateur de décrémentation est « -- » et signifie
« diminuer d'une unité ». L'opérateur d'incrémentation est « ++ » et signifie « augmenter d'une unité ». Si a est un
int, par exemple, l'expression ++a est équivalente à (a = a + 1). Le résultat des opérateurs d'incrémentation et de
décrémentation est la variable elle-même.

Il existe deux versions de chaque type d'opérateur, souvent nommées version préfixée et version postfixée. Pour
les deux opérateurs, incrémentation et décrémentation, préfixée signifie que l'opérateur (« ++ » ou « -- ») se trouve
juste avant la variable ou l'expression, postfixée que l'opérateur se trouve après la variable ou l'expression. Pour la
préincrémentation et la prédécrémentation, (c'est-à-dire, ++a ou --a), l'opération est réalisée en premier, puis la valeur
est produite. Pour la postincrémentation et la postdécrémentation (c'est-à-dire a++ ou a--), la valeur est produite, puis
l'opération est réalisée. En voici un exemple :

//: c03:AutoInc.java
// Démonstration des opérateurs ++ et --.

public class AutoInc {


public static void main(String[] args) {
int i = 1;
prt("i : " + i);
prt("++i : " + ++i); // Préincrémentation
prt("i++ : " + i++); // Postincrémentation
prt("i : " + i);
prt("--i : " + --i); // Prédécrémentation
prt("i-- : " + i--); // Postdécrémentation
prt("i : " + i);
}
static void prt(String s) {
System.out.println(s);
}
} ///:~

Voici le résultat de ce programme :

i : 1
++i : 2
i++ : 2
i : 3
--i : 2
i-- : 2
i : 1

On constate qu'avec la forme préfixée on obtient la valeur de la variable après que l'opération ait été exécutée, et
qu'avec la forme postfixée on obtient la valeur de la variable avant que l'opération ne soit réalisée. Ce sont les seuls
opérateurs ayant des effets de bord, mis à part ceux qui impliquent l'affectation : en d'autres termes, ils modifient
l'opérande au lieu de simplement utiliser sa valeur.

L'opérateur d'incrémentation explique le nom C++, qui voudrait signifier « un pas de plus au-delà de C ». Dans
un ancien discours sur Java, Bill Joy (l'un des créateurs), disait que « Java = C++-- » (C plus plus moins moins),
suggérant que Java serait C++ auquel on aurait ôté les parties difficiles et non nécessaires, et qu'il serait donc un
langage bien plus simple. Au fil de votre lecture, vous découvrirez ici que beaucoup de choses sont plus simples,
bien que Java ne soit pas tellement plus simple que C++.

V-A-5 - Les opérateurs relationnels

Les opérateurs relationnels créent un résultat de type boolean. Ils évaluent les rapports entre les valeurs des
opérandes. Une expression relationnelle renvoie true si le rapport est vrai, false dans le cas opposé. Les opérateurs
relationnels sont : plus petit que (<), plus grand que (>), plus petit que ou égal à (<=), plus grand que ou égal
à (>=), équivalent (==) et non équivalent (!=). Le type boolean n'accepte comme opérateur relationnel que les
opérateurs d'équivalence (==) et de non-équivalence (!=), lesquels peuvent être utilisés avec tous les types de
données disponibles dans le langage.

- 86 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

V-A-5-a - Tester l'équivalence des objets

Les opérateurs relationnels == et != fonctionnent avec tous les objets, mais leur utilisation déroute souvent le
programmeur Java novice. Voici un exemple :

//: c03:Equivalence.java

public class Equivalence {


public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1 == n2);
System.out.println(n1 != n2);
}
} ///:~

L'expression System.out.println(n1 == n2) imprimera le résultat de la comparaison de type boolean. Il semble a


priori évident que la sortie sera true puis false, puisque les deux objets de type Integer sont identiques. Mais, bien
que le contenu des objets soit le même, les références sont différentes, et il se trouve que les opérateurs == and !=
comparent des références d'objet. En réalité la sortie sera false puis true. Naturellement, cela en surprendra plus
d'un.

Que faire si on veut comparer le contenu réel d'un objet ? Il faut utiliser la méthode spéciale equals( ) qui existe pour
tous les objets (mais non pour les types primitifs, qui s'accommodent mieux de == et !=). Voici comment l'utiliser :

//: c03:EqualsMethod.java

public class EqualsMethod {


public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1.equals(n2));
}
} ///:~

//: c03:EqualsMethod2.java

class Value {
int i;
}

public class EqualsMethod2 {


public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
} ///:~

nous voici revenus à la case départ : le résultat est false. Ceci parce que, par défaut, equals( ) compare des
références. Aussi, faute de redéfinir equals( ) dans la nouvelle classe, nous n'obtiendrons pas le résultat désiré.
Mais la redéfinition des méthodes ne sera exposée que dans le titre IX, aussi d'ici là il nous faudra garder à l'esprit
que l'utilisation de equals( ) peut poser des problèmes.

Beaucoup de classes des bibliothèques Java implémentent la méthode equals( ) afin de comparer le contenu des
objets plutôt que leurs références.

- 87 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

V-A-6 - Les opérateurs logiques

Les opérateurs logiques AND (&&), OR (||) et NOT (!) produisent une valeur boolean qui prend la valeur true ou
false en fonction des arguments. Cet exemple utilise les opérateurs relationnels et logiques :

//: c03:Bool.java
// Opérateurs relationnels et logiques.
import java.util.*;

public class Bool {


public static void main(String[] args) {
Random rand = new Random();
int i = rand.nextInt() % 100;
int j = rand.nextInt() % 100;
prt("i = " + i);
prt("j = " + j);
prt("i > j is " + (i > j));
prt("i < j is " + (i < j));
prt("i >= j is " + (i >= j));
prt("i <= j is " + (i <= j));
prt("i == j is " + (i == j));
prt("i != j is " + (i != j));

// Traiter un int comme un boolean


// n'est pas légal en Java
//! prt("i && j is " + (i && j));
//! prt("i || j is " + (i || j));
//! prt("!i is " + !i);

prt("(i < 10) && (j < 10) is "


+ ((i < 10) && (j < 10)) );
prt("(i < 10) || (j < 10) is "
+ ((i < 10) || (j < 10)) );
}
static void prt(String s) {
System.out.println(s);
}
} ///:~

On ne peut appliquer AND, OR, et NOT qu'aux valeurs boolean. On ne peut pas utiliser une variable non booléenne
comme si elle était booléenne, comme on le fait en C et C++. Les tentatives (erronées) de le faire ont été mises
en commentaires avec le marqueur //!. Les expressions qui suivent, toutefois, produisent des valeurs boolean en
utilisant les opérateurs de comparaisons relationnels, puis appliquent des opérations logiques sur les résultats.

Exemple de listing de sortie :

i = 85
j = 4
i > j is true
i < j is false
i >= j is true
i <= j is false
i == j is false
i != j is true
(i < 10) && (j < 10) is false
(i < 10) || (j < 10) is true

Notez qu'une valeur boolean est automatiquement convertie en texte approprié lorsqu'elle est utilisée dans un
contexte où on attend une String.

Dans le programme précédent, on peut remplacer la définition int par n'importe quelle autre donnée de type primitif
excepté boolean. Toutefois il faut rester attentif au fait que la comparaison de nombres en virgule flottante est très
stricte. Un nombre qui diffère très légèrement d'un autre est toujours « différent ». Un nombre représenté par le plus
petit bit significatif au-dessus de zéro est différent de zéro.

- 88 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

V-A-6-a - « Court-circuit »

En travaillant avec les opérateurs logiques, on rencontre un comportement appelé « court-circuit ». Cela signifie que
l'évaluation de l'expression sera poursuivie jusqu'à ce que la vérité ou la fausseté de l'expression soit déterminée
sans ambiguïté. En conséquence, certaines parties d'une expression logique peuvent ne pas être évaluées. Voici un
exemple montrant une évaluation « court-circuitée » :

//: c03:ShortCircuit.java
// Démonstration du fonctionnement du "court-circuit"
// avec les opérateurs logiques.

public class ShortCircuit {


static boolean test1(int val) {
System.out.println("test1(" + val + ")");
System.out.println("result: " + (val < 1));
return val < 1;
}
static boolean test2(int val) {
System.out.println("test2(" + val + ")");
System.out.println("result: " + (val < 2));
return val < 2;
}
static boolean test3(int val) {
System.out.println("test3(" + val + ")");
System.out.println("result: " + (val < 3));
return val < 3;
}
public static void main(String[] args) {
if(test1(0) && test2(2) && test3(2))
System.out.println("expression is true");
else
System.out.println("expression is false");
}
} ///:~

Chaque fonction test effectue une comparaison sur l'argument et renvoie true ou false. De plus elle imprime cette
valeur pour montrer qu'elle est appelée. Les tests sont utilisés dans l'expression :

if(test1(0) && test2(2) && test3(2))

On pourrait naturellement penser que les trois tests sont exécutés, mais la sortie montre le contraire :

test1(0)
result: true
test2(2)
result: false
expression is false

Le premier test produit un résultat true, et l'évaluation de l'expression se poursuit. Toutefois, le second test produit un
résultat false. Puisque cela signifie que l'expression complète sera false, pourquoi poursuivre l'évaluation du reste
de l'expression ? Cela pourrait avoir un coût. C'est de fait la justification du « court-circuit » : gagner potentiellement
en performance s'il n'est pas nécessaire d'évaluer complètement l'expression logique.

V-A-7 - Les opérateurs bit à bit

Les opérateurs bit à bit permettent de manipuler les bits individuels d'une donnée de type primitif. Les opérateurs
bit à bit effectuent des opérations d'algèbre booléenne sur les bits en correspondance dans les deux arguments afin
de produire un résultat.

L'origine des opérateurs bit à bit est à rechercher dans l'orientation bas niveau du langage C ; il fallait alors
manipuler directement le hardware ainsi que les bits des registres hardware. Java a été conçu à l'origine pour être

- 89 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

embarqué dans les décodeurs TV, ce qui explique cette orientation bas niveau. Vous n'utiliserez vraisemblablement
pas beaucoup ces opérateurs.

L'opérateur AND (&) bit à bit retourne la valeur 1 si les deux bits correspondants des opérandes d'entrée sont à 1 ;
sinon il retourne la valeur zéro. L'opérateur OR (|) bit à bit retourne la valeur 1 si l'un des deux bits correspondants des
opérandes d'entrée est à 1 et retourne la valeur zéro dans le cas où les deux bits sont à zéro. L'opérateur EXCLUSIVE
OR, ou XOR (^), retourne la valeur 1 si l'un des deux bits correspondants des opérandes est à 1, mais pas les deux.
L'opérateur NOT bit à bit (~ , appelé également opérateur de complément à 1) est un opérateur unaire, il a un seul
argument (tous les autres opérateurs bit à bit sont des opérateurs binaires), il renvoie l'opposé de l'argument - 1 si
le bit de l'argument est à zéro, zéro si le bit est à 1.

Les opérateurs bit à bit et les opérateurs logiques étant représentés par les mêmes caractères, je vous propose un
procédé mnémotechnique pour vous souvenir de leur signification : les bits étant « petits », les opérateurs bit à bit
comportent un seul caractère.

Les opérateurs bit à bit peuvent être combinés avec le signe = pour réaliser en une seule fois opération et affectation :
&=, |= et ^= sont tous légitimes. (~ étant un opérateur unaire, il ne peut être combiné avec le signe =).

Le type boolean est traité comme une valeur binaire et il est quelque peu différent. Il est possible de réaliser des
opérations AND, OR et XOR « bit à bit », mais il est interdit d'effectuer un NOT « bit à bit » (vraisemblablement pour
ne pas faire de confusion avec le NOT logique). Pour le type boolean les opérateurs bit à bit ont le même effet que
les opérateurs logiques, sauf qu'il n'y a pas de « court-circuit ». De plus, parmi les opérations bit à bit effectuées sur
des types boolean il existe un opérateur XOR logique qui ne fait pas partie de la liste des opérateurs « logiques ».
Enfin, le type boolean ne doit pas être utilisé dans les expressions de décalage décrites ci-après.

V-A-8 - Les opérateurs de décalage

Les opérateurs de décalage manipulent eux aussi des bits. On ne peut les utiliser qu'avec les types primitifs entiers.
L'opérateur de décalage à gauche (<<) a pour résultat la valeur de l'opérande situé à gauche de l'opérateur, décalée
vers la gauche du nombre de bits spécifié à droite de l'opérateur (en insérant des zéros dans les bits de poids faible).
L'opérateur signé de décalage à droite (>>) a pour résultat la valeur de l'opérande situé à gauche de l'opérateur,
décalée vers la droite du nombre de bits spécifié à droite de l'opérateur. L'opérateur signé de décalage à droite >>
étend le signe : si la valeur est positive, des zéros sont insérés dans les bits de poids fort ; si la valeur est négative,
des 1 sont insérés dans les bits de poids fort. Java comprend également un opérateur de décalage à droite non signé
>>>, qui étend les zéros : quel que soit le signe, des zéros sont insérés dans les bits de poids fort. Cet opérateur
n'existe pas en C ou C++.

Si on décale un char, byte, ou short, il sera promu en int avant le décalage, et le résultat sera un int. Seuls seront
utilisés les cinq bits de poids faible de la valeur de décalage, afin de ne pas décaler plus que le nombre de bits dans
un int. Si on opère avec un long, le résultat sera un long. Seuls les six bits de poids faible de la valeur de décalage
seront utilisés, on ne peut donc décaler un long d'un nombre de bits supérieur à celui qu'il contient.

Les décalages peuvent être combinés avec le signe égal (<<=, >>= ou >>>=). La lvalue est remplacée par la lvalue
décalée de la valeur rvalue. Il y a un problème, toutefois, avec le décalage à droite non signé combiné à une
affectation. Son utilisation avec un byte ou un short ne donne pas un résultat correct. En réalité, l'opérande est
promu en int, décalé à droite, puis tronqué comme s'il devait être affecté dans sa propre variable, et dans ce cas
on obtient -1. L'exemple suivant démontre cela :

//: c03:URShift.java
// Test du décalage à droite non signé.

public class URShift {


public static void main(String[] args) {
int i = -1;
i >>>= 10;
System.out.println(i);
long l = -1;
l >>>= 10;

- 90 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

System.out.println(l);
short s = -1;
s >>>= 10;
System.out.println(s);
byte b = -1;
b >>>= 10;
System.out.println(b);
b = -1;
System.out.println(b>>>10);
}
} ///:~

Dans la dernière ligne, la valeur résultante n'est pas réaffectée à b, mais directement imprimée et dans ce cas le
comportement est correct.

Voici un exemple montrant l'utilisation de tous les opérateurs travaillant sur des bits :

//: c03:BitManipulation.java
// Utilisation des opérateurs bit à bit.
import java.util.*;

public class BitManipulation {


public static void main(String[] args) {
Random rand = new Random();
int i = rand.nextInt();
int j = rand.nextInt();
pBinInt("-1", -1);
pBinInt("+1", +1);
int maxpos = 2147483647;
pBinInt("maxpos", maxpos);
int maxneg = -2147483648;
pBinInt("maxneg", maxneg);
pBinInt("i", i);
pBinInt("~i", ~i);
pBinInt("-i", -i);
pBinInt("j", j);
pBinInt("i & j", i & j);
pBinInt("i | j", i | j);
pBinInt("i ^ j", i ^ j);
pBinInt("i << 5", i << 5);
pBinInt("i >> 5", i >> 5);
pBinInt("(~i) >> 5", (~i) >> 5);
pBinInt("i >>> 5", i >>> 5);
pBinInt("(~i) >>> 5", (~i) >>> 5);

long l = rand.nextLong();
long m = rand.nextLong();
pBinLong("-1L", -1L);
pBinLong("+1L", +1L);
long ll = 9223372036854775807L;
pBinLong("maxpos", ll);
long lln = -9223372036854775808L;
pBinLong("maxneg", lln);
pBinLong("l", l);
pBinLong("~l", ~l);
pBinLong("-l", -l);
pBinLong("m", m);
pBinLong("l & m", l & m);
pBinLong("l | m", l | m);
pBinLong("l ^ m", l ^ m);
pBinLong("l << 5", l << 5);
pBinLong("l >> 5", l >> 5);
pBinLong("(~l) >> 5", (~l) >> 5);
pBinLong("l >>> 5", l >>> 5);
pBinLong("(~l) >>> 5", (~l) >>> 5);
}
static void pBinInt(String s, int i) {
System.out.println(
s + ", int: " + i + ", binary: ");
System.out.print(" ");

- 91 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

for(int j = 31; j >=0; j--)


if(((1 << j) & i) != 0)
System.out.print("1");
else
System.out.print("0");
System.out.println();
}
static void pBinLong(String s, long l) {
System.out.println(
s + ", long: " + l + ", binary: ");
System.out.print(" ");
for(int i = 63; i >=0; i--)
if(((1L << i) & l) != 0)
System.out.print("1");
else
System.out.print("0");
System.out.println();
}
} ///:~

Les deux dernières méthodes, pBinInt( ) et pBinLong( ) sont appelées respectivement avec un int et un long, et
l'impriment en format binaire avec une description. Nous ne parlerons pas de cette implémentation pour le moment.

Remarquez l'utilisation de System.out.print( ) au lieu de System.out.println( ). La méthode print( ) n'émet pas de


retour chariot, et permet ainsi d'imprimer une ligne en plusieurs fois.

Cet exemple montre l'effet de tous les opérateurs bit à bit pour les int et les long, mais aussi ce qui se passe avec
les valeurs minimale, maximale, +1 et -1, pour un int et pour un long. Noter que le bit de poids le plus fort représente
le signe : 0 signifie positif, 1 négatif. Voici la sortie pour la partie int :

-1, int: -1, binary:


11111111111111111111111111111111
+1, int: 1, binary:
00000000000000000000000000000001
maxpos, int: 2147483647, binary:
01111111111111111111111111111111
maxneg, int: -2147483648, binary:
10000000000000000000000000000000
i, int: 59081716, binary:
00000011100001011000001111110100
~i, int: -59081717, binary:
11111100011110100111110000001011
-i, int: -59081716, binary:
11111100011110100111110000001100
j, int: 198850956, binary:
00001011110110100011100110001100
i & j, int: 58720644, binary:
00000011100000000000000110000100
i | j, int: 199212028, binary:
00001011110111111011101111111100
i ^ j, int: 140491384, binary:
00001000010111111011101001111000
i << 5, int: 1890614912, binary:
01110000101100000111111010000000
i >> 5, int: 1846303, binary:
00000000000111000010110000011111
(~i) >> 5, int: -1846304, binary:
11111111111000111101001111100000
i >>> 5, int: 1846303, binary:
00000000000111000010110000011111
(~i) >>> 5, int: 132371424, binary:
00000111111000111101001111100000

La représentation binaire des nombres est dite en complément à deux signé.

- 92 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Cet opérateur est inhabituel parce qu'il a trois opérandes. C'est un véritable opérateur dans la mesure où il produit
une valeur, à l'inverse de l'instruction habituelle if-else que nous étudierons dans la prochaine section de ce chapitre.
L'expression est de la forme :

expression-booléenne ? valeur0 : valeur1

Si le résultat de expression booléenne est true, l'expression valeur0 est évaluée et son résultat devient le résultat
de l'opérateur. Si expression booléenne est false, c'est l'expression valeur1 qui est évaluée et son résultat devient
le résultat de l'opérateur.

Bien entendu, il est possible d'utiliser à la place une instruction if-else (qui sera décrite plus loin), mais l'opérateur
ternaire est plus concis. Bien que C (d'où est issu cet opérateur) s'enorgueillit d'être lui-même un langage concis, et
que l'opérateur ternaire ait été introduit, entre autres choses, pour des raisons d'efficacité, il faut se garder de l'utiliser
à tout bout de champ, car on aboutit très facilement à un code illisible.

Cet opérateur conditionnel peut être utilisé, soit pour ses effets de bord, soit pour la valeur produite, mais en général
on recherche la valeur puisque c'est elle qui rend cet opérateur distinct du if-else. En voici un exemple :

static int ternary(int i) {


return i < 10 ? i * 100 : i * 10;
}

Ce code est plus compact que celui qu'on aurait écrit sans l'opérateur ternaire :

static int alternative(int i) {


if (i < 10)
return i * 100;
else
return i * 10;
}

La deuxième forme est plus compréhensible, et ne nécessite pas de commentaire. Il est donc nécessaire de bien
peser tous les arguments avant d'opter pour l'opérateur ternaire.

V-A-9 - L'opérateur virgule

La virgule est utilisée en C et C++ non seulement comme séparateur dans la liste des arguments des fonctions, mais
aussi en tant qu'opérateur pour une évaluation séquentielle. L'opérateur virgule est utilisé en Java uniquement dans
les boucles for, qui seront étudiées plus loin dans ce chapitre.

V-A-10 - L'opérateur + pour les String

Un des opérateurs a une utilisation spéciale en Java : l'opérateur + peut être utilisé pour concaténer des chaînes
de caractères, comme on l'a déjà vu. Il semble que ce soit une utilisation naturelle de l'opérateur +, même si cela
ne correspond pas à son utilisation traditionnelle. Étendre cette possibilité semblait une bonne idée en C++, aussi la
surcharge d'opérateurs fut ajoutée au C++ afin de permettre au programmeur d'ajouter des significations différentes
à presque tous les opérateurs. En fait, la surcharge d'opérateurs, combinée à d'autres restrictions du C++, s'est
trouvée être très compliquée à mettre en œuvre par les programmeurs pour la conception de leurs classes. En Java,
la surcharge d'opérateurs aurait été plus simple à implémenter qu'elle ne l'a été en C++ ; mais cette fonctionnalité a
été jugée trop complexe, et les programmeurs Java, à la différence des programmeurs C++, ne peuvent implémenter
leurs propres surcharges d'opérateurs.

L'utilisation de l'opérateur + pour les String présente quelques caractéristiques intéressantes. Si une expression
commence par une String, alors tous les opérandes qui suivent doivent être des String (souvenez-vous que le
compilateur remplace une séquence de caractères entre guillemets par une String) :

- 93 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

int x = 0, y = 1, z = 2;
String sString = "x, y, z ";
System.out.println(sString + x + y + z);

Ici, le compilateur Java convertit x, y, et z dans leurs représentations String au lieu d'ajouter d'abord leurs valeurs.
Et si on écrit :

System.out.println(x + sString);

Java remplacera x par une String.

V-A-11 - Les pièges classiques dans l'utilisation des opérateurs

L'un des pièges dus aux opérateurs est de vouloir se passer des parenthèses alors qu'on n'est pas tout à fait certain
de la manière dont sera évaluée l'opération. Ceci reste vrai en Java.

Une erreur très classique en C et C++ ressemble à celle-ci :

while(x = y) {
// ....
}

Le programmeur voulait tester l'équivalence (==) et non effectuer une affectation. En C et C++ le résultat de cette
affectation est toujours true si y est différent de zéro, et on a toutes les chances de partir dans une boucle infinie. En
Java, le résultat de cette expression n'est pas un boolean ; le compilateur attendant un boolean, et ne transtypant pas
l'int, générera une erreur de compilation avant même l'exécution du programme. Par suite cette erreur n'apparaîtra
jamais en Java. Il n'y aura aucune erreur de compilation que dans le seul cas où x et y sont des boolean, pour lequel
x = y est une expression légale ; mais il s'agirait probablement d'une erreur dans l'exemple ci-dessus.

Un problème similaire en C et C++ consiste à utiliser les AND et OR bit à bit au lieu de leurs versions logiques. Les
AND et OR bit à bit utilisent un des caractères (& ou |) alors que les AND et OR logique en utilisent deux (&& et ||).
Tout comme avec = et ==, il est facile de ne frapper qu'un caractère au lieu de deux. En Java, le compilateur interdit
cela et ne vous laissera pas utiliser cavalièrement un type là où il n'a pas lieu d'être.

V-A-12 - Les opérateurs de transtypage

Le mot transtypage est utilisé dans le sens de « couler dans un moule ». Java transforme automatiquement un type
de données dans un autre lorsqu'il le faut. Par exemple, si on affecte une valeur entière à une variable en virgule
flottante, le compilateur convertira automatiquement l'int en float. Le transtypage permet d'effectuer cette conversion
explicitement, ou bien de la forcer lorsqu'elle ne serait pas effectuée implicitement.

Pour effectuer un transtypage, il suffit de mettre le type de données voulu (ainsi que tous ses modificateurs) entre
parenthèses à gauche de n'importe quelle valeur. Voici un exemple :

void casts() {
int i = 200;
long l = (long)i;
long l2 = (long)200;
}

Comme on peut le voir, il est possible de transtyper une valeur numérique aussi bien qu'une variable. Toutefois, dans
les deux exemples présentés ici, le transtypage est superflu puisque le compilateur promouvra une valeur int en long
si nécessaire. Il est tout de même possible d'effectuer un tel transtypage, soit pour le souligner, soit pour rendre le
code plus clair. Dans d'autres situations, un transtypage pourrait être utilisé afin d'obtenir un code compilable.

- 94 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

En C et C++, le transtypage est parfois la source de quelques migraines. En Java, le transtypage est sûr, avec
l'exception suivante : lorsqu'on fait ce qu'on appelle une conversion rétrécissante (c'est-à-dire lorsqu'on transtype
depuis un type de données vers un autre, le premier pouvant contenir plus d'information que le second) on court
le risque de perdre de l'information. Dans ce cas le compilateur demande un transtypage explicite, en émettant un
message à peu près formulé ainsi « ceci peut être dangereux - néanmoins, si c'est ce que vous voulez vraiment faire,
je vous en laisse la responsabilité ». Avec une conversion élargissante, le transtypage explicite n'est pas obligatoire,
car il n'y a pas de risque de perte d'information, le nouveau type pouvant contenir plus d'information que l'ancien.

Java permet de transtyper n'importe quel type primitif vers n'importe quel autre type primitif, excepté le type boolean,
pour lequel il n'existe aucun transtypage. Les types Class ne peuvent être transtypés. Pour convertir une classe en
une autre, il faut utiliser des méthodes spéciales. (String est un cas à part, et on verra plus loin dans ce livre que les
objets peuvent être transtypés à l'intérieur d'une famille de types ; un Chêne peut être transtypé en Arbre et vice
versa, mais non dans un type étranger tel que Roche).

V-A-12-a - Les littéraux

Habituellement le compilateur sait exactement quel type affecter aux valeurs littérales insérées dans un programme.
Quelquefois, cependant, le type est ambigu. Dans de tels cas, il faut guider le compilateur en ajoutant une information
supplémentaire sous la forme de caractères associés à la valeur littérale. Le code suivant montre l'utilisation de ces
caractères :

//: c03:Literals.java

class Literals {
char c = 0xffff; // plus grande valeur char en hexadécimal
byte b = 0x7f; // plus grande valeur byte en hexadécimal
short s = 0x7fff; // plus grande valeur short en hexadécimal
int i1 = 0x2f; // Hexadécimal (minuscules)
int i2 = 0X2F; // Hexadécimal (majuscules)
int i3 = 0177; // Octal (avec zéro en tête)
// Hexadécimal et Octal avec des long.
long n1 = 200L; // suffixe long
long n2 = 200l; // suffixe long
long n3 = 200;
//! long l6(200); // non autorisé
float f1 = 1;
float f2 = 1F; // suffixe float
float f3 = 1f; // suffixe float
float f4 = 1e-45f; // 10 puissance
float f5 = 1e+9f; // suffixe float
double d1 = 1d; // suffixe double
double d2 = 1D; // suffixe double
double d3 = 47e47d; // 10 puissance
} ///:~

L'hexadécimal (base 16), utilisable avec tous les types entier, est représenté par 0x ou 0X suivi de caractères 0-9 et/
ou a-f en majuscules ou en minuscules. Si on tente d'initialiser une variable avec une valeur plus grande que celle
qu'elle peut contenir (indépendamment de la forme numérique de la valeur), le compilateur émettra un message
d'erreur. Le code ci-dessus montre entre autres la valeur hexadécimale maximale possible pour les types char,
byte, et short. Si on dépasse leur valeur maximale, le compilateur crée automatiquement une valeur int et émet
un message nous demandant d'utiliser un transtypage rétrécissant afin de réaliser l'affectation : Java nous avertit
lorsqu'on franchit la ligne.

L'octal (base 8) est représenté par un nombre dont le premier digit est 0 (zéro) et les autres 0-7. Il n'existe pas de
représentation littérale des nombres binaires en C, C++ ou Java.

Un caractère suivant immédiatement une valeur littérale établit son type : L, majuscule ou minuscule, signifie long ;
F, majuscule ou minuscule, signifie float, et D, majuscule ou minuscule, double.

- 95 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Les exposants utilisent une notation qui m'a toujours passablement consterné : 1.39 e-47f. En science et en ingénierie,
« e » représente la base des logarithmes naturels, approximativement 2.718 (une valeur double plus précise existe
en Java, c'est Math.E). e est utilisé dans les expressions d'exponentiation comme 1.39 x e-47, qui signifie 1.39 x
2.718-47. Toutefois, lorsque FORTRAN vit le jour il fut décidé que e signifierait naturellement « dix puissance »,
décision bizarre puisque FORTRAN a été conçu pour résoudre des problèmes scientifiques et d'ingénierie, et on
aurait pu penser que ses concepteurs auraient fait preuve de plus de bon sens avant d'introduire une telle ambiguïté.
(19) Quoi qu'il en soit, cette habitude a continué avec C, C++ et maintenant Java. Ceux d'entre vous qui ont utilisé e
en tant que base des logarithmes naturels doivent effectuer une translation mentale en rencontrant une expression
telle que 1.39 e-47f en Java ; elle signifie 1.39 x 10-47.

Noter que le caractère de fin n'est pas obligatoire lorsque le compilateur est capable de trouver le type approprié.
Avec :

long n3 = 200;

il n'y a pas d'ambiguïté, un L suivant le 200 serait superflu. Toutefois, avec :

float f4 = 1e-47f; // 10 puissance

le compilateur traite normalement les nombres en notation scientifique en tant que double, et en l'absence du f final
générerait un message d'erreur disant qu'on doit effectuer un transtypage explicite afin de convertir un double en
float.

V-A-12-b - La promotion

Lorsqu'on effectue une opération mathématique ou bit à bit sur des types de données primitifs plus petits qu'un int
(c'est-à-dire char, byte, ou short), on découvre que ces valeurs sont promues en int avant que les opérations ne
soient effectuées, et que le résultat est du type int. Par suite, si on affecte ce résultat à une variable d'un type plus
petit, il faut effectuer un transtypage explicite qui peut d'ailleurs entraîner une perte d'information. En général, dans
une expression, la donnée du type le plus grand est celle qui détermine le type du résultat de cette expression ; en
multipliant un float et un double, le résultat sera un double ; en ajoutant un int et un long, le résultat sera un long.

V-A-13 - Java n'a pas de « sizeof »

En C and C++, l'opérateur sizeof( ) satisfait un besoin spécifique : il renseigne sur le nombre d'octets alloués pour
les données individuelles. En C et C++, la principale raison d'être de l'opérateur sizeof( ) est la portabilité. Plusieurs
types de données peuvent avoir des tailles différentes sur des machines différentes, et le programmeur doit connaître
la taille allouée pour ces types lorsqu'il effectue des opérations sensibles à la taille des données. Par exemple, un
ordinateur peut traiter les entiers sur 32 bits, alors qu'un autre les traitera sur 16 bits : les programmes peuvent ranger
de plus grandes valeurs sur la première machine. Comme on peut l'imaginer, la portabilité est un énorme casse-tête
pour les programmeurs C et C++.

Java n'a pas besoin d'un opérateur sizeof( ), car tous les types de données ont la même taille sur toutes les machines.
Il n'est absolument pas besoin de parler de portabilité à ce niveau - celle-ci est déjà intégrée au langage.

V-A-14 - Retour sur la priorité des opérateurs

Lors d'un séminaire, entendant mes jérémiades au sujet de la difficulté de se souvenir de la priorité des opérateurs,
un étudiant suggéra un procédé mnémotechnique qui est également un commentaire : « Ulcer Addicts Really Like
C A lot ». (« Les Accros de l'Ulcère Adorent Réellement C »)

- 96 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Mnémonique Type d'opérateur Opérateurs


Ulcer Unaire + - ++--
Addicts Arithmétique (et * / % + - << >>
décalage)
Really Relationnel > < >= <= == !=
Like Logique (et bit à bit) && || & | ^
C Conditionnel (ternaire) A>B?X:Y
A Lot Affectation = (et affectation
composée comme*=)

Bien entendu, ce n'est pas un moyen mnémotechnique parfait puisque les opérateurs de décalage et les opérateurs
bit à bit sont quelque peu éparpillés dans le tableau, mais il fonctionne pour les autres opérateurs.

V-A-15 - Résumé sur les opérateurs

L'exemple suivant montre les types de données primitifs qu'on peut associer avec certains opérateurs. Il s'agit du
même exemple de base répété plusieurs fois, en utilisant des types de données primitifs différents. Le fichier ne doit
pas générer d'erreur de compilation dans la mesure où les lignes pouvant générer de telles erreurs ont été mises
en commentaires avec //! :

Noter que le type boolean est totalement limité. On peut lui assigner les valeurs true et false, on peut tester sa vérité
ou sa fausseté, mais on ne peut ni additionner des booléens ni effectuer un autre type d'opération avec eux.

On peut observer l'effet de la promotion des types char, byte, et short avec l'application d'un opérateur arithmétique
sur l'un d'entre eux. Le résultat est un int, qui doit être explicitement transtypé vers le type original (c'est-à-dire une
conversion rétrécissante qui peut entraîner une perte d'information) afin de l'affecter à une variable de ce type. Avec
les valeurs int, toutefois, il n'est pas besoin de transtyper, puisque tout ce qu'on obtient est toujours un int. N'allez
cependant pas croire qu'on peut faire n'importe quoi en toute impunité. Le résultat de la multiplication de deux ints
un peu trop grands peut entraîner un débordement. L'exemple suivant en fait la démonstration :

//: c03:Overflow.java
// Surprise ! Java ne contrôle pas vos débordements.

public class Overflow {


public static void main(String[] args) {
int big = 0x7fffffff; // plus grande valeur int
prt("big = " + big);
int bigger = big * 4;
prt("bigger = " + bigger);
}
static void prt(String s) {
System.out.println(s);
}
} ///:~

Voici le résultat :

big = 2147483647
bigger = -4

La compilation se déroule sans erreur ni avertissement ; il n'y a pas d'exception lors de l'exécution : Java est puissant,
mais tout de même pas à ce point-là.

Les affectations composées ne nécessitent pas de transtypage pour les types char, byte, ou short, bien qu'elles
entraînent des promotions qui ont le même résultat que les opérations arithmétiques directes. Cette absence de
transtypage simplifie certainement le code.

- 97 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

On remarque qu'à l'exception du type boolean, tous les types primitifs peuvent être transtypés entre eux. Il faut
rester attentif à l'effet des conversions rétrécissantes en transtypant vers un type plus petit, sous peine de perdre
de l'information sans en être averti.

V-B - Le contrôle d'exécution

Java utilisant toutes les instructions de contrôle de C, bien des choses seront familières au programmeur C ou C+
+. La plupart des langages de programmation procéduraux possèdent le même type d'instructions de contrôle, et on
retrouve beaucoup de choses d'un langage à un autre. En Java, les mots-clefs sont if-else, while, do-while, for, et
une instruction de sélection appelée switch. Toutefois Java ne possède pas le goto très pernicieux (lequel reste le
moyen le plus expéditif pour traiter certains types de problèmes). Il est possible d'effectuer un saut ressemblant au
goto, mais bien plus contraignant qu'un goto classique.

V-B-1 - true et false

Toutes les instructions conditionnelles utilisent la vérité ou la fausseté d'une expression conditionnelle pour déterminer
le chemin d'exécution. Exemple d'une expression conditionnelle : A == B. Elle utilise l'opérateur conditionnel ==
pour déterminer si la valeur A est équivalente à la valeur B. L'expression renvoie la valeur true ou false. Tous les
opérateurs relationnels vus plus haut dans ce chapitre peuvent être utilisés pour créer une instruction conditionnelle.
Il faut garder à l'esprit que Java ne permet pas d'utiliser un nombre à la place d'un boolean, même si c'est autorisé
en C et C++ (pour lesquels la vérité est « différent de zéro » et la fausseté « zéro »). Pour utiliser un non-boolean
dans un test boolean, tel que if(a), il faut d'abord le convertir en une valeur boolean en utilisant une expression
booléenne, par exemple if(a != 0).

V-B-2 - if-else

L'instruction if-else est sans doute le moyen le plus simple de contrôler le déroulement du programme. La clause
else est optionnelle, et par suite l'instruction if possède deux formes :

if(expression booléenne)
instruction

ou bien :

if(expression booléenne)
instruction
else
instruction

L'expression conditionnelle expression booléenne doit fournir un résultat de type boolean. instruction désigne
soit une instruction simple terminée par un point-virgule, soit une instruction composée, c'est-à-dire un groupe
d'instructions simples placées entre deux accolades. Par la suite, chaque utilisation du mot « instruction » sous-
entendra que l'instruction peut être simple ou composée.

Voici un exemple d'instruction if-else : la méthode test( ) détermine si une estimation est supérieure, inférieure ou
équivalente à une valeur donnée :

//: c03:IfElse.java
public class IfElse {
static int test(int testval, int target) {
int result = 0;
if(testval > target)
result = +1;
else if(testval < target)
result = -1;
else
result = 0; // Identique

- 98 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

return result;
}
public static void main(String[] args) {
System.out.println(test(10, 5));
System.out.println(test(5, 10));
System.out.println(test(5, 5));
}
} ///:~

Par convention, on indente le corps d'une instruction de contrôle de flux, afin que le lecteur détermine plus facilement
son début et sa fin.

V-B-2-a - return

Le mot-clef return a deux buts : il spécifie la valeur que la méthode doit retourner (si elle n'a pas un type de retour
void) et provoque le renvoi immédiat de cette valeur. Voici la méthode test( ) ci-dessus, réécrite en utilisant cette
propriété :

//: c03:IfElse2.java
public class IfElse2 {
static int test(int testval, int target) {
int result = 0;
if(testval > target)
return +1;
else if(testval < target)
return -1;
else
return 0; // Identique
}
public static void main(String[] args) {
System.out.println(test(10, 5));
System.out.println(test(5, 10));
System.out.println(test(5, 5));
}
} ///:~

V-B-3 - Itération

Les instructions de contrôle de boucle while, do-while et for sont souvent appelés instructions d'itération. Une
instruction est répétée jusqu'à ce que l'expression booléenne de contrôle devienne fausse. Voici la forme d'une
boucle while :

while(expression booléenne)
instruction

expression booléenne est évaluée à l'entrée de la boucle, puis après chaque itération ultérieure d'instruction.

Voici un exemple simple qui génère des nombres aléatoires jusqu'à l'arrivée d'une condition particulière :

//: c03:WhileTest.java
// Démonstration de la boucle while.

public class WhileTest {


public static void main(String[] args) {
double r = 0;
while(r < 0.99d) {
r = Math.random();
System.out.println(r);
}
}
} ///:~

- 99 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

Ce test utilise la méthode static random( ) de la bibliothèque Math, qui génère une valeur double comprise entre 0
et 1. (0 inclus, 1 exclu). L'expression conditionnelle de la boucle while signifie « continuer l'exécution de cette boucle
jusqu'à ce que le nombre généré soit égal ou supérieur à 0.99 ». Le résultat est une liste de nombre, et la taille de
cette liste est différente à chaque exécution du programme.

V-B-4 - do-while

Voici la forme de la boucle do-while :

do
instruction
while(expression booléenne);

La seule différence entre while et do-while est que dans une boucle do-while, instruction est exécutée au moins
une fois, même si l'expression est fausse la première fois. Dans une boucle while, si l'expression conditionnelle est
fausse la première fois, l'instruction n'est jamais exécutée. En pratique, la boucle do-while est moins utilisée que
while.

V-B-5 - for

La boucle for effectue une initialisation avant la première itération. Puis elle effectue un test conditionnel et, à la fin
de chaque itération, une « instruction d'itération ». Voici la forme d'une boucle for :

for(instruction d'initialisation; expression booléenne; instruction d'itération)


instruction

Chacune des expressions instruction d'initialisation, expression booléenne et instruction d'itération peut être
vide. expression booléenne est testée avant chaque itération, et dès qu'elle est évaluée à false l'exécution continue
à la ligne suivant l'instruction for. À la fin de chaque boucle, instruction d'itération est exécutée.

Les boucles for sont généralement utilisées pour les tâches impliquant un décompte :

//: c03:ListCharacters.java
// Démonstration de la boucle "for" listant
// tous les caractères ASCII.

public class ListCharacters {


public static void main(String[] args) {
for( char c = 0; c < 128; c++)
if (c != 26 ) // Effacement de l'écran ANSI
System.out.println(
"value: " + (int)c +
" character: " + c);
}
} ///:~

Remarquons que la variable c est définie à l'endroit où elle est utilisée, à l'intérieur de l'expression de contrôle de la
boucle for, plutôt qu'au début du bloc commençant à l'accolade ouvrante. La portée de c est l'expression contrôlée
par la boucle for.

Les langages procéduraux traditionnels tels que C exigent que toutes les variables soient définies au début d'un bloc
afin que le compilateur leur alloue de l'espace mémoire lorsqu'il crée un bloc. En Java et C++ les déclarations de
variables peuvent apparaître n'importe où dans le bloc, et être ainsi définies au moment où on en a besoin. Ceci
permet un style de code plus naturel et rend le code plus facile à comprendre.

Il est possible de définir plusieurs variables dans une instruction for, à condition qu'elles aient le même type :

for(int i = 0, j = 1;

- 100 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

i < 10 && j != 11;


i++, j++)
/* corps de la boucle for */;

La définition int de l'instruction for s'applique à la fois à i et à j. La possibilité de définir des variables dans une
expression de contrôle est limitée à la boucle for. On ne peut l'utiliser dans aucune autre instruction de sélection
ou d'itération.

V-B-5-a - L'opérateur virgule

Au début de ce chapitre j'ai déclaré que l'opérateur virgule (à distinguer du séparateur virgule, utilisé pour séparer
les définitions et les arguments de fonctions) avait un seul usage en Java, à savoir dans l'expression de contrôle d'une
boucle for. Aussi bien la partie initialisation que la partie itération de l'expression de contrôle peuvent être formées
de plusieurs instructions séparées par des virgules, et ces instructions seront évaluées séquentiellement. L'exemple
précédent utilisait cette possibilité. Voici un autre exemple :

//: c03:CommaOperator.java
public class CommaOperator {
public static void main(String[] args) {
for(int i = 1, j = i + 10; i < 5;
i++, j = i * 2) {
System.out.println("i= " + i + " j= " + j);
}
}
} ///:~

En voici le résultat :

i= 1 j= 11
i= 2 j= 4
i= 3 j= 6
i= 4 j= 8

remarquez que la partie initialisation ainsi que la partie itération sont évaluées en ordre séquentiel. La partie
initialisation peut comporter n'importe quel nombre de définitions du même type.

V-B-6 - break et continue

Le déroulement de toutes les instructions d'itération peut être contrôlé de l'intérieur du corps de la boucle au moyen
des instructions break et continue. L'instruction break sort de la boucle sans exécuter la suite des instructions.
L'instruction continue arrête l'exécution de l'itération courante, et l'exécution reprend en début de boucle avec
l'itération suivante.

Ce programme montre des exemples d'utilisation des instructions break et continue dans des boucles for et while :

//: c03:BreakAndContinue.java
// Démonstration des mots-clefs break et continue.

public class BreakAndContinue {


public static void main(String[] args) {
for(int i = 0; i < 100; i++) {
if(i == 74) break; // Sortie définitive de la boucle for
if(i % 9 != 0) continue; // Continue avec l'itération suivante
System.out.println(i);
}
int i = 0;
// une "boucle infinie" :
while(true) {
i++;
int j = i * 27;
if(j == 1269) break; // Sortie de boucle

- 101 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

if(i % 10 != 0) continue; // Début de boucle


System.out.println(i);
}
}
} ///:~

Dans la boucle for la valeur de i n'atteint jamais 100, car l'instruction break termine la boucle lorsque i prend la valeur
74. En principe, il ne faudrait pas utiliser break de cette manière, à moins que l'on ne connaisse pas le moment où
la condition de fin arrivera. L'instruction continue provoque un branchement au début de la boucle d'itération (donc
en incrémentant i) chaque fois que i n'est pas divisible par 9. Lorsqu'il l'est, la valeur est imprimée.

La seconde partie montre une « boucle infinie » qui, théoriquement, ne devrait jamais s'arrêter. Toutefois, elle contient
une instruction break lui permettant de le faire. De plus, l'instruction continue retourne au début de la boucle au lieu
d'exécuter la fin, ainsi la seconde boucle n'imprime que lorsque la valeur de i est divisible par 10. La sortie est :

0
9
18
27
36
45
54
63
72
10
20
30
40

La valeur 0 est imprimée, car 0 % 9 a pour résultat 0.

Il existe une seconde forme de boucle infinie, c'est for(;;). Le compilateur traite while(true) et for(;;) de la même
manière, le choix entre l'une et l'autre est donc affaire de goût.

V-B-6-a - L'infâme « goto »

Le mot-clef goto est aussi ancien que les langages de programmation. En effet, goto a été le premier moyen de
contrôle des programmes dans les langages assembleur : « si la condition A est satisfaite, alors sauter ici, sinon
sauter là ». Lorsqu'on lit le code assembleur finalement généré par n'importe quel compilateur, on voit qu'il comporte
beaucoup de sauts. Toutefois, un goto au niveau du code source est un saut, et c'est ce qui lui a donné mauvaise
réputation. Un programme n'arrêtant pas de sauter d'un point à un autre ne peut-il être réorganisé afin que le flux du
programme soit plus séquentiel ? goto tomba en disgrâce après la publication du fameux article « Le goto considéré
comme nuisible » écrit par Edsger Dijkstra, et depuis lors les guerres de religion à propos de son utilisation sont
devenues monnaie courante, les partisans du mot-clef honni recherchant une nouvelle audience.

Comme il est habituel en de semblables situations, la voie du milieu est la plus indiquée. Le problème n'est pas
d'utiliser le goto, mais de trop l'utiliser - dans quelques rares situations, le goto est réellement la meilleure façon de
structurer le flux de programme.

Bien que goto soit un mot réservé de Java, on ne le trouve pas dans le langage ; Java n'a pas de goto. Cependant,
il existe quelque chose qui ressemble à un saut, lié aux mots-clefs break et continue. Ce n'est pas vraiment un saut,
mais plutôt une manière de sortir d'une instruction d'itération. On le présente dans les discussions sur le goto parce
qu'il utilise le même mécanisme : une étiquette.

Une étiquette est un identificateur suivi du caractère deux-points, comme ceci :

label1:

- 102 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

En Java, une étiquette ne peut se trouver qu'en un unique endroit : juste avant une instruction d'itération. Et, j'insiste,
juste avant - il n'est pas bon de mettre une autre instruction entre l'étiquette et la boucle d'itération. De plus, il n'y a
qu'une seule bonne raison de mettre une étiquette avant une itération, c'est lorsqu'on a l'intention d'y nicher une autre
itération ou un switch. Ceci parce que les mots-clefs break et continue ont pour fonction naturelle d'interrompre la
boucle en cours, alors qu'utilisés avec une étiquette ils interrompent la boucle pour se brancher à l'étiquette :

label1:
outer-iteration {
inner-iteration {
//...
break; // 1
//...
continue; // 2
//...
continue label1; // 3
//...
break label1; // 4
}
}

Cas 1 : break interrompt l'itération intérieure, on se retrouve dans l'itération extérieure. Cas 2 : continue branche à
l'itération intérieure. Mais, cas 3 : continue label1 interrompt l'itération intérieure et l'itération extérieure, et branche
dans tous les cas à label1. En fait, l'itération continue, mais en redémarrant à partir de l'itération extérieure. Cas 4 :
break label1 interrompt lui aussi dans tous les cas et branche à label1, mais ne rentre pas à nouveau dans l'itération.
En fait il sort des deux itérations.

Voici un exemple utilisant les boucles for :

//: c03:LabeledFor.java
// la boucle for "étiquetée" en Java.

public class LabeledFor {


public static void main(String[] args) {
int i = 0;
outer: // Il ne peut y avoir d'instruction ici
for(; true ;) { // boucle infinie
inner: // Il ne peut y avoir d'instruction ici
for(; i < 10; i++) {
prt("i = " + i);
if(i == 2) {
prt("continue");
continue;
}
if(i == 3) {
prt("break");
i++; // Sinon i ne sera
// jamais incrémenté.
break;
}
if(i == 7) {
prt("continue outer");
i++; // Sinon i ne sera
// jamais incrémenté.
continue outer;
}
if(i == 8) {
prt("break outer");
break outer;
}
for(int k = 0; k < 5; k++) {
if(k == 3) {
prt("continue inner");
continue inner;
}
}
}
}

- 103 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

// On ne peut pas utiliser un break ou


// un continue vers une étiquette ici
}
static void prt(String s) {
System.out.println(s);
}
} ///:~

Ce programme utilise la méthode prt( ) déjà définie dans d'autres exemples.

Noter que break sort de la boucle for, et l'expression d'incrémentation ne sera jamais exécutée avant le passage en
fin de boucle for. Puisque break saute l'instruction d'incrémentation, l'incrémentation est réalisée directement dans
le cas où i == 3. Dans le cas i == 7, l'instruction continue outer saute elle aussi en tête de la boucle, donc saute
l'incrémentation, qui est, ici aussi, réalisée directement.

Voici le résultat :

i = 0
continue inner
i = 1
continue inner
i = 2
continue
i = 3
break
i = 4
continue inner
i = 5
continue inner
i = 6
continue inner
i = 7
continue outer
i = 8
break outer

Si l'instruction break outer n'était pas là, il n'y aurait aucun moyen de se brancher à l'extérieur de la boucle extérieure
depuis la boucle intérieure, puisque break utilisé seul ne permet de sortir que de la boucle la plus interne (il en est
de même pour continue).

Évidemment, lorsque break a pour effet de sortir de la boucle et de la méthode, il est plus simple d'utiliser return.

Voici une démonstration des instructions étiquetées break et continue avec des boucles while :

//: c03:LabeledWhile.java
// La boucle while "étiquetée" en Java.

public class LabeledWhile {


public static void main(String[] args) {
int i = 0;
outer:
while(true) {
prt("Outer while loop");
while(true) {
i++;
prt("i = " + i);
if(i == 1) {
prt("continue");
continue;
}
if(i == 3) {
prt("continue outer");
continue outer;
}
if(i == 5) {

- 104 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

prt("break");
break;
}
if(i == 7) {
prt("break outer");
break outer;
}
}
}
}
static void prt(String s) {
System.out.println(s);
}
} ///:~

Les mêmes règles s'appliquent au while :

1 Un continue génère un saut en tête de la boucle courante et poursuit l'exécution ;


2 Un continue étiqueté génère un saut à l'étiquette puis entre à nouveau dans la boucle juste après cette
étiquette ;
3 Un break « sort de la boucle par le bas » ;
4 Un break étiqueté sort de la boucle par le bas, à la fin de la boucle repérée par l'étiquette.

Le résultat de cette méthode éclaircit cela :

Outer while loop


i = 1
continue
i = 2
i = 3
continue outer
Outer while loop
i = 4
i = 5
break
Outer while loop
i = 6
i = 7
break outer

Il est important de se souvenir qu'il n'y a qu'une seule raison d'utiliser une étiquette en Java, c'est lorsqu'il existe
plusieurs boucles imbriquées et que l'on veut utiliser break ou continue pour traverser plus d'un niveau d'itération.

Dijkstra, dans son article « Le goto considéré comme nuisible », critiquait les étiquettes, mais pas le goto lui-même.
Il avait observé que le nombre de bogues semblait augmenter avec le nombre d'étiquettes d'un programme. Les
étiquettes et les goto rendent difficile l'analyse statique d'un programme, car ils introduisent des cycles dans le graphe
d'exécution de celui-ci. Remarquons que les étiquettes Java ne sont pas concernées par ce problème, dans la mesure
où leur emplacement est contraint, et qu'elles ne peuvent pas être utilisées pour réaliser un transfert de contrôle à
la demande. Il est intéressant de noter que nous nous trouvons dans un cas où une fonctionnalité du langage est
rendue plus utile en en diminuant la puissance.

V-B-7 - switch

On parle parfois de switch comme d'une instruction de sélection. L'instruction switch sélectionne un morceau de
code parmi d'autres en se basant sur la valeur d'une expression entière. Voici sa forme :

switch(sélecteur-entier) {
case valeur-entière1 : instruction; break;
case valeur-entière2 : instruction; break;
case valeur-entière3 : instruction; break;
case valeur-entière4 : instruction; break;
case valeur-entière5 : instruction; break;

- 105 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

// ...
default : instruction;
}

sélecteur-entier est une expression qui produit une valeur entière. switch compare le résultat de sélecteur-entier
avec chaque valeur-entière. S'il trouve une égalité, l'instruction correspondante (simple ou composée) est exécutée.
Si aucune égalité n'est trouvée, l'instruction qui suit default est exécutée. Notons dans la définition précédente que
chaque instruction case se termine par une instruction break, qui provoque un saut à la fin du corps de l'instruction
switch. Ceci est la manière habituelle de construire une instruction switch. Cependant break est optionnel. S'il n'est
pas là, le code associé à l'instruction case suivante est exécuté, et ainsi de suite jusqu'à la rencontre d'une instruction
break. Bien qu'on n'ait généralement pas besoin d'utiliser cette possibilité, elle peut se montrer très utile pour un
programmeur expérimenté. La dernière instruction, qui suit default, n'a pas besoin de break, car en fait l'exécution
continue juste à l'endroit où une instruction break l'aurait amenée de toute façon. Il n'y a cependant aucun problème
à terminer l'instruction default par une instruction break si on pense que le style de programmation est une question
importante.

L'instruction switch est une manière propre d'implémenter une sélection multiple (c'est-à-dire sélectionner un certain
nombre de possibilités d'exécution), mais elle requiert une expression de sélection dont le résultat soit entier, comme
int ou char. Par exemple on ne peut pas utiliser une chaîne de caractères ou un flottant comme sélecteur dans une
instruction switch. Pour les types non entiers, il faut mettre en œuvre une série d'instructions if.

Voici un exemple qui crée des lettres aléatoirement, et détermine s'il s'agit d'une voyelle ou d'une consonne :

//: c03:VowelsAndConsonants.java
// Démonstration de l'instruction switch.

public class VowelsAndConsonants {


public static void main(String[] args) {
for(int i = 0; i < 100; i++) {
char c = (char)(Math.random() * 26 + 'a');
System.out.print(c + ": ");
switch(c) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
System.out.println("vowel");
break;
case 'y':
case 'w':
System.out.println(
"Sometimes a vowel");
break;
default:
System.out.println("consonant");
}
}
}
} ///:~

Math.random( ) générant une valeur entre 0 et 1, il faut la multiplier par la borne supérieure de l'intervalle des nombres
qu'on veut produire (26 pour les lettres de l'alphabet) puis ajouter un décalage correspondant à la borne inférieure.

Bien qu'il semble que la sélection s'opère ici sur un type caractère, l'instruction switch utilise en réalité la valeur entière
du caractère. Les caractères entre guillemets simples des instructions case sont également interprétés comme des
entiers avant la comparaison.

Remarquez la manière d'empiler les instructions case pour affecter un même code d'exécution à plusieurs cas
d'égalité. Il faut également faire attention à terminer chaque instruction par une instruction break, faute de quoi le
contrôle serait transféré à l'instruction correspondant au case suivant.

- 106 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

V-B-7-a - Détails de calcul :

L'instruction :

char c = (char)(Math.random() * 26 + 'a');

mérite une attention particulière. Math.random( ) a pour résultat un double, par suite la valeur 26 est convertie en
double avant que la multiplication ne soit effectuée ; cette dernière a aussi pour résultat un double. Ce qui signifie
que 'a' doit lui aussi être converti en double avant d'exécuter l'addition. Le résultat double est finalement transtypé
en char.

Que fait exactement ce transtypage ? En d'autres termes, si on obtient une valeur de 29.7 et qu'on la transtype en
char, le résultat est-il 30 ou 29 ? La réponse est dans l'exemple suivant :

//: c03:CastingNumbers.java
// Qu'arrive-t-il lorsqu'on transtype un flottant
// ou un double vers une valeur entière ?

public class CastingNumbers {


public static void main(String[] args) {
double
above = 0.7,
below = 0.4;
System.out.println("above: " + above);
System.out.println("below: " + below);
System.out.println(
"(int)above: " + (int)above);
System.out.println(
"(int)below: " + (int)below);
System.out.println(
"(char)('a' + above): " +
(char)('a' + above));
System.out.println(
"(char)('a' + below): " +
(char)('a' + below));
}
} ///:~

Le résultat :

above: 0.7
below: 0.4
(int)above: 0
(int)below: 0
(char)('a' + above): a
(char)('a' + below): a

La réponse est donc : le transtypage d'un type float ou double vers une valeur entière entraîne une troncature dans
tous les cas.

Une seconde question à propos de Math.random( ) : cette méthode produit des nombres entre zéro et un, mais :
les valeurs 0 et 1 sont-elles incluses ou exclues ? En jargon mathématique, obtient-on ]0,1[, [0,1], ]0,1] ou [0,1[ ? (les
crochets « tournés vers le nombre » signifient « ce nombre est inclus », et ceux tournés vers l'extérieur « ce nombre
est exclu »). À nouveau, un programme de test devrait nous donner la réponse :

//: c03:RandomBounds.java
// Math.random() produit-il les valeurs 0.0 et 1.0 ?

public class RandomBounds {


static void usage() {
System.out.println("Usage: \n\t" +
"RandomBounds lower\n\t" +
"RandomBounds upper");

- 107 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

System.exit(1);
}
public static void main(String[] args) {
if(args.length != 1) usage();
if(args[0].equals("lower")) {
while(Math.random() != 0.0)
; // Essayer encore
System.out.println("Produced 0.0!");
}
else if(args[0].equals("upper")) {
while(Math.random() != 1.0)
; // Essayer encore
System.out.println("Produced 1.0!");
}
else
usage();
}
} ///:~

Pour lancer le programme, frapper en ligne de commande :

java RandomBounds lower

ou bien :

java RandomBounds upper

Dans les deux cas nous sommes obligés d'arrêter le programme manuellement, et il semble donc que
Math.random( ) ne produise jamais les valeurs 0.0 ou 1.0. Une telle expérience est décevante. Si vous
remarquez (20) qu'il existe environ 262 fractions différentes en double précision entre 0 et 1, alors la probabilité
d'atteindre expérimentalement l'une ou l'autre des valeurs pourrait dépasser la vie d'un ordinateur, voire celle de
l'expérimentateur. Cela ne permet pas de montrer que 0.0 est inclus dans les résultats de Math.random( ). En réalité,
en jargon mathématique, le résultat est [0,1[.

V-C - Résumé

Ce chapitre termine l'étude des fonctionnalités fondamentales qu'on retrouve dans la plupart des langages de
programmation : calcul, priorité des opérateurs, transtypage, sélection et itération. Vous êtes désormais prêts à
aborder le monde de la programmation orientée objet. Le prochain chapitre traite de la question importante de
l'initialisation et du nettoyage des objets, et le suivant du concept essentiel consistant à cacher l'implémentation.

V-D - Exercices

Les solutions des exercices sélectionnés sont dans le document électronique The Thinking in Java Annotated
Solution Guide, disponible pour un faible coût à www.BruceEckel.com.

1 Dans la section « priorité » au début de ce chapitre, il y a deux expressions. Utiliser ces expressions dans un
programme qui montre qu'elles produisent des résultats différents.
2 Utiliser les méthodes ternary( ) et alternative( ) dans un programme qui fonctionne.
3 À partir des sections « if-else » et « return », utiliser les méthodes test( ) et test2( ) dans un programme qui
fonctionne.
4 Écrire un programme qui imprime les valeurs de un à 100.
5 Modifier l'exercice 4 de manière que le programme termine avec la valeur 47, en utilisant le mot-clef break.
Même exercice en utilisant return.
6 Écrire une fonction prenant pour arguments deux String, utiliser les comparaisons booléennes pour comparer
les deux chaînes et imprimer le résultat. En plus de == et !=, tester aussi equals( ). Dans la méthode main( ),
appeler la fonction avec différents objets de type String.

- 108 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

7 Écrire un programme qui génère aléatoirement 25 valeurs entières. Pour chaque valeur, utiliser une
instruction if-then-else pour la classer (plus grande, plus petite, ou égale) par rapport à une deuxième valeur
générée aléatoirement.
8 Modifier l'exercice 7 en englobant le code dans une boucle while infinie. Il devrait alors fonctionner tant qu'on
ne l'interrompt pas au moyen du clavier (classiquement avec Ctrl-C).
9 Écrire un programme utilisant deux boucles for imbriquées ainsi que l'opérateur modulo (%) pour détecter et
imprimer les nombres premiers (les nombres entiers qui ne sont divisibles que par eux-mêmes et l'unité).
10 Écrire une instruction switch qui imprime un message pour chaque case, la mettre dans une boucle for
qui teste chaque case. Mettre un break après chaque case, tester, puis enlever les break et voir ce qui se
passe...

VI - Initialisation et nettoyage

Depuis le début de la révolution informatique, la programmation « sans garde-fou » est la principale cause des coûts
de développement excessifs.

L'initialisation et la libération d'éléments sont deux problèmes majeurs. De nombreux bogues en C surviennent
lorsque le programmeur oublie d'initialiser une variable. L'utilisation de bibliothèques augmente ce risque, car les
utilisateurs ne savent pas toujours comment initialiser certains composants, ni même qu'ils le doivent. La phase de
nettoyage ou libération pose problème dans la mesure où il est très facile d'oublier l'existence d'un élément dont on
n'a plus besoin, car justement il ne nous intéresse plus. Dans ce cas, certaines ressources utilisées par un élément
oublié sont conservées. Ce phénomène peut entraîner un manque de ressources (dans la majorité des cas, un
manque de mémoire).

C++ a introduit la notion de constructeur, une méthode appelée automatiquement à la création d'un objet. Java
utilise aussi les constructeurs, associé à un ramasse-miettes qui libère les ressources mémoire lorsqu'elles ne sont
plus utilisées. Ce chapitre décrit les concepts d'initialisation et de libération, ainsi que leur support dans Java.

VI-A - Garantie d'initialisation grâce au constructeur

Pour chaque classe il serait possible de créer une méthode initialise( ). Ce nom inciterait à exécuter la méthode
avant d'utiliser l'objet. Malheureusement ce serait à l'utilisateur de se souvenir d'appeler cette méthode pour chaque
instance. En Java, le concepteur d'une classe peut garantir son initialisation grâce à une méthode spéciale que
l'on dénomme constructeur. Quand une classe possède un constructeur, Java l'appelle automatiquement à toute
création d'objets, avant qu'ils ne puissent être utilisés. L'initialisation est donc bien garantie.

Le premier problème consiste à trouver un nom pour cette méthode ce qui entraîne deux nouveaux problèmes. Tout
d'abord il pourrait y avoir un conflit avec le nom d'un attribut. Ensuite c'est à la compilation que l'appel du constructeur
est vérifié. Il faut donc que le compilateur puisse décider du nom du constructeur. La solution de C++ paraît la plus
simple et la plus logique, elle est donc aussi utilisée en Java. Il faut donc donner au constructeur le nom de sa classe.
Il semble naturel qu'une telle méthode soit en charge de l'initialisation de la classe.

Voici une classe avec un constructeur :

//: c04:SimpleConstrutor.java
// Démonstration d'un constructeur.

class Rock {
Rock() { // Ceci est un constructeur
System.out.println("Creating Rock");
}
}

public class SimpleConstructor {


public static void main(String[] args) {
for(int i = 0; i < 10; i++)
new Rock();
}

- 109 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

} ///:~

Quand un objet est créé :

new Rock();

de l'espace mémoire est alloué et le constructeur est appelé. L'objet sera obligatoirement initialisé avant qu'il ne
puisse être manipulé.

Notez que la convention de nommage qui impose une minuscule pour la première lettre des noms de méthode ne
s'applique pas aux constructeurs, leur nom devant exactement coïncider avec celui de la classe.

Comme les autres méthodes, un constructeur peut prendre des paramètres. Cela permet de préciser comment
l'objet va être créé. Notre premier exemple peut facilement être modifié pour que le constructeur prenne un unique
paramètre :

//: c04:SimpleConstructor2.java
// Les constructeurs peuvent prendre des paramètres.

class Rock2 {
Rock2(int i) {
System.out.println(
"Creating Rock number " + i);
}
}

public class SimpleConstructor2 {


public static void main(String[] args) {
for(int i = 0; i < 10; i++)
new Rock2(i);
}
} ///:~

Les paramètres des constructeurs permettent de personnaliser la création des objets. Par exemple, si la classe Tree
(arbre) a un constructeur avec un paramètre de type int qui détermine la hauteur de l'arbre, un objet Tree se crée
de la façon suivante :

Tree t = new Tree(12); // arbre de 12 pieds

De plus, si Tree(int) est le seul constructeur, le compilateur ne permettra pas de créer un objet Tree d'une autre façon.

La notion de constructeur élimine toute une catégorie d'erreurs et rend plus aisée la lecture du code. Dans le
fragment de code précédent, par exemple, il n'y a pas d'appel explicite à une certaine méthode initialise( ) qui
serait conceptuellement séparée de la définition. En Java, définition et initialisation sont des concepts unifiés - il est
impossible d'avoir l'un sans l'autre.

Un constructeur est une méthode très spéciale de par le fait qu'elle n'a pas de valeur de retour. Cela n'a absolument
rien à voir avec le type de retour void, qui signifie qu'une méthode ne renvoie rien, mais qu'il aurait tout à fait été
possible de lui faire renvoyer autre chose. Les constructeurs ne retournent rien et on n'a pas le choix. S'il y avait une
valeur de retour, et si l'on pouvait choisir son type, le compilateur devrait trouver une utilisation à cette valeur.

VI-B - Surcharge de méthodes

L'un des points les plus importants de tout langage de programmation est le nommage. Créer un objet revient à
donner un nom à un emplacement mémoire. Une méthode est un nom d'action. En utilisant des noms pour décrire
un système, on simplifie la lecture et la modification des programmes. Cela s'apparente à l'écriture en prose dont le
but est de communiquer avec le lecteur.

- 110 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

On se réfère à tous les objets et méthodes en utilisant leurs noms. Des noms bien choisis rendent la compréhension
du code plus aisée, tant pour le développeur que pour les relecteurs.

Les difficultés commencent lorsque l'on essaie d'exprimer les nuances subtiles du langage humain dans un langage
de programmation. Très souvent, un même mot a plusieurs sens, on parle de surcharge. Cette notion est très pratique
pour exprimer les différences triviales de sens. On dit « laver la chemise » , « laver la voiture » et « laver le chien » .
Cela paraîtrait absurde d'être obligé de dire « laverChemise la chemise » , « laverVoiture la voiture » et « laverChien
le chien » pour que l'auditoire puisse faire la distinction entre ces actions. La plupart des langages humains sont
redondants à tel point que même sans entendre tous les mots, il est toujours possible de comprendre le sens d'une
phrase. Nous n'avons aucunement besoin d'identifiants uniques, le sens peut être déduit du contexte.

La plupart des langages de programmation (C en particulier) imposent un nom unique pour chaque fonction. Ils ne
permettent pas d'appeler une fonction affiche( ) pour afficher des entiers et une autre appelée affiche( ) pour afficher
des flottants, chaque fonction doit avoir un nom unique.

En Java (et en C++), un autre facteur impose la surcharge de noms de méthodes : les constructeurs. Comme le nom
d'un constructeur est déterminé par le nom de la classe, il ne peut y avoir qu'un seul nom de constructeur. Mais que
se passe-t-il quand on veut créer un objet de différentes façons ? Par exemple, supposons que l'on construise une
classe qui peut s'initialiser de façon standard ou en lisant des informations depuis un fichier. Nous avons alors besoin
de deux constructeurs, l'un ne prenant pas de paramètre (le constructeur par défaut, aussi appelé le constructeur
sans paramètre/no-arg), et un autre prenant une Chaîne/String comme paramètre, qui représente le nom du fichier
depuis lequel on souhaite initialiser l'objet. Tous les deux sont des constructeurs, ils doivent donc avoir le même
nom, le nom de la classe. Cela montre que la surcharge de méthode est essentielle pour utiliser le même nom de
méthode pour des utilisations sur différents types de paramètres. Et si la surcharge de méthode est obligatoire pour
les constructeurs, elle est aussi très pratique pour les méthodes ordinaires.

L'exemple suivant montre à la fois une surcharge de constructeur et une surcharge de méthode ordinaire :

//: c04:Overloading.java
// Exemple de surcharge de constructeur
// et de méthode ordinaire.
import java.util.*;

class Tree {
int height;
Tree() {
prt("Planting a seedling"); // Planter une jeune pousse
height = 0;
}
Tree(int i) {
prt("Creating new Tree that is " // Création d'un arbre
+ i + " feet tall"); // de i pieds de haut
height = i;
}
void info() {
prt("Tree is " + height // L'arbre mesure x pieds
+ " feet tall");
}
void info(String s) {
prt(s + ": Tree is " // valeur de s : L'arbre mesure x pieds
+ height + " feet tall");
}
static void prt(String s) {
System.out.println(s);
}
}

public class Overloading {


public static void main(String[] args) {
for(int i = 0; i < 5; i++) {
Tree t = new Tree(i);
t.info();
t.info("overloaded method");
}

- 111 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

// constructeur surchargé :
new Tree();
}
} ///:~

Un objet Tree peut être créé soit en tant que jeune pousse, sans fournir de paramètre, soit en tant que plante poussée
en pépinière, en donnant une hauteur initiale. Pour permettre ceci, il y a deux constructeurs, l'un ne prend pas de
paramètre (on appelle les constructeurs sans paramètre des constructeurs par défaut name="fnB27" (21) ) et un
deuxième qui prend la hauteur initiale de l'arbre.

Il est aussi possible d'appeler la méthode info( ) de plusieurs façons. Par exemple, avec un paramètre String si un
message supplémentaire est désiré, ou sans paramètre lorsqu'il n'y a rien d'autre à dire. Cela paraîtrait étrange de
donner deux noms distincts à ce qui est manifestement le même concept. Heureusement, la surcharge de méthode
permet l'utilisation du même nom pour les deux.

VI-B-1 - Différencier les méthodes surchargées

Quand deux méthodes ont le même nom, comment Java peut-il décider quelle méthode est demandée ? Il y a une
règle toute simple : chaque méthode surchargée doit prendre une liste unique de types de paramètres.

Lorsqu'on y pense, cela paraît tout à fait sensé : comment le développeur lui-même pourrait-il choisir entre deux
méthodes du même nom, autrement que par le type des paramètres ?

Une différence dans l'ordre des paramètres est suffisante pour distinguer deux méthodes (cette approche n'est
généralement pas utilisée, car elle donne du code difficile à maintenir) :

//: c04:OverloadingOrder.java
// Surcharge basée sur l'ordre
// des paramètres.

public class OverloadingOrder {


static void print(String s, int i) {
System.out.println(
"String: " + s +
", int: " + i);
}
static void print(int i, String s) {
System.out.println(
"int: " + i +
", String: " + s);
}
public static void main(String[] args) {
print("String first", 11);
print(99, "Int first");
}
} ///:~

Les deux méthodes print( ) ont les mêmes paramètres, mais dans un ordre différent, et c'est ce qui les différencie.

VI-B-2 - Surcharge avec types de base

Un type de base peut être promu automatiquement depuis un type plus petit vers un plus grand ; ceci peut devenir
déconcertant dans certains cas de surcharge. L'exemple suivant montre ce qui se passe lorsqu'un type de base est
passé à une méthode surchargée :

//: c04:PrimitiveOverloading.java
// Promotion des types de base et surcharge.

public class PrimitiveOverloading {


// boolean ne peut pas être converti automatiquement

- 112 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

static void prt(String s) {


System.out.println(s);
}

void f1(char x) { prt("f1(char)"); }


void f1(byte x) { prt("f1(byte)"); }
void f1(short x) { prt("f1(short)"); }
void f1(int x) { prt("f1(int)"); }
void f1(long x) { prt("f1(long)"); }
void f1(float x) { prt("f1(float)"); }
void f1(double x) { prt("f1(double)"); }

void f2(byte x) { prt("f2(byte)"); }


void f2(short x) { prt("f2(short)"); }
void f2(int x) { prt("f2(int)"); }
void f2(long x) { prt("f2(long)"); }
void f2(float x) { prt("f2(float)"); }
void f2(double x) { prt("f2(double)"); }

void f3(short x) { prt("f3(short)"); }


void f3(int x) { prt("f3(int)"); }
void f3(long x) { prt("f3(long)"); }
void f3(float x) { prt("f3(float)"); }
void f3(double x) { prt("f3(double)"); }

void f4(int x) { prt("f4(int)"); }


void f4(long x) { prt("f4(long)"); }
void f4(float x) { prt("f4(float)"); }
void f4(double x) { prt("f4(double)"); }

void f5(long x) { prt("f5(long)"); }


void f5(float x) { prt("f5(float)"); }
void f5(double x) { prt("f5(double)"); }

void f6(float x) { prt("f6(float)"); }


void f6(double x) { prt("f6(double)"); }

void f7(double x) { prt("f7(double)"); }

void testConstVal() {
prt("Testing with 5");
f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5);
}
void testChar() {
char x = 'x';
prt("char argument:");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
}
void testByte() {
byte x = 0;
prt("byte argument:");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
}
void testShort() {
short x = 0;
prt("short argument:");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
}
void testInt() {
int x = 0;
prt("int argument:");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
}
void testLong() {
long x = 0;
prt("long argument:");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
}
void testFloat() {
float x = 0;
prt("float argument:");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);

- 113 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

}
void testDouble() {
double x = 0;
prt("double argument:");
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);
}
public static void main(String[] args) {
PrimitiveOverloading p =
new PrimitiveOverloading();
p.testConstVal();
p.testChar();
p.testByte();
p.testShort();
p.testInt();
p.testLong();
p.testFloat();
p.testDouble();
}
} ///:~

En regardant la sortie du programme, on voit que la constante 5 est considérée comme un int. Lorsqu'une méthode
surchargée utilisant un int est disponible, elle est utilisée. Dans tous les autres cas, si un type de données est plus
petit que l'argument de la méthode, le type est promu. char est légèrement différent, comme il ne trouve pas une
correspondance exacte, il est promu vers un int.

//: c04:Demotion.java
// Types de base déchus et surcharge.

public class Demotion {


static void prt(String s) {
System.out.println(s);
}

void f1(char x) { prt("f1(char)"); }


void f1(byte x) { prt("f1(byte)"); }
void f1(short x) { prt("f1(short)"); }
void f1(int x) { prt("f1(int)"); }
void f1(long x) { prt("f1(long)"); }
void f1(float x) { prt("f1(float)"); }
void f1(double x) { prt("f1(double)"); }

void f2(char x) { prt("f2(char)"); }


void f2(byte x) { prt("f2(byte)"); }
void f2(short x) { prt("f2(short)"); }
void f2(int x) { prt("f2(int)"); }
void f2(long x) { prt("f2(long)"); }
void f2(float x) { prt("f2(float)"); }

void f3(char x) { prt("f3(char)"); }


void f3(byte x) { prt("f3(byte)"); }
void f3(short x) { prt("f3(short)"); }
void f3(int x) { prt("f3(int)"); }
void f3(long x) { prt("f3(long)"); }

void f4(char x) { prt("f4(char)"); }


void f4(byte x) { prt("f4(byte)"); }
void f4(short x) { prt("f4(short)"); }
void f4(int x) { prt("f4(int)"); }

void f5(char x) { prt("f5(char)"); }


void f5(byte x) { prt("f5(byte)"); }
void f5(short x) { prt("f5(short)"); }

void f6(char x) { prt("f6(char)"); }


void f6(byte x) { prt("f6(byte)"); }

void f7(char x) { prt("f7(char)"); }

void testDouble() {
double x = 0;

- 114 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

prt("double argument:");
f1(x);f2((float)x);f3((long)x);f4((int)x);
f5((short)x);f6((byte)x);f7((char)x);
}
public static void main(String[] args) {
Demotion p = new Demotion();
p.testDouble();
}
} ///:~

Ici, les méthodes prennent des types de base plus restreints. Si les paramètres sont d'un type plus grand, if faut les
caster (convertir) vers le type requis en utilisant le nom du type entre parenthèses. Sinon, le compilateur donnera
un message d'erreur.

Il est important de noter qu'il s'agit d'une conversion vers un type plus petit, ce qui signifie que des informations
peuvent être perdues pendant la conversion. C'est d'ailleurs pour cette raison que le compilateur force une conversion
explicite.

VI-B-3 - Surcharge sur la valeur de retour

Il est fréquent de se demander « Pourquoi seulement les noms de classes et la liste des paramètres des méthodes ?
Pourquoi ne pas aussi distinguer entre deux méthodes en se basant sur leur type de retour ? » Par exemple, ces
deux méthodes, qui ont le même nom et les mêmes arguments, peuvent facilement être distinguées l'une de l'autre :

void f() {}
int f() {}

Cela fonctionne bien lorsque le compilateur peut déterminer le sens sans équivoque depuis le contexte, comme dans
int x = f( ). Par contre, on peut utiliser une méthode et ignorer sa valeur de retour. On se réfère souvent à cette action
comme appeler une méthode pour ses effets de bord puisqu'on ne s'intéresse pas à la valeur de retour, mais aux
autres effets que cet appel de méthode génère. Donc, si on appelle la méthode comme suit :

f();

Comment Java peut-il déterminer quelle méthode f( ) doit être exécutée ? Et comment quelqu'un lisant ce code
pourrait-il le savoir ? À cause de ce genre de difficultés, il est impossible d'utiliser la valeur de retour pour différencier
deux méthodes Java surchargées.

VI-B-4 - Constructeurs par défaut

Comme mentionné précédemment, un constructeur par défaut (c.à.d un constructeur « no-arg » ) est un constructeur
sans argument, utilisé pour créer des « objets de base ». Si une classe est créée sans constructeur, le compilateur
créé automatiquement un constructeur par défaut. Par exemple :

//: c04:DefaultConstructor.java

class Bird {
int i;
}

public class DefaultConstructor {


public static void main(String[] args) {
Bird nc = new Bird(); // défaut !
}
} ///:~

La ligne

new Bird();

- 115 -
Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par
les droits d'auteur. Copyright ® 2013 Bruce Eckel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://bruce-eckel.developpez.com/livres/java/traduction/tij2/
Penser en Java par Bruce Eckel

crée un nouvel objet et appelle le constructeur par défaut, même s'il n'était pas défini explicitement. Sans lui, il n'y
aurait pas de méthode à appeler pour créer cet objet. Par contre, si au moins un constructeur est défini (avec ou
sans argument), le compilateur n'en synthétisera pas un :

class Bush {
Bush(int i) {}
Bush(double d) {}
}

Maintenant si on écrit :

new Bush();

le compilateur donnera une erreur indiquant qu'aucun constructeur ne corre