Download as pdf or txt
Download as pdf or txt
You are on page 1of 214

Programmation avec

le langage Java

CENTRE DE CALCUL ET DES SYSTÈMES D'INFORMATION


NORBERT KAJLER
JEAN-MICHEL VIOVY
ET L'ÉQUIPE DU CCSI

v 1.3 (septembre 2015)


Table des matières

Objectifs 11

Pourquoi Java ? 13

I - Introduction 15
A. Les langages de programmation............................................................15
B. Origine et historique de Java................................................................18
C. Java aujourd'hui..................................................................................18
D. Caractéristiques techniques de Java......................................................19
E. Qualités et défauts de Java...................................................................20
F. JRE, Java SE, JDK, Eclipse, ..................................................................21
G. Les différentes « éditions » du langage Java...........................................22
H. Langages et technologies connexes.......................................................22

II - Syntaxe de base 25
A. Premiers exemples..............................................................................25
B. Variables, types, portée, commentaires, ….............................................26
1. Variables et types.............................................................................................26
2. Types « primitifs »............................................................................................26
3. Le type booléen................................................................................................27
4. Le type caractère..............................................................................................27
5. Les types entiers..............................................................................................28
6. Les types flottants............................................................................................28
7. Constantes......................................................................................................29
8. Déclaration et portée des variables.....................................................................30
9. Conventions de nommage.................................................................................30
10. Commentaires................................................................................................31

C. Opérateurs.........................................................................................31
1. Principaux opérateurs.......................................................................................31
2. Opérateurs arithmétiques..................................................................................32
3. Opérateurs de comparaison...............................................................................33
4. Opérateurs booléens.........................................................................................33
5. Opérateurs bit-à-bit..........................................................................................34
6. Opérateurs d'affectation....................................................................................34
7. Opérateurs d'incrémentation et de décrémentation...............................................35
8. Autres opérateurs.............................................................................................35
9. Priorité des opérateurs......................................................................................35

D. Blocs, instructions de contrôle (tests, boucles, …)...................................36


1. Instructions et blocs.........................................................................................36
2. Instructions de contrôle.....................................................................................37
3. Exécution conditionnelle....................................................................................37
4. Cas multiples...................................................................................................38
5. Boucles de répétitions.......................................................................................39
6. Boucles d'itération............................................................................................40

3
7. Boucles d'itération « simplifiées ».......................................................................40
8. Interruptions des boucles, labels........................................................................41

E. Entrées-sorties....................................................................................42
F. Exemple de programme, compilation, exécution......................................45

III - Références, tableaux, chaînes de caractères, types


énumérés simples 47
A. Références.........................................................................................47
B. Tableaux............................................................................................48
C. Chaînes de caractères..........................................................................53
D. Types énumérés simples......................................................................55
E. Références constantes.........................................................................56

IV - Fonctions 57
A. Introduction.......................................................................................57
B. Type de retour et instruction return.......................................................58
C. Appel (ou « invocation » ) de fonction....................................................59
D. Fonction et portée...............................................................................59
E. Programme principal............................................................................60
F. Passage des paramètres.......................................................................60
G. Récursivité.........................................................................................62
H. Surcharge (ou « overloading »)............................................................62
I. Fonctions à nombre variable d'arguments...............................................62
J. Fonctions « natives »...........................................................................63

V - Algorithmique, complexité, tris 65


A. Algorithme.........................................................................................65
B. Calculabilité........................................................................................66
C. Heuristique.........................................................................................67
D. Complexité, efficacité..........................................................................67
E. Algorithmique, classification des algorithmes, …......................................69
F. Problématique du tri............................................................................69
G. Tri par sélection..................................................................................70
H. Tri par insertion..................................................................................71
I. Tri bulle..............................................................................................72
J. Tri rapide............................................................................................74
K. Complexité des algorithmes de tri.........................................................77

VI - Programmation par objets 79


A. Vocabulaire (classe, instance, objet, ...).................................................79
B. Classes, instances, .............................................................................80
1. Classe.............................................................................................................80
2. Attributs..........................................................................................................81

4
3. Méthodes........................................................................................................81
4. Constructeur....................................................................................................81
5. Instanciation (mot-clé : new).............................................................................82
6. Tableau d'objets...............................................................................................83
7. L'instruction instanceof......................................................................................83
8. Destructeur.....................................................................................................84

C. This...................................................................................................84
1. this(...) dans un constructeur.............................................................................84
2. this comme référence........................................................................................84

D. Static................................................................................................85
1. Mot-clé static...................................................................................................85
2. Attribut statique...............................................................................................85
3. Initialiseur statique...........................................................................................86
4. Méthode statique..............................................................................................87
5. Appel de méthode statique................................................................................87
6. Static or not static ?..........................................................................................88

E. Visibilité.............................................................................................88
F. Types énumérés..................................................................................89

VII - Exceptions 91
A. Principe des exceptions........................................................................91
B. Gestion des erreurs.............................................................................91
C. Traitement des exceptions....................................................................93
D. Nature des exceptions.........................................................................93
E. Catégories d'exceptions........................................................................94
F. Exceptions contrôlées ou non................................................................94
G. Types d'exception usuels.....................................................................95
H. Lancement d'exception........................................................................95
I. Création de nouveaux types d'exception.................................................96
J. Clause throws......................................................................................96
K. Assertions..........................................................................................97

VIII - Entrées - Sorties 99


A. Catégories de flux et classes à connaître................................................99
1. Les 4 grandes catégories de flux abstraits............................................................99
2. Principaux flux « concrets ».............................................................................100
3. Conversions pour flux binaire...........................................................................101
4. Autres conversions de flux...............................................................................101

B. Fiches pratiques (exemples)...............................................................101


1. En pratique : écriture d'un fichier « texte »........................................................101
2. En pratique : lecture d'un fichier « texte » sans Scanner......................................103
3. En pratique : lecture d'un fichier « texte » avec Scanner......................................103
4. En pratique : écriture d'un fichier « binaire »......................................................105
5. En pratique : lecture d'un fichier « binaire ».......................................................106

C. Autres classes à connaître..................................................................107


1. Entrées-sorties en mode « random ».................................................................107
2. Manipulation de fichiers et répertoires...............................................................108

5
IX - Listes, piles, files, arbres 109
A. Problématique commune....................................................................109
B. Listes...............................................................................................110
1. Introduction...................................................................................................110
2. Fonctions de manipulation...............................................................................111
3. Implantation..................................................................................................112
4. Applications...................................................................................................113

C. Piles................................................................................................113
1. Introduction...................................................................................................113
2. Fonctions de manipulation...............................................................................114
3. Piles : implantation.........................................................................................114
4. Application.....................................................................................................115

D. Files................................................................................................116
1. Introduction...................................................................................................116
2. Fonctions de manipulation...............................................................................116
3. Implantation..................................................................................................117
4. Applications...................................................................................................117

E. Arbres..............................................................................................117
1. Introduction...................................................................................................117
2. Récursivité....................................................................................................117
3. Vocabulaire....................................................................................................118
4. Arbres binaires...............................................................................................118
5. Numérotation des nœuds.................................................................................118
6. Parcours........................................................................................................119
7. Exemple de parcours RGD en java....................................................................119
8. Fonctions de manipulation d'arbres binaires.......................................................119
9. Implantation..................................................................................................120
10. Applications.................................................................................................120

X - Paquetages, importation 123


A. Paquetage........................................................................................123
B. Paquetage et visibilité........................................................................123
C. Importation......................................................................................124
D. Nommage des paquetages.................................................................124
E. Organisation en fichiers, compilation et exécution..................................124
F. Paquetages standards de Java.............................................................125

XI - Compléments sur les classes 127


A. Niveaux de visibilité...........................................................................127
B. Classes ou interfaces internes.............................................................128
C. Classes locales et classes anonymes....................................................128
D. Héritage, classe racine, .....................................................................129
1. Notion de hiérarchie de classes.........................................................................129
2. Héritage........................................................................................................129
3. Héritage, attributs et méthodes........................................................................130
4. Héritage et visibilité........................................................................................130
5. Héritage et références.....................................................................................130
........................................................................................................................131
6. Héritage et constructeurs................................................................................131
........................................................................................................................131
7. Redéfinition, spécialisation, masquage...............................................................131
........................................................................................................................132
8. Polymorphisme dynamique..............................................................................132
9. Méthode abstraite...........................................................................................132
10. Classe abstraite............................................................................................133

6
11. Classe non dérivable.....................................................................................133
12. Méthode non redéfinissable............................................................................133
13. Héritage et tableau.......................................................................................134
14. la classe « Object ».......................................................................................134
15. Méthode clone()...........................................................................................136
16. Programmation « générique » via la classe Object.............................................136

E. Introspection....................................................................................137

XII - Interfaces 139


A. Interfaces.........................................................................................139
B. Exemple d'interfaces..........................................................................140
C. Autres exemples d'interfaces..............................................................140
D. Interfaces prédéfinies en Java............................................................141
E. Héritage entre interfaces....................................................................141
F. Implantation d'une interface par une classe..........................................141
G. Interface dans une déclaration d'attribut, variables, .............................141
H. Interfaces en paramètres de méthodes................................................142
I. Interfaces « marqueurs »....................................................................142
J. Interfaces Serializable, Externalizable et mot-clé transient......................143
K. Interfaces fonctionnelles....................................................................144
L. Passage d'une fonction/méthode en paramètre de méthode....................144
M. Méthodes par défaut.........................................................................146
N. Corps de méthodes statiques dans une interface...................................146
O. Comparaison interfaces / classes abstraites..........................................147

XIII - Collections (listes, ensembles, files, tables) 149


A. Introduction......................................................................................149
B. Deux versions : « paramétrée » ou pas................................................150
C. Les classes Collections et Arrays.........................................................151
D. Fiches pratiques et exemple d'utilisation..............................................151
1. Utilisation d'une liste.......................................................................................151
2. Parcours avec un Iterator................................................................................151
3. Exemple d'utilisation de la classe LinkedList.......................................................152
4. Définition d'une relation d'ordre / l'interface Comparable.....................................153
5. Définition d'ordres multiples / l'interface Comparator..........................................153

E. Principales interfaces et classes...........................................................154


1. L'interface Collection.......................................................................................154
2. L'interface Iterator..........................................................................................154
3. Les listes / interface List..................................................................................154
4. L'interface ListIterator.....................................................................................155
5. Les piles / classe Stack....................................................................................155
6. Les ensembles / interfaces Set et SortedSet.......................................................156
7. Les files d'attente / interface Queue..................................................................156
8. Implantations de l'interface Queue....................................................................157
9. Les tables d'association / interface Map.............................................................157
10. Table d'association triée / interface SortedMap.................................................157
11. Principales implantations de l'interface Map......................................................158
12. Collections et enum.......................................................................................158

7
XIV - Le paquetage java.lang 159
A. Le paquetage java.lang......................................................................159
B. La classe Math..................................................................................160
C. La classe StrictMath...........................................................................161
D. La classe System..............................................................................161
E. La classe Runtime..............................................................................162
F. La classe Process...............................................................................162
G. Les classes « enveloppes ».................................................................162
H. La classe Character...........................................................................163
I. La classe Number et ses classes filles...................................................163
J. La classe Enum..................................................................................164
K. La classe Class..................................................................................164
L. La classe Field...................................................................................165
M. La classe Method..............................................................................166
N. Interfaces pré-définies à connaître......................................................166

XV - Autres classes et interfaces à connaître 167


A. Le paquetage java.util.......................................................................167
B. Les classes Scanner et Pattern............................................................168
C. La classe Random..............................................................................170
D. La classe Objects..............................................................................171
E. Localisation et internationalisation.......................................................172

XVI - Documentation automatique (javadoc) 175

XVII - Annotations 177


A. Annotations......................................................................................177
B. Annotations standards (prédéfinies) en Java.........................................178
C. Définition d'annotations.....................................................................178
D. Le « checker framework »..................................................................179

XVIII - Graphisme et Interface Homme-Machine (IHM) 181


A. Introduction......................................................................................181
B. Composants prédéfinis d'AWT.............................................................182
C. Utilisation des conteneurs...................................................................184
D. Gestionnaires de présentation.............................................................184
E. Événements et programmation événementielle.....................................186
F. Dessiner...........................................................................................192
G. Couleurs..........................................................................................193
H. Polices de caractères.........................................................................194
I. Images.............................................................................................194

8
J. Dimensions de l'écran et des composants.............................................195
K. Applet vs application..........................................................................196
L. Ecrire une applet...............................................................................196
M. Ecrire une application graphique.........................................................201
N. Swing..............................................................................................203
O. Pour aller plus loin............................................................................205

XIX - Processus légers (threads) 207


A. Programmation multi-threadée...........................................................207
B. Thread.............................................................................................208
C. Classe Thread...................................................................................208
D. Création de threads...........................................................................208
E. Suspension / arrêt de thread..............................................................209
F. Exemple de thread.............................................................................209
G. Synchronisation des données..............................................................210
H. Synchronisation des exécutions..........................................................210
I. Blocages...........................................................................................211
J. Priorités des threads..........................................................................211
K. Groupement de threads.....................................................................212
L. Penser à utiliser la documentation.......................................................212

XX - Programmation réseau 215


A. Paquetage java.net............................................................................215
B. Accès aux protocoles Internet.............................................................215
C. Exemple d'utilisation de la classe URL..................................................216
D. Connexion réseau bas niveau.............................................................216
E. Exemple de Client..............................................................................217
F. Exemple de serveur...........................................................................217
G. Penser à utiliser la documentation.......................................................218

XXI - Annexe : ressources complémentaires sur Java 219

XXII - Annexe : ressources complémentaires sur


l'algorithmique 223

Index 225

9
Objectifs

Ce document est conçu pour servir de support de cours principal au tronc commun
d'Informatique.
Il couvre au plus près les aspects algorithmique et programmation de cet enseignement
(mais pas les aspects architecture des ordinateurs et systèmes d'exploitation pour lesquels
d'autres documents ont été distribués) en suivant autant que possible l'ordre des séances.
Il comporte un certain nombre de compléments et d'exemples qui ne seront pas
nécessairement détaillés lors des petites classes.
Il ne saurait toutefois remplacer un ouvrage de référence sur le langage Java, ou
sur l'algorithmique, et encore moins l'ensemble des documentations, cours et
bases d'exemples disponibles via le site web de l'Ecole.
NOTE : ce support de cours a pour origine un diaporama sur la programmation en Java,
écrit par Fabien Moutarde et Norbert Kajler. Il s'agit ici d'une version complétement
réécrite, avec le concours actif de Norbert Kajler et Jean-Michel Viovy, et la participation de
toute l'équipe du CCSI. Cette version utilise la chaîne éditoriale « Scénari ».

Nous vous remercions par avance de signaler toute erreur ou imprécision aux
auteurs.

11
Pourquoi Java ?

Java a été choisi par l'équipe enseignante en tant que compromis entre :
 langage puissant, incluant un maximum de paradigmes de programmation
pertinents à enseigner car généralement non maîtrisés par la plupart des élèves
admis en 1° année (typage fort, références, programmation objet, exceptions,
événements et programmation réactive, threads, ...) ;
 langage pouvant constituer un 2° langage idéal pour des élèves qui connaissent déjà
soit un langage moins riche et/ou moins général que Java (Maple, Mathematica,
Pascal, Basic, JavaScript, PHP, ...) soit un langage essentiellement fonctionnel
(CAML, Lisp, ...) de nature très différente ;
 langage relativement facile à maîtriser sans avoir suivi au préalable un
enseignement d'Informatique avancé ;
 langage non-spécialisé, permettant l'écriture de programmes de toutes sortes,
de toutes tailles, et dans tous les domaines ;
 langage largement utilisé dans l'industrie du logiciel 1 ;
 langage mature et très bien documenté (existence de nombreux cours, FAQs,
bases d'exemples couvrant tous les aspects du langage) en anglais français, et bien
d'autres langues si besoin ;
 langage disponible gratuitement sur l'ensemble des matériels, et doté d'une
vaste bibliothèque de classes et de nombreux outils de développement
également gratuits.
Java n'est certes pas optimal sur l'ensemble de ces critères ; il constitue néanmoins – du
point de vue de l'équipe enseignante – le meilleur compromis disponible étant donné
l'objectif de cours et les connaissances préalables des élèves.
Par ailleurs, l'équipe enseignante considère que la maîtrise d'un langage de programmation
donné importe moins que la maîtrise des notions sous-jacentes même si, dans le cas
particulier de Java, l'expérience acquise peut être directement valorisée (stages, junior
entreprise, ...) étant donné le nombre de projets informatiques réalisés à l'aide de ce
langage (y compris le développement d'applications Android).
Ainsi, apprendre à programmer en Java est avant tout un moyen d'étudier, et pratiquer, un
certain nombre de principes et styles de programmation essentiels (et que l'on retrouve
dans beaucoup d'autres langages).
Ce faisant, l'apprentissage de java constitue une étape dans l'étude de l'Informatique en
général, et en particulier dans la capacité à écrire des programmes non-triviaux dans un
langage fortement typé.
A l'issue de cet enseignement, il devrait être assez facile aux élèves qui en auraient besoin
d'apprendre à programmer dans n'importe lequel des autres langages très répandus
aujourd'hui (C, C++, C#, Python ...) ou qui émergent depuis quelques années (Scala,
Ruby, ...).

1 - Java est en 1° ou 2° place dans les différents classements sur l'utilisation des langages de programmation
(TIOBE, Transparent Language Popularity Index, PYPL, RedMonk Programming Language Rankings, ...)

13
14
I- Introduction

Les langages de programmation 15


Origine et historique de Java 18
Java aujourd'hui 18
Caractéristiques techniques de Java 19
Qualités et défauts de Java 20
JRE, Java SE, JDK, Eclipse, ... 21
Les différentes « éditions » du langage Java 22
Langages et technologies connexes 22

A. Les langages de programmation


Niveaux et catégories des langages de programmation :
 langage binaire
 assembleur : instructions de base du processeur (transferts entre registres,
addition, ...)
 langages « impératifs » : Cobol, Fortran, Basic, Pascal, C, Ada, PHP, ...
 langages de « programmation logique » : Prolog, Mercury, ...
 langages « fonctionnels » : Lisp, Scheme, Clojure, ML/CAML, Haskell,
Erlang, ...
 langages « orientés objets » : SmallTalk, Objective C, C++, Java, C#, Scala,
...

Définition
 Langage binaire : langage natif de l'ordinateur, spécifique à un type
d'ordinateur ; programmes constitués d'une suite de zéros et de uns,
directement exécutables par l'ordinateur mais incompréhensibles ou presque
par un être humain.
 Assembleur : langage de « bas niveau » spécifique à un processeur et très
proche du langage de l'ordinateur, donc difficile à comprendre pour un être
humain mais trivial à transcrire en langage binaire (en assembleur chaque
instruction du langage correspond à une instruction élémentaire du processeur,
par exemple : affecter une valeur à une case mémoire, comparer deux valeurs,
poursuivre l'exécution à une adresse mémoire donnée, ...)
 Langage de « haut niveau » : par opposition au langage binaire et à
l'assembleur, langage relativement lisible pour un être humain et nécessitant

15
un gros travail de transcription en langage binaire ; les langages de « haut
niveau » se déclinent en plusieurs catégories ─ pas forcément exclusives les
unes des autres ─ selon le style de programmation qu'ils préconisent :
- style impératif : le programme correspond à une suite d'instructions
totalement explicitées et regroupées en modules/procédures/instructions.
- style logique : un programme correspond à une suite de « faits » et de
« règles » à partir desquels sera créée automatiquement la séquence
d'instructions exécutée par l'ordinateur ; dans un langage de
« programmation logique » tel que Prolog le code décrit ce qui doit être fait
en termes abstraits, sans se préoccuper du comment cela sera fait (ce qui
limite en pratique les domaines d'applications et engendre des problèmes
de performances) ; en cela les langages de « programmation logique » sont
à l'opposé des langages impératifs.
- style fonctionnel : les programmes sont des fonctions au sens
mathématique – fonctions « d'ordre supérieur »2 y compris, ce qui fait qu'il
n'existe pas de distinction fondamentale entre programmes et données en
programmation fonctionnelle (un programme dans un langage fonctionnel
tel que Lisp, ML/CAML, Haskell, etc. peut typiquement en cours de
traitement produire un autre programme qui crée un troisième programme
qui s'applique à des données dont la nature est elle-même un programme).
- style orienté objets : repose sur un certain nombre d'abstractions
positionnées au cœur du langage – encapsulation, classes, instances,
attributs, méthodes, héritage, ... (voir plus loin) ; la plupart des langages
orientés objets sont des langages essentiellement impératifs (C++, Java)
avec des aspects fonctionnels plus ou moins prononcés.

Complément : Langages de programmation et architectures


matérielles
De nos jours, la quasi totalité des ordinateurs (et smartphones) ont une architecture
matérielle (processeur) conçue :
1. pour privilégier la programmation impérative en termes d'efficacité (sans
interdire pour autant les autres styles de programmation) ;
2. pour être programmée dans n'importe quel langage (sous réserve qu'il puisse
être traduit ou interprété dans le langage binaire du processeur).
Il est toutefois possible de créer des ordinateurs privilégiant le style fonctionnel (e.g.
les machines Lisp conçues dans les années 70s et commercialisées dans les années
80s mais disparues depuis) ou logique (quelques variantes d'architectures matérielles
optimisées pour Prolog dans les années 80-90s).
Il est également possible de concevoir des processeurs pour un langage de
programmation précis – les auteurs de Java ont d'ailleurs un temps travaillé sur un
processeur optimisé pour l'exécution de bytecode Java avant d'y renoncer – mais,
depuis la fin des années 90s, l'envie d'optimiser les performances d'un langage de
programmation par la création d'une architecture matérielle spécifique (processeur
dédié compris) se heurte à un obstacle majeur d'ordre strictement économique : les
coûts de développement des processeurs sont tellement élevés que seules une ou
deux architectures polyvalentes par génération se révèlent commercialement viables
(présentement : Intel et ARM).
Désormais, la puissance atteinte par les processeurs couplée avec les progrès
accomplis dans l'optimisation des compilateurs rendent, de fait, peu pertinent le
développement de processeurs dédiés à un langage donné. Toutefois, une des

2 - On appelle fonction d'ordre supérieur une fonction prenant d'autres fonctions en paramètres. Par exemple,
le calcul formel de la dérivée étant données une fonction et une variable est une fonction d'ordre supérieur.
Autre exemple : une fonction qui prend en paramètres deux fonctions f et g et une liste l et qui applique la
fonction f à tous les éléments de la liste dont l'image par g est vraie.

16
Introduction

particularités des processeurs ARM (très utilisés dans les smartphones, tablettes, ...)
est leur formidable flexibilité, à tel point que certaines versions disposent de mode(s)
permettant d'exécuter du bytecode Java plus efficacement3.

Principaux langages « généralistes » :

Complément
Le diagramme ci-dessus présente quelques uns des langages de programmation
« généralistes » (permettant d'écrire une grande variété de programmes dans de
nombreux domaines) qui ont été développés depuis l'apparition des premiers
ordinateurs. Y sont ainsi visibles, les langages généralistes ayant été les plus utilisés
au fil des ans et/ou ayant le plus influencé les langages utilisés aujourd'hui.
Outre les langages généralistes, il existe des milliers de langages de programmation
plus ou moins spécialisés, autrement dit, des langages qui ont été développés pour
écrire des programmes dans des domaines spécifiques (e.g. VHDL 4 pour la conception
de circuits électroniques), ou pour fonctionner exclusivement à l'intérieur d'un logiciel
donné (e.g. ceux utilisés dans Maple ou Mathematica).
La frontière entre langages généralistes et spécialisés est toutefois floue et poreuse :
historiquement, de nombreux langages ont été initialement développés pour satisfaire
un besoin spécifique avant d'être utilisés plus largement. C'est le cas de C (conçu
pour créer Unix), de Python, et de Java comme on le verra plus loin. Inversement des
langages comme C++, C# ou Scala ont, d'emblée, été conçus pour être des langages
généralistes.
De même, la frontière entre langages impératifs / fonctionnels / orientés objets n'est
3 - Le mode Jazelle DBX permet, au moins théoriquement, l'exécution directe du bytecode sur les processeurs
ARM sans l'intermédiaire d'une machine virtuelle. En pratique, tout dépend de l'implantation du mode Jazelle
DBX sachant qu'il existe des dizaines de fournisseurs de processeurs ARM. Au pire le code reste entièrement
exécuté dans une machine virtuelle ; au mieux, seule une partie du bytecode est véritablement exécutée
directement sur le processeur, les instructions les plus complexes et/ou les moins courantes étant toujours
interprétées dans une machine virtuelle. Une variante à Jazelle DBX est par ailleurs incluse dans les
processeurs ARM depuis 2005 : ThumbEE, conçu comme le mode d'exécution privilégié pour l'exécution des
programmes écrits en Java, C#, Phython, Perl, etc. Dans ce mode, le processeur exécute un jeu d'instructions
réduit optimisé pour être très proche de tous ces langages à la fois. L'usage de ThumbEE n'est cependant plus
recommandé par ARM sur les dernières générations de ses processeurs, même si il reste disponible pour des
raisons de compatibilité avec les anciens processeurs.
4 - VHSIC (Very High Speed Integrated Circuit) Hardware Description Language.

17
pas figée : la plupart des langages évoluent au fil des années, et dans certains cas
changent de catégorie, en ajoutant une couche objet par exemple (e.g. Pyhthon, PHP
et bien d'autres) ou des aspects fonctionnels (Java 8). D'autres langages sont conçus
pour être précisément à la frontière de différents styles comme Scala ou F# qui
tentent de concilier au mieux les styles impératifs, objets et fonctionnels.
Par ailleurs il existe de nombreux « langages informatiques » qui ne sont pas des
langages de programmation : par exemple XML (Extensible Markup Language) est un
langage conçu pour représenter/archiver/manipuler des données structurées, il ne
permet pas l'écriture de « programmes ».

B. Origine et historique de Java


Initialement (1991) « Oak » était un projet de langage pour l'électronique grand
public développé au sein de la société Sun (rachetée depuis par Oracle)
Principal concepteur : James Gosling
Transformé en langage pour le Web ─ sous le nom de « Java » ─ grâce à sa
portabilité (1994/95)
Lancement officiel en mai 1995

Complément : Historique des versions du langage


1996 : Java 1.0
1997 : Java 1.1
 nombreuses optimisations, modification du modèle des événements pour
AWT, ... ~400 classes prédéfinies
1998 : Java 1.2 (renommé Java2 ou J2SE 1.2)
 ajouts : collections, Swing, Java2D, ... ~1200 classes prédéfinies
2000 : Java 1.3 (J2SE 1.3)
2002 : Java 1.4 (J2SE 1.4)
2004 : Java 1.5 (J2SE 1.5)
 ajouts : généricité (proche des templates de C++), types énumérés, web
services, ... ~2500 classes prédéfinies
2006 : Java 1.6 (ou « Mustang » ou Java SE 6)
 améliorations des performances (Swing notamment)
 ajouts : interactions avec scripts (PHP, Python, Ruby, JavaScript), ...
2011 : Java 1.7 (ou « Dolphin » ou Java SE 7)
 améliorations de la généricité et des instructions switch, catch, ...
 ajouts : NIO (new I/O), try-with, ... ~3000 classes prédéfinies
2014 : Java 1.8 (ou « Wolf » ou Java SE 8)
 améliorations de la gestion du temps et des durées (classes Instant,
Duration, ...)
 ajouts : lambda expressions, streams, ... ~4000 classes prédéfinies
~2016 : Java 1.9

C. Java aujourd'hui
Langage de programmation parmi les plus utilisés aujourd'hui :
 plus de 10 millions de développeurs Java
 nombreux outils de développement
 plusieurs milliards d'objets avec une « machine virtuelle Java », dont :

18
Introduction

- 5 milliards de cartes à puce (y compris cartes SIM)


- 3 milliards de téléphones portables
- 100% des lecteurs de disque « Blu-ray »
- 90% des PCs d'entreprise

D. Caractéristiques techniques de Java


Un langage orienté-objet :
 robuste (typage fort, pas de pointeurs, garbage collector)
 modulaire (packages)
 intégrant le multi-threading
 compilable en bytecode pouvant être interprété (ou exécuté à volée) au sein
d'une machine virtuelle Java (JVM)
maximise la portabilité

Complément : Java et C / C++


Java est proche du langage C++. Historiquement, sa syntaxe de base a été
volontairement calquée sur celle de C / C++ afin de faciliter la transition pour les
millions de programmeurs qui connaissent déjà ces deux langages.
Principales simplifications de Java (par rapport à C++) :
 pas de manipulations de pointeurs sous forme d'adresse mémoire ;
 gestion mémoire automatique (garbage collector) ;
 pas de surcharge des opérateurs ;
 pas d'héritage multiple 5 ;
 pas de préprocesseur.
Principaux ajouts (par rapport à C++) :
 tableaux avec test de dépassement de bornes vérifié à l'exécution ;
 chaînes de caractères sous forme de classe ;
 notion d'interface ;
 classe racine ;
 introspection ;
 structuration en paquetages ;
 aspects fonctionnels (depuis Java 1.8) ;
 multi-threading incorporé au langage ;
 vaste bibliothèque de classes.

Complément : Java et JavaScript


Le langage JavaScript n'a rien ou presque à voir avec Java au plan technique : il s'agit
d'un langage faiblement typé, beaucoup moins riche que Java en termes de
paradigmes de programmation et de bibliothèque de classes.
Concernant les usages il y a quelques points communs : l'utilisation à l'intérieur de
navigateurs web et de serveurs, mais pour JavaScript c'est quasiment sa seule
utilisation alors que pour Java c'est une utilisation parmi bien d'autres.
JavaScript est maintenu par la fondation Mozilla ; il fait partie, comme Java, des
langages informatiques les plus répandus ; il est en particulier une brique essentielle

5 - Du moins pas au sens de C++ qui permet l'héritage multiple des attributs et des méthodes : en Java seuls
les méthodes peuvent dans une certaines mesure faire l'objet d'un héritage multiple via le mécanisme des
méthodes « par défaut ».

19
de la technologie AJAX (asynchronous JavaScript and XML) utilisée pour la création de
pages web dynamiques dans lesquelles il y a des échanges fréquents et automatiques
entre le navigateur et le serveur (par exemple pour la mise à jour d'une carte).
JavaScript et Java sont en fait complémentaires : certains codes très spécifiques
s'écrivent plus aisément avec JavaScript (pour la gestion de formulaires dans des
pages web par exemple) alors que Java est utilisé beaucoup plus largement pour
exécuter des programmes complexes à l'intérieur de pages web ou de serveurs, et
pour développer des programmes autonomes de grande taille comme Eclipse.
Cette complémentarité est telle qu'il existe plusieurs briques technologiques pour
faciliter l'utilisation conjointe des deux langages dont le moteur JavaScript
« Nahshorn » (fournit avec Java depuis la version 8) et qui permet l'exécution de code
Javascript au sein de la machine virtuelle Java (la JVM) et également l'invocation de
code Java depuis Javascript (et réciproquement).

E. Qualités et défauts de Java


Principales qualités
 Programmes portables
 Programmes fiables (rigueur du langage => peu de bogues)
 Formidable bibliothèque de classes (4000+ classes disponibles en standard)
 Développement rapide
 Multiples possibilités de déploiement (applet, web start, ...)
 Langage très répandu grande disponibilité de compétences, documentation,
outils, ...
 Capacité prouvée à permettre la réalisation de très gros programmes (e.g.
Eclipse = 58 millions de lignes de code !)

Principaux défauts
 Vitesse d'exécution des codes inférieure à C/C++ (dépend des codes)
 Réputation de sécurité ternie à plusieurs reprises par des bugs dans les
implantations de référence
 Syntaxe relativement verbeuse
 Système de type non entièrement unifié (types élémentaires / tableaux /
classes)
 Poids du passé encombrement cognitif (beaucoup de classes a « superflues »
maintenues pour garantir la compatibilité ascendante des codes Java)
 Langage difficile pour des programmeurs occasionnels
 Inversement, langage possiblement trop banal/mature pour des programmeurs
expérimentés

Complément
 Une étude de 2012 sur un ensemble de codes de référence met en évidence
une vitesse d'exécution des codes Java (J2SE 1.7) inférieure de 44% comparé
au langage C++. Il s'agit d'une différence importante dans l'absolu mais, en
pratique, rares sont les applications pour lesquelles un tel gain de vitesse
justifie à lui seul le choix d'un langage de programmation : les critères
essentiels sont bien plutôt la rapidité et le coût de développement des
programmes, la fiabilité, la portabilité, ...
 Concernant la verbosité, c'est un point à relativiser : la verbosité de java
découle en grande partie d'un choix de conception délibéré lié d'une part au

20
Introduction

typage fort et d'autre part à la volonté de faire prendre conscience de certains


choix au programmeur. Par ailleurs, l'étendue de la bibliothèque de classes
permet, dans certains cas, d'écrire en quelques lignes ce qui prendrait plusieurs
pages en C ou C++. Un programmeur averti peut néanmoins préférer un
langage moins verbeux.
 Parmi les points qui peuvent manquer à des programmeurs expérimentés en
Java il y a :
a. des mécanismes volontairement absents du langages alors qu'il sont
présents dans beaucoup de langages de la même génération (pointeurs,
héritage multiple, surcharge des opérateurs, ...) ;
b. des paradigmes disponibles uniquement dans des langages plus récents que
Java (évaluation paresseuse, schémas de conceptions intégrés au langage,
etc).
Il s'agit là aussi de points à relativiser : peu de programmeurs sont
véritablement limités par des manques dans le langage Java. En outre,
certaines innovations qu'on retrouve dans des langages plus récents tels que
Ruby on rail, Scala, ... apportent certes puissance et légèreté mais sont parfois
difficiles à maîtriser sans un bon niveau technique et un minimum d'expérience
dans le développement logiciel. Enfin, Java évolue régulièrement (ajout de la
généricité en 2004, ajout des lambda expressions et des Streams en 2014, ...)
ce qui réduit l'attrait des langages les plus récents. Toutefois, la volonté des
concepteurs du langage de garantir une (quasi)-parfaite compatibilité
ascendante6 lorsque de nouveaux concepts sont ajoutés tend à alourdir le
langage au plan syntaxique. Au fil du temps, ce pourrait d'ailleurs être un
avantage décisif pour les langages plus récents que Java : à force d'ajouter des
éléments au langage sans remettre en cause la syntaxe d'ensemble, Java
devient progressivement moins agréable à utiliser que ses alternatives les plus
récentes.

F. JRE, Java SE, JDK, Eclipse, ...


Plusieurs implantations de Java sont disponibles, dont celle d'origine ORACLE/SUN
(créateur du langage) et quelques autres
Pour exécuter du code Java : le « JRE » (Java Runtime Environment) d'ORACLE/SUN
suffit (gratuit et largement disponible)
Pour créer du code java, plusieurs possibilités (au choix) :
 le « Java SE » (Standard Edition) dénommé aussi « JDK » (Java Development
Kit) d'ORACLE/SUN (gratuit) contient :compilateur (javac), interpréteur /
machine virtuelle (java), divers outils génération doc (javadoc), debugger
(jdb), ...
 la plateforme de développement « Eclipse » (gratuite, la plus utilisée)
 la plateforme de développement « NetBeans » (gratuite, développée par
Oracle)
 ou l'une des nombreuses autres plateformes de développement permettant de
dévlopper du code Java...

6 - En Java, « compatibilité ascendante » veut dire qu'un programme compilé avec une version antérieure du
langage continuera à fonctionner de la même manière sur une machine virtuelle plus récente, sans nécessiter
de re-compilation ou de modification du code source (à de rares exceptions près). Autrement dit, un code
développé pour Java 1.6 pourra fonctionner sur un ordinateur doté d'un environnement d'exécution (JRE)
plus récent tel que Java 1.8. L'inverse est faux : un code Java récent ne fonctionnera pas forcément sur un
environnement d'exécution plus ancien.
Attention : la « compatibilité ascendante » concerne les programmes écrits en langage Java ; si on considère
les outils (compilateur et machine virtuelle Java) on doit alors parler de « compatibilité descendante » ou
« rétro-compatibilité » (une JVM 1.6 pourra exécuter tout code écrit en Java 1.6 ou avec des versions plus
anciennes, mais pas forcément des codes plus récents).

21
Complément : OpenJDK, licences, ...
 OpenJDK est une version de Java dont la totalité des composants est
strictement dans le domaine public (sources de toutes les classes, de la
machine virtuelle, du compilateur,...)
 OpenJDK est distribué sous licence GNU
 OpenJDK est une initiative soutenue par une grande partie de l'industrie
informatique (Oracle, IBM, Apple, SAP, ...)
 La version standard distribuée gratuitement par Oracle (JRE, Java SE, ...)
utilise les mêmes codes sources qu'OpenJDK mais y ajoute des composants qui
ne sont pas dans le domaine public ; le résultat est distribué sous une licence
spécifique (Binary Code License)

G. Les différentes « éditions » du langage Java


Plusieurs « éditions » (ou « distributions ») du langage co-existent :
1. Java Standard Edition (J2SE ou Java SE)
2. Java Enterprise Edition (J2EE ou Java EE) applications réparties
(e.g. services web)
3. Java Micro Edition (J2ME ou Java ME) applications embarquées (e.g.
smartphones, TVs, ...)
4. Java Card applications embarquées sur cartes à puce (smartcards)

Remarque : Différences au sein du langage Java selon les


éditions
Chaque édition :
 inclut un ensemble déterminé de packages plus ou moins conséquent ;
 utilise une « machine virtuelle » possiblement différente.
Le langage est donc sensiblement différent selon l'édition utilisée même si les bases
restent strictement les mêmes (syntaxe, structures de données, classes de base).

H. Langages et technologies connexes


Il existe de nombreux langages et technologies connexes dans l'écosystème Java :
 GWT (Google) pour la création de pages web dynamiques de type
googlemaps
 Xtend (Eclipse.org) variante de Java avec une syntaxe allégée ; se compile
en code source Java
 ...
Aussi, la machine virtuelle Java est fréquemment utilisée pour exécuter des
programmes écrits dans d'autres langages après compilation en bytecode :
JavaScript, Scala, Groovy, Clojure, Jython, JRuby, ...

Remarque : Avantages pour d'autres langages d'utiliser la


machine virtuelle Java
Au moins trois avantages majeurs pour qui souhaite développer un nouveau langage :
1. pouvoir exécuter le code sur les milliards de machines physiques (PCs,
téléphones, cartes de crédits, ...) déjà équipés d'une machine virtuelle Java ;
2. aboutir plus rapidement à une première version utilisable du langage : pas

22
Introduction

besoin de développer sa propre machine virtuelle, ni de multiplier les


compilateurs « natifs », il suffit d'écrire un compilateur qui produit du bytecode
Java) ;
3. disposer d'un accès aux 4000+ classes de la bibliothèque Java via leur
bytecode.

Complément : Java et Android


L'essentiel d'Android (Google) est écrit en C/C++ (le cœur du système est une
variante d'Unix/Linux) ; Java y est utilisé pour la création des « applications ».
Le code java compilé en bytecode (fichiers .class) est converti en fichiers .dex (pour
Dalvik executable) afin de pouvoir fonctionner sur la machine virtuelle Dalvik qui est
une JVM optimisée pour fonctionner sur des téléphones portables, tablettes, ...

Attention
Ce cours correspond à l'édition standard de Java (Java SE) et ne couvre pas
les spécificités des autres éditions, ni les langages connexes à Java.

23
II - Syntaxe de base

II
Premiers exemples 25
Variables, types, portée, commentaires, … 26
Opérateurs 31
Blocs, instructions de contrôle (tests, boucles, …) 36
Entrées-sorties 42
Exemple de programme, compilation, exécution 45

A. Premiers exemples

Remarque : mots-clés
Dans l'exemple ci-dessus, int, for, class, public, static et void sont des mot-
clés. Par mot-clé il faut comprendre un mot réservé par les concepteurs du langage,
et qu'il est donc impossible d'utiliser dans un programme pour nommer une variable,
une fonction, ...
Java comporte une cinquantaine de tels mots-clés qui seront présentés au fil du
cours.

25
B. Variables, types, portée, commentaires, …
1. Variables et types

Définition : Notion de variable


nom (identificateur) + type + zone mémoire

Deux grandes familles de types en Java :


1. les types « primitifs » (entiers, flottants, ...)
2. les types « composites » qui se manipulent par l'intermédiaire de
références :
- tableaux
- énumérations
- objets
- interfaces

Remarque
Contrairement à certains langages moins fortement typés (Python, Maple, ...), Java
ne cherche quasiment jamais à « inférer » (deviner) le type des variables : en Java, il
faut déclarer le type de chaque nouvelle variable. Cela alourdit l'écriture du code mais
permet de gagner en fiabilité (le compilateur interdit les manipulations risquées, le
programmeur est obligé d'expliciter ses choix).
Par ailleurs, le type d'une variable en Java est fixé une fois pour toute (i.e. il ne peut
changer au fur et à mesure des affectations...)

2. Types « primitifs »

 boolean

 char (16-bit, Unicode)

 byte : entier (signé) 8-bit


 short : entier (signé) 16-bit
 int : entier (signé) 32-bit
 long : entier (signé) 64-bit

 float : flottant (IEEE 754) 32-bit


 double : flottant (IEEE 754) 64-bit

Remarque
Le typage est particulièrement strict en Java (comparé à C ou C++ par exemple),
ainsi :
 les conversions automatiques sont peu nombreuses (et seulement vers des
types « plus larges », par exemple du type int vers le type long)
 les conversions manuelles sont restreintes (il est, par exemple, interdit de
convertir un booléen en entier)

26
Syntaxe de base

3. Le type booléen
Valeurs possibles : true ou false
Véritable type
Type retourné par les opérateurs de comparaison
Type attendu dans tous les tests
Ne peut pas être converti en entier

Remarque
Contrairement à d'autres langages, le type booléen est un type à part entière en
Java. En particulier, il n'y a pas de correspondance entre faux et 0 comme c'était le
cas historiquement en C/C++ (non-ISO).

4. Le type caractère
16-bit 65536 valeurs : quasiment tous les caractères de toutes les écritures (mais
affichables uniquement si le système possède les polices de caractères adéquates !)
Littéraux entre simples quotes : 'a' 'Z' ...
Caractères spéciaux : '\n' '\t' '\b' '\\' '"' ...
Possibilité d'utiliser la valeur Unicode : '\u03c0'7
Convertibles automatiquement en int ou long (et manuellement en byte ou short)
Inversement, (char)val est le caractère dont le code Unicode est l'entier val
Possibilité de tester la nature du caractère :
Character.isLetter(c), Character.isDigit(c), ...
où c est une variable de type char

NOTA-BENE : nombreuses fonctions utilitaires dans la classe Character, voir plus loin
(cf. La classe Character p 163) et dans la documentation en-ligne de Java

Attention
 Ne pas confondre 'a' et "a" ('a' est un char, i.e. UN SEUL caractère, "a"est
une chaîne de caractères de longueur 1)
 \ suivi directement d'un nombre indique un char donné par son code en octal
(base 8)
ex. : `\43' est le char de code 4x8+3=35 (et pas le caractère de code 43)

Complément : Distance entre caractères


L'opérateur - est disponible sur les caractères pour connaître la distance entre deux
caractères.
Ainsi 'c' - 'a' vaut 2.

7 - Cette valeur Unicode correspond à π (la lettre grecque PI en majuscule).

27
5. Les types entiers
Littéraux de type entier :
 en base dix : 139
 en octal : 0213
 en hexadécimal : 0x8b
 en binaire : 0b100101

Usage possible du caractère _ (augmente la lisibilité) : 17_500_000

L ou l pour spécifier un entier « long » :: 139L

Valeurs min/max ::
 byte = [-128; +127]
 short = [-32768 ; +32767]
 int = [-2.147.483.648 ; +2.147.483.647]
 long = [-9.223.372.036.854.775.808 ; +9.223.372.036.854.775.807]

Conversion automatique seulement vers les types entiers plus grands (int long,
etc...) et vers les types flottants

Remarque
Contrairement à d'autres langages (C, C++, ...), il n'existe pas de variantes « non-
signées » de ces types en Java (et donc pas de mot-clé unsigned).

Complément : Encodage des entiers en mémoire


Le bit de gauche = le signe ; les autres bits = la valeur en binaire en « complément à
deux », i.e. ~|x|+1, pour les <0.
Exemple :
 5 en binaire sur 7bits : 0000101 et donc sous forme de byte (8 bits) avec bit
de signe (0) en tête 00000101
 -5 avec bit de signe (1) en tête : 11111011 (les 7 bits en complément à 2 :
1111010+1 = 1111011)

6. Les types flottants


Notation « ingénieur » : 2.45e-25
Littéraux de type double par défaut:

float x = 2.5; // Erreur


double y = 2.5; // OK
float z = 2.5f; // OK (f ou F pour spécifier un float)

Valeurs min/max (en valeur absolue, hors 0) :


float [ 1.40239846e-45 ; 3.40282347e+38 ]
double [ 4.9406...e-324 ; 1.7976...e+308 ]

28
Syntaxe de base

Valeurs spéciales : Infinity, -Infinity, NaN

Conversion automatique : seulement de float double

ATTENTION, la conversion « manuelle » en entier tronque la partie décimale :


double d = -2.8;
int i = (int) d; // ici, i vaut -2

Complément : Encodage des nombres flottants en mémoire


 La représentation en mémoire suit strictement la norme IEEE-754
 Il existe des valeurs « spéciales » représentant +infini, -infini, et 0/0
(NaN=NotANumber)
 Principe : où est la « mantisse » sous forme d'un nombre dans [0 ; 1] écrit en
base 2 ()
 Pour les float, il y a : 1 bit de signe puis 8 bits pour l'exposant puis 23 bits pour
la mantisse
 Pour les double, il y a : 1 bit de signe puis 11 bits pour l'exposant puis 52 bits
pour la mantisse

7. Constantes
Variable dont la valeur ne peut plus être changée une fois fixée
Se déclare avec le mot-clé final :
final double PI = 3.14159;

. . . ce qui interdit d'écrire ensuite :

PI = 3.14; // ERREUR...

Possibilité de calculer la valeur de la constante non pas lors de sa déclaration mais


plus tard, à l'exécution :
final int MAX_VAL;
// OK : constante « blanche »
// ...
MAX_VAL = lireLaValeur();
// ...
MAX_VAL = 1000; // ERREUR...

Complément : le mot-clé const


En Java, const (à ne pas confondre avec final) est un mot-clé au sens où on ne peut
pas l'utiliser librement pour nommer une variable ; cependant il n'est pas utilisé par le
langage, au moins dans sa version actuelle. C'est d'ailleurs avec goto le seul mot
ainsi « réservé » par le langage sans être effectivement utilisé.

29
8. Déclaration et portée des variables
Déclaration préalable obligatoire

Identificateurs :
- caractères Unicode
- commencent par une lettre, _ ou $
- ensuite : lettre, chiffre, _ ou $

Exemples :

int i;
double x, y, z;
char c = 'A', d;
boolean flag = true;

ATTENTION, initialisation obligatoire avant usage :


int i, j;
j = i; // ERREUR : i non initialisé

« Portée » (ou « scope ») des variables (= zone de validité de la déclaration) :


jusqu'à la fin du bloc englobant (voir plus loin)

9. Conventions de nommage
1. Identificateurs toujours en minuscules, sauf :
- majuscule au début des « sous-mots » intérieurs :
unNomDeVariableOuDeFonctionOrdinaire
- début des noms en majuscule pour classes et interfaces (et elles seules) :
UnNomDeClasse
2. Pour les constantes : tout en majuscules et séparation des mots par _
UNE_CONSTANTE
3. Pour les classes et interfaces : éviter tous les noms déjà utilisés dans le JDK
(ex. String, System, ...)
4. Pas d'emploi du caractère $ (ni de caractères non ASCII8)

Remarque
Ces conventions de nommage édictées par les auteurs du langage ne sont pas
strictement obligatoires pour faire fonctionner un programme ; elles sont néanmoins
fortement recommandées dans la mesure où elles facilitent grandement la
lisibilité du code et sa maintenance). Elle sont de fait très largement respectées.

8 - ASCII = American Standard Code for Information Interchange. La norme ASCII date de 1963, c'est
l'ancêtre de tous les systèmes d'encodage de caractères en informatique ; les caractères y sont codés sur un
octet ce qui limite leur nombre à 256. ASCII a été conçu pour la langue anglaise dont il couvre tous les
caractères et symboles usuels. Pour des raisons de compatibilité ascendante, les normes plus récentes qui
couvrent davantage de langues sont généralement calquées sur l'ASCII pour ce qui concerne les caractères
couverts par cette norme (lettres latines sans accents, chiffres, ponctuation courante...) . En particulier, sous
Unicode, le standard ASCII est intégré sous le label « Basic Latin » (ou C0 Controls and Basic Latin).

30
Syntaxe de base

10. Commentaires
Plusieurs sortes de commentaires en Java :

a/ commentaires techniques sur une ligne :

// commentaire -> fin de la ligne


int x; // autre commentaire

b/ commentaires techniques sur plusieurs lignes :

/* commentaire qui s'étend comme ici


sur plusieurs lignes */

c/ commentaires destinés à la documentation automatique (javadoc) :

/** commentaire pour javadoc */

NOTA-BENE : javadoc = outil qui analyse le code Java, et produit automatiquement


une documentation HTML avec la liste des classes, attributs, méthodes... (en y
intégrant, le cas échéant, les « commentaires de documentation »)

Remarque : javadoc

 Les commentaires « javadoc » se placent juste avant l'entité (classe, attribut,


méthode) à laquelle ils se rapportent
 Voir la section sur javadoc (cf. Documentation automatique (javadoc) p 175)
pour plus de détails.

C. Opérateurs
1. Principaux opérateurs
 affectation : =
 arithmétique : + - * / %
 comparaison : < <= > >= == !=
 booléen : && || ! ^ & |
 opération bit-à-bit (sur les entiers) : & | ^ ~ << >> >>>
 opération et affectation simultanées : += -= *= /= %= &= |= ^=
<<= >>= >>>=
 pré/post-incrémentation : ++
 pré/post-décrémentation : --
 opérateur ternaire : ?:
 création tableau ou objet (allocation mémoire) : new

31
2. Opérateurs arithmétiques

Opérateur Fonction Usage


+ addition expr1 + expr2
- soustraction expr1 - expr2
- changement de signe - expr2

* multiplication expr1 * expr2


/ division expr1 / expr2

% modulo expr1 % expr2

Attention
 L'arithmétique entière est « circulaire » : elle produit des résultats
mathématiquement faux en cas de dépassement, mais pas d'erreur au sens
informatique, sauf lors d'une division par zéro.
 L'arithmétique décimale (en virgule flottante) produit des erreurs d'arrondis
mais n'est pas circulaire : elle produit des valeurs de type infini en cas de
dépassement.
 En cas de division par zéro, l'arithmétique entière produit une erreur
informatique (ArithmeticException) tandis que l'arithmétique décimale
retourne la valeur spéciale NaN (NotANumber).
 Les divisions entre entiers produisent le quotient 9 (pas de passage automatique
à l'arithmétique décimale).

Conséquence : le comportement de l'opérateur / diffère totalement selon la nature


des opérandes :
 / entre deux entiers quotient (donc 5/2 vaut 2 alors que 5.0/2 vaut 2.5)
 1/0 « ArithmeticException » (division par zéro prohibée entre entiers)
alors que 1.0/0 retourne la valeur Infinity (et 0.0/0 produit la valeur NaN)

Les constantes et fonctions mathématiques usuelles sont dans la classe Math (cf. La
classe Math p 160) :
 Math.E
 Math.PI
 Math.pow(x,y)
 Math.sin(x)
 Math.log(x)
 …

9 - En java, étant donnés deux entiers et , vaut avec qui vaut , ou selon que est <, = ou > à .
Exemples : 18/10 vaut 1 ; -18/10 vaut -1 ; -18/-10 vaut 1.

32
Syntaxe de base

3. Opérateurs de comparaison

Opérateur Fonction
== égalité
!= inégalité
< inférieur strict
<= inférieur ou égal
> supérieur strict
>= supérieur ou égal

NOTA-BENE : résultat de type booléen

Attention
Ne surtout pas confondre == (test d'égalité) et = (affectation)

4. Opérateurs booléens

Opérateur Fonction Usage


&& et (version optimisée) expr1 && expr2

|| ou (version optimisée) expr1 || expr2

^ ou exclusif (xor) expr1 ^ expr2

! négation ! expr1

& et (version non optimisée) expr1 & expr2

| ou (version non optimisée) expr1 | expr2

NOTA-BENE : les opérandes doivent être des expressions à valeur booléenne

Remarque
Différence entre les versions optimisées et non-optimisées :
 avec le et optimisé : &&, le deuxième opérande n'est pas évalué si le premier
est faux
 avec le ou optimisé : ||, le deuxième opérande n'est pas évalué si le premier
est vrai

33
5. Opérateurs bit-à-bit

Opérateur Fonction Usage


& et op1 & op2

| ou op1 | op2

^ ou exclusif (xor) op1 ^ op2

~ négation ~ op1

<< décalage à gauche (x2) op1 << op2

>> décalage à droite op1 >> op2

>>> décalage à droite non signé (/2) op1 >>> op2

Travaillent sur la représentation binaire

NOTA-BENE : opérandes de type entier

6. Opérateurs d'affectation

int i, j, k ;
final int TMAX = 100 ;

// Exemples d'affectations ordinaires :


i = 0 ;
j = i ;
k = TMAX ;

// Exemple d'affectations en série :


// (évaluation de droite à gauche)
i = j = 2 ; // i et j valent 2

// Exemple avec opération combinée :


i += 3 ; // équivaut à i = i+3 ;

Complément : Différence subtile !


L'équivalence entre opérateurs combinés et opération arithmétique suivie d'une
affectation n'est pas totale, car (bizarrement) pour les affectation combinées, il y a
conversion automatique.
Exemple : si i est de type int, i+=3.7; est équivalent à i = (int)(i+3.7); et donc à
i+=3; !!!

34
Syntaxe de base

7. Opérateurs d'incrémentation et de décrémentation

Opérateur Fonction Usage


++ post-incrémentation i++

pré-incrémentation ++i

-- post-décrémentation i--

pré-décrémentation --i

Ces opérateurs permettent de compacter le code :

n = i++; équivaut à n = i;
i = i + 1;
n = ++i; équivaut à i = i + 1;
n = i;

8. Autres opérateurs
Ternaire conditionnel : bool ? expr1 : expr2

int v = (x < y) ? x : y
// v vaut le minimum entre x et y

Conversion explicite (ou casting) : (type)

double x = 1.7;
int i = (int) x; // i vaut 1
double y = -1.7;
int j = (int) y; // i vaut -1

9. Priorité des opérateurs

Opérateurs Java (par ordre de priorité décroissante)


[ ] - (params) expr++ expr--
++expr --expr +expr -expr ~ !
new (type)expr
* / %
+ -
<< >> >>>
< > <= >= instanceof
== !=

35
Opérateurs Java (par ordre de priorité décroissante)
&
^
|
&&
||
? :

= += -= *= /= &= <<= ...


->

NOTA-BENE : à priorité égale, évaluation de gauche à droite pour les opérateurs


binaires, sauf pour les affectations (=, *=, ...) qui s'évaluent de droite à
gauche

D. Blocs, instructions de contrôle (tests, boucles, …)

1. Instructions et blocs
Chaque instruction se termine par un ';'

int x, y, z;
x = 10;
y = f(x);
z = (x+y)/2;

On peut grouper plusieurs instructions en un bloc (délimité par des accolades) :

int a=1, b=2;

{ // début de bloc
int x = a;
a = b;
b = x;
} // fin de bloc

x = 3; // ERREUR : x est inconnu ici

Remarque
La portée d'une variable va de sa déclaration jusqu'à la fin du bloc où elle est
déclarée

36
Syntaxe de base

2. Instructions de contrôle
Les instructions de contrôle permettent de modifier l'ordre normal (séquentiel)
d'exécution des instructions :

1. exécution conditionnelle : if(...) ... else


2. cas multiples : switch(...) case ...
3. boucles :
- while(...) ...
- do ... while(...)
- for(...) …

3. Exécution conditionnelle
Forme minimale (pas de clause else, une seule instruction) :

if (boolExpr) instruction;

Forme standard :

if (boolExpr) {
instruction(s); // exécutée(s) si VRAI
} else {
instruction(s); // exécutée(s) si FAUX
}

Possibilité d'imbrication :

if (boolExpr) {
instruction(s); // exécutée(s) si VRAI
} else if (boolExpr2) {
instruction(s);
} else { // . . .
}
}

Exemple
if ( a!=10 ) x = 4;
else { //bloc car plusieurs instructions
x = 5;
y = t+2;
}

Remarque
 Dans tous les cas : le test est placé entre parenthèses.
 La partie « sinon » (else) est facultative.
 Les accolades sont facultatives si il n'y a qu'une seule instruction.
 Contrairement à d'autres langages, il n'y a pas de mot-clé then en Java.

37
4. Cas multiples

switch (e) {
case cst1:
// instruction(s) si e==cst1
break;
case cst2:
// instruction(s) si e==cst2
case cst3:
// instruction(s) si e==cst3 ou e==cst2
break;
default:
// instruction(s) si aucun des cas prévus
break;
}

Avec :
 e : de type entier ou char ou String ou bien type énuméré (enum)
 cst1, cst2, ... : littéral ou constante (final)

Exemple
final int ERREUR=-1;
int x, y;
//...
switch(x) {
case 0 :
y=x;
break;
case 1 :
x=y;
break;
case ERREUR :
System.exit(1);
break;
default :
y=0;
}

Exemple
enum Temperature { FROID, TIEDE, CHAUD } ;
Temperature t;
// ..
switch(t) {
case FROID : // ...
case TIEDE : // ...
case CHAUD : // ...
}

38
Syntaxe de base

Attention
 Le paramètre de l'instruction switch ne peut pas être de n'importe quel type
(les nombres flottants en particulier sont interdits, de même que les instances
de classes autres que String).
 Sauf cas particuliers, une clause break est nécessaire à la fin de chaque
branche du switch. A défaut, chacun des codes correspondant aux branches
suivantes sera exécuté sans même vérifier la validité des tests associés, ce qui
ne correspond que très rarement au fonctionnement souhaité.

5. Boucles de répétitions
Deux sortes de boucles « while » en Java :

while (boolExpr) { do {
// corps exécuté tant que // corps exécuté
// boolExpr est vrai : // au moins 1 fois :
instruction(s); instruction(s);
} } while (boolExpr);

NOTA-BENE : les accolades sont optionnelles si le corps comporte une seule


instruction :

while (boolExpr) do instruction;


instruction; while (boolExpr);

Exemples :

int y = 10 ;
while (y<8) {
y *= 2 ;
}
// que vaut y ?

int z = 10 ;
do {
z *= 2 ;
} while (z<8);
// que vaut z ?

while (x>0.0001) x = f(x);

39
6. Boucles d'itération

for (init ; boolExpr ; incr) {


instructions; // corps de la boucle
}

Avec :
 init : déclarations et/ou affectations, séparées par des virgules
(typiquement : initialisation des variables utilisées dans la boucle)
 incr : expressions séparées par des virgules
(typiquement : incrémentation des variables utilisées dans la boucle)

Equivaut à :
init;
while (boolExpr) {
instructions;
incr;
}

Exemples :
int somme=0;
for (int i=1 ; i<=n ; i++) {
somme += i;
}

for (i=0, j=1 ; i<10 && (i+j)<10 ; i++, j*=2) {


// . . .
}

for ( ; ; ) ;

Remarque
 Possibilité d'avoir plusieurs instructions à la suite dans la zone « initialisation »
et/ou « incrémentation » comme dans le 2° exemple ci-dessus (remarquer
l'usage de la virgule pour séparer les instructions en question).
 Inversement, chacun des composants du for peut être vide (voir le 3e
exemple : boucle infinie qui ne fait rien !)

7. Boucles d'itération « simplifiées »

for (type param : expression) {


// . . .
}
où expression est
 soit un tableau (de type cohérent avec celui de param),
 soit un objet implantant l'interface Iterable (cf. Interfaces pré-
définies à connaître p 166)

40
Syntaxe de base

Exemple
int[] prems = { 2, 3, 5, 7, 11};
// prems : tableau d'entiers
int somme = 0;
for (int i : prems) {
somme += i*i;
}

String[] rep = { "oui", "non", "peut-être" };


// rep : tableau de chaînes de caractères
for (String s : rep) {
System.out.println(s);
}

Attention
 Contrairement à la version « classique » du for, le 1° paramètre entre
parenthèse n'est pas forcément de type entier (son type doit être celui des
éléments du tableau).
 Par ailleurs, les valeurs successives affectées à ce paramètre lors du
déroulement de la boucle correspondent aux différentes valeurs présentes dans
le tableau (et pas aux indices comme dans la version « classique » du for).

DONC ATTENTION : risque d'erreur lorsque le type des éléments est entier si on
confond les deux versions de l'instruction « for ».

8. Interruptions des boucles, labels


Trois instructions permettent d'interrompre le déroulement normal d'une boucle en
Java :
 continue : fait sortir du tour de boucle en cours (passe immédiatement au
prochain test de la boucle)
 break : fait sortir de la boucle
 return (cf. Type de retour et instruction return p 58) : fait sortir
immédiatement de la fonction en cours, et donc, a fortiori, de la boucle en
cours

Complément : label devant une boucle


On peut mettre un « label » devant une boucle Java et utiliser les instructions
continue et break (suivies du nom du label) pour indiquer une boucle spécifique.
Intérêt : gestion de cas particuliers dans des boucles imbriquées complexes (à éviter
dans les autres cas dans la mesure où ces labels rendent le code difficile à
relire/vérifier).

41
Exemple
nomDuLabel:
while ( f(x) > 0 ) {
for ( x : tab) {
// ....
if ( tab[x] > 100 ) {
break;
// sort de la boucle la plus interne (for)
}
if ( tab[x] < 0 ) {
break nomDuLabel;
// sort de la boucle englobante (while)
}
if ( tab[x] == 0 ) {
continue nomDuLabel;
// saute au prochain test de la boucle
// englobante (while)
}
// ....
}
}

Complément : le mot-clé goto


En Java, goto est un mot-clé au sens où on ne peut pas l'utiliser librement pour
nommer une variable ; cependant il n'est pas utilisé par le langage, au moins dans sa
version actuelle. C'est d'ailleurs avec const le seul mot ainsi « réservé » par le
langage sans être effectivement utilisé.

E. Entrées-sorties
Exemple d'écriture sur le flux de sortie standard (écrit sur
la console par défaut) :
double z = 0.43;
System.out.print("z=");
System.out.print(z);
System.out.println(" et 2z=" + (2*z));

Exemple de lecture sur le flux d'entrée standard (lit depuis


le clavier par défaut) :
// Lecture d'un caractère à la fois
int car = System.in.read();

// Lecture de 10 caractères
byte buf[] = new byte[10];
int nbLus = System.in.read(buf);

Conseil
Utiliser la classe Scanner pour lire autre chose que des caractères ou tableaux de
caractères (voir ci-après).

42
Syntaxe de base

Exemple de lecture avec la classe Scanner


import java.util.Scanner;

//…

Scanner sc = new Scanner(System.in);


String ch = sc.next(); // lecture d'un mot
int k = sc.nextInt(); // lecture d'un entier
double val;
// teste si un double suit sur le flux d'entrée
// (ici il s'agit du clavier) :
if ( sc.hasNextDouble() ) {
val = sc.nextDouble(); // lecture d'un double
}
String s = sc.nextLine(); // lecture d'une ligne

ATTENTION : Java utilise, par défaut, le format « local » des nombres (par exemple
en français : 2,5 et pas 2.5) ; possibilité de choisir une « localisation » avec la
méthode useLocale() (cf. Localisation et internationalisation p 172)

Complément : la classe Scanner


 Il existe une méthode nextXyz() et une méthode hasNextXyz() pour chaque
type primitif Xyz
exemple pour le type « double » : nextDouble() et hasNextDouble()
 Lance InputMismatchException si l'élément suivant n'est pas convertible dans
le type demandé
d'où l'intérêt de tester la présence d'une donnée d'un certain type avant de la
lire !
 Possibilité de choisir un séparateur avec useDelimiter(Pattern)
 Voir plus loin dans le cours pour plus de détails sur les exceptions (cf. Principe
des exceptions p 91) et les classes Scanner et Pattern (cf. Les classes Scanner
et Pattern p 168)

Ecriture formatée avec printf()


printf(String, Object...) est une méthode à nombre d'arguments variable qui
facilite l'affichage formaté :

double rac2 = Math.sqrt(2);


System.out.printf("sqrt(2)=%.3f", rac2);
// imprime : sqrt(2)=1,414

int i=3;
int j=30;
int k=303;
System.out.printf("|%3d|%3d|%3d|", i, j, k);
// imprime : | 3| 30|303|

double x=2.5;
double y=-3.755;
System.out.printf("x:%+.2f\ny:%+.2f", x, y);
// imprime quoi ?

43
Complément : printf(), format() et la classe Formatter
printf() est une méthode d'affichage puissante mais plus complexe d'emploi que
print() et println(). Son principal intérêt est de permettre un contrôle fin du
formatage des données, en particulier numériques (mais pas seulement)10.
Le principe général est de passer en 1° paramètre une chaîne de caractères avec du
texte à afficher, et comportant un nombre quelconque de « séquences » introduites
par le caractère %.
A chaque séquence doit correspondre une variable passée en paramètre à la suite de
la chaîne de caractères comme dans les exemples ci-dessus.
Les séquences doivent suivre une syntaxe spécifique détaillée dans la documentation
en-ligne de la classe Formatter.
Pour comprendre les exemples ci-dessus il suffit de savoir que :
 chaque séquence commence par un caractère % et se termine par une lettre qui
spécifie la nature de la variable qui sera substituée à cette séquence, à savoir :
- s pour une chaîne de caractères ;
- c pour un caractère ;
- d pour un entier ;
- f pour un nombre flottant ;
- e pour un nombre flottant à afficher en notation « scientifique » ;
- ...
 le contrôle de l'affichage s'effectue en ajoutant, si besoin, des directives entre
le caractère % et la lettre qui termine la séquence, ainsi :
- %f indique qu'on souhaite afficher à cet endroit un nombre flottant ;
- %.2f indique qu'on souhaite exactement 2 chiffres après la virgule ;
- %6.2f indique en outre que l'affichage devra comporter au minimum 6
caractères, y compris la virgule et le signe éventuel (quitte à ajouter des
blancs si besoin) ;
- %+6.2f indique en outre que le signe (+ ou -) devra impérativement
s'afficher (par défaut seuls les signes - s'affichent);
- %6d indique qu'on souhaite afficher à cet endroit un nombre entier occupant
6 caractères au minimum ;
- %+6d indique en outre que le signe devra impérativement s'afficher.
[ NOTA-BENE : beaucoup d'autres directives sont disponibles pour les nombres
flottants, et pour chacun des autres types. ]
 %% permet d'inclure un caractère % sans qu'il soit interprété comme le début
d'une séquence
Au delà, se souvenir que printf() est une méthode à la fois puissante et flexible ; à
privilégier dès qu'un simple print() ou println() ne suffit pas, et ce d'autant plus
qu'elle permet de formater des données créées par l'utilisateur dès lors que ces
données se conforment à l'interface « Formattable ».
Outre printf(), il peut être utile de connaître la méthode statique String.format()
qui s'appuie sur la même syntaxe que printf() mais se contente de retourner la
chaîne de caractères produite au lieu de l'afficher.
NOTA-BENE : comme pour tout aspect non-trivial de Java, il ne faut pas chercher à
tout découvrir – et encore moins tout mémoriser – par avance. Concernant, par
exemple, printf(), il faut bien comprendre et mémoriser le mode général de
fonctionnement, puis, lorsque nécessaire, approfondir ses connaissances en
parcourant la documentation de référence en-ligne (l'ensemble des possibilités de

10 - Accessoirement, elle présente l'avantage de fonctionner de manière similaire à la fonction de même nom
du langage C, et donc d'être facile d'utilisation pour tous les programmeurs en C.

44
Syntaxe de base

formatage permises par la classe Formatter occupe 5 pages) et/ou en cherchant des
exemples dans une base telle que http://www.java2s.com.

F. Exemple de programme, compilation, exécution


Exemple de programme
// Début du fichier : les « import »
import java.util.Scanner;

// Toutes les autres instructions sont dans une


// (ou plusieurs) classe(s)
public class MonProgramme {

// Un programme « ordinaire » contient toujours


// une fonction principale (main) :
public static void main(String[] args) {
System.out.print("Entrez un int : ");
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for (int i=0 ; i<n ; i++) {
System.out.println(i);
} // fin de la boucle for
} // fin de la fonction main

} // fin de la définition de la classe

Compilation et exécution
 En général, un fichier MaClasse.java doit contenir la classe MaClasse, et elle
seule ; pour plus de détails voir organisation en fichiers (cf. Organisation en
fichiers, compilation et exécution p 124)
 La compilation de MaClasse.java MaClasse.class
 Le fichier MaClasse.class peut être exécuté si et seulement si la classe
MaClasse comporte une fonction « main ».

45
Références,
III -

tableaux, chaînes de
caractères, types III
énumérés simples

Références 47
Tableaux 48
Chaînes de caractères 53
Types énumérés simples 55
Références constantes 56

A. Références
Les références servent à manipuler toutes les variables dont le type n'est pas
primitif (i.e. tableaux, objets, types énumérés)

A voir comme une sorte de « poignée », un mécanisme intermédiaire entre un nom


de variable et l'emplacement en mémoire où est stockée sa valeur

NOTA-BENE :
 plusieurs références différentes peuvent référencer un même objet ou tableau
 les références sont typées
 le mot-clé null désigne une référence « vers rien » (compatible avec tous
types de référence)
 une affectation entre références modifie la référence en partie gauche de
l'affectation, et non la chose référencée

Exemple :

int t1[] = {1, 2, 3};


int t2[] = t1; // t2 réf. le même tableau que t1
t2 = new int[5]; // t1 reste réf. à {1,2,3}
t1 = null; // t1 ne pointe plus vers rien

47
B. Tableaux
Principes
 Manipulés par des références
 Allocation dynamique par new ( taille définissable à l'exécution)
 Taille fixée une fois pour toute après allocation
 Taille accessible à tout moment par le « champ » length
 Indices variant entre 0 et length-1 (et vérification systématique des bornes à
l'utilisation)

Complément : stockage des tableaux en mémoire


Contrairement à C/C++, les tableaux en Java ne sont pas stockés sous forme d'une
simple zone mémoire de taille égale à la longueur du tableau multipliée par la taille
d'un élément (avec possibilité de naviguer librement dans la zone mémoire ainsi
délimitée, et même au delà étant donné le niveau de liberté offert par les opérations
sur pointeurs dans ces deux langages).
En Java, le stockage d'un tableau inclut sa taille. Surtout, l'accès aux cases du tableau
est strictement contrôlé pour interdire toute lecture/écriture en dehors des limites
qu'il occupe en mémoire, et plus généralement toute opération non conforme en
termes de typage (en Java, chaque élément d'un tableau doit être du type indiqué
lors de sa déclaration).
Par ailleurs, les tableaux en Java ne sont pas des « instances d'une classe » (voir plus
loin) comme dans d'autres langages objet : ce sont des entités particulières, ni type
primitif, ni instance de classe.

Déclaration, création, initialisation


 Déclaration :

int tab[]; // 1° forme autorisée


int [] tab2; // 2° forme autorisée (équivalente)

 Création :
- par new après la déclaration (ou lors de la déclaration) :

int tab[]; // déclaration


tab = new int[5]; // création

- création implicite en cas d'initialisation lors de la création (voir ci-dessous)

 Initialisation :

// A la déclaration :
int tab[] = {1, 2, 3};

// Lors de la création :
tab = new int[] {1, 2, 3};

NOTA-BENE : par défaut, les cases du tableau sont initialisées à 0, '\u0000', false ou
null (selon le type de base)

48
Références, tableaux, chaînes de caractères, types énumérés simples

Attention
Il ne faut jamais spécifier de dimension (entier entre les crochets) lors :
 d'une simple déclaration : on doit écrire int tab[]; et surtout pas int
tab[5];
 d'une création comportant la liste des valeurs initiales : on doit écrire tab =
new tab[]{1,2,3,4,5}; et surtout pas tab = new tab[5]{1,2,3,4,5};

Manipulations usuelles
 Accès à la taille :

int [] tab = new int[5];


int size = tab.length; // size vaut 5

 Accès aux valeurs stockées :

tab[0] = 1;
tab[4] = -1;
// RAPPEL : les indices varient entre 0 et length-1

 Affichage :

for(val : tab) {
System.out.println(val) ;
}
// affiche quoi ?

// ATTENTION :
System.out.println(tab) ;
// affiche tab en tant que référence
// (adresse mémoire où est stockée le contenu)

 Affectation (attention, l'affectation ne modifie que la référence ) :

int t1[] = {1, 2, 3};


int t2[] = {4, 5};
t1 = t2; // t1 réfèrence le même tableau que t2
// NOTA-BENE : le tableau {1, 2, 3} n'est plus référencé,
// l'espace mémoire correspondant sera automatiquement
// récupéré par le « ramasse-miette » (GC) afin de
// pouvoir le ré-allouer ultérieurement.

 Recherche, tri, etc. : voir fonctions utilitaires de la classe Arrays (cf.


Introduction p 149)

Attention
Lancement de l'exception (cf. Principe des exceptions p 91)
ArrayIndexOutOfBoundsException en cas de tentative d'accès hors des bornes d'un
tableau (indice négatif ou >= t.length)

Définition
On appelle « ramasse-miettes » (en anglais : garbage collector ou encore GC) le
mécanisme intégré à l'interpréteur du langage (la machine virtuelle dans le cas de

49
Java) qui récupère de manière automatique les zones mémoires allouées puis rendues
inaccessibles au fil de l'exécution du programme.
Tous les langages n'incluent pas de « ramasse-miette », l'alternative étant de
confier au programmeur la tâche de libérer explicitement les zones mémoire dont il
n'a plus l'usage (cas des langages C et C++ par exemple).
En pratique, la présence d'un « ramasse-miette » simplifie la programmation et
rend les programmes plus fiables, mais cela se paye par :
 une dégradation (et une moindre prévisibilité) des performances à
l'exécution ;
 l'impossibilité de procéder à certaines optimisations très spécifiques liées à
l'organisation des données en mémoire.
Dans tous les cas, il est essentiel de recycler les zones mémoire sans quoi la taille des
programmes grossit inutilement au cours de l'exécution (on parle alors de « fuite de
mémoire » ou memory leak en anglais).

Exemple
public class ExempleTableau {
public static void main(String[] args) {

// DECLARATION :
double[] tab;

// CREATION ET DIMENSIONNEMENT :
int lg = 1 + (int)( 9*Math.random() );
tab = new double[lg];

// AFFECTATION DES ELEMENTS DU TABLEAU :


for (int i=0 ; i<tab.length ; i++) {
tab[i] = 1./(i+1);
}

// AFFICHAGE :
for (int i=0 ; i<tab.length ; i++) {
System.out.print(tab[i] + " ");
}
System.out.println();

}
}

Copie de tableaux
 Méthode « manuelle » : création d'un nouveau tableau, puis copie case par
case
 Copie (sans allocation) par appel de System.arraycopy() :

// copie src[0..49] (50 cases) ==> dst[2..51]


System.arraycopy(src, 0, dst, 2, 50);

 Allocation et copie par Arrays.copyOf() ou Arrays.copyOfRange() :

// copie les 10 premières cases de t dans t2 :


int[] t2 = Arrays.copyOf(t, 10);
// copie les cases 5,6..79 de t dans t3 :
int[] t3 = Arrays.copyOfRange(t, 5, 80);

50
Références, tableaux, chaînes de caractères, types énumérés simples

// ATTENTION : copie les cases d'indice [5..80[

 Allocation et copie par clonage :

int[] copie = t.clone();

ATTENTION : pour un tableau d'objets, les fonctions ci-dessus recopient


uniquement les références les mêmes objets sont ensuite partagés par les 2
tableaux

NOTA-BENE : déplacement interne dans un tableau possible par


System.arraycopy() :

// décale le contenu du tableau d'une case vers la droite


// (la case t[0] reste inchangée) :
System.arraycopy(t, 0, t, 1, t.length-1);

Attention : plusieurs points à connaître concernant


System.arraycopy(), Arrays.copyOf() et clone()
Lorsqu'on utilise System.arraycopy() :
 le tableau destination doit au préalable avoir été déclaré et dimensionné
correctement ;
 les tableaux source et destination doivent être du même type (sinon,
lancement de l'exception ArrayStoreException).
Lorsqu'on utilise Arrays.copyOf() ou clone() :
 le résultat de la fonction est un nouveau tableau créé (l'allocation est faite par
Arrays.copyOf()) ;
Lorsqu'on utilise Arrays.copyOf() :
 lorsque la taille demandée est supérieure à la taille du tableau initial les cases
finales sont initialisées à la valeur par défaut du type de base, dans le cas
contraire les cases en trop sont ignorées.
Pour résumer :
1. System.arraycopy() est la méthode la plus puissante/flexible mais aussi la
plus délicate à cause du risque de confusion dans les paramètres et de la
nécessité d'allouer au préalable le tableau destination.
2. Inversement, clone() et Arrays.copyOf() sont des méthodes plus simples
d'emploi – à privilégier chaque fois que l'on veut copier dans un nouveau
tableau.
3. Dans tous les cas la copie n'est jamais récursive (pas de méthode
« deepCopy() » dans Java jusqu'ici).

Tableaux d'objets
Des tableaux contenant des (références à des) objets d'une classe donnée peuvent
être déclarés et créés pour toute classe (prédéfinie ou bien écrite par le
programmeur).
Par exemple, un tableau de chaînes de caractères modifiables (classe StringBuffer :
voir ci-après) se déclare et se dimensionne ainsi :

StringBuffer[] tabChaines;
tabChaines = new StringBuffer[2];

51
Attention
Le dimensionnement d'un tableau d'objets crée uniquement des « cases » pour
stocker des références aux objets, mais pas les objets eux-mêmes.
Ces références valent initialement null, il faut donc les faire ensuite pointer vers les
objets voulus par des affectations, comme dans l'exemple suivant :

StringBuffer[] tabChaines;
tabChaines = new StringBuffer[2];

// affectation des références du tableau :


tabChaines[0] = new StringBuffer("OUI");
tabChaines[1] = new StringBuffer("NON");

Tableaux multi-dimensionnels
Il n'existe pas de tableaux à plusieurs dimensions en Java, mais, de manière analogue
aux tableaux d'objets, on peut créer des « tableaux de tableaux » :

// Déclaration et création :
float matrix[][] = new float[2][3];
// matrix référence un tableau de taille 2
// dont chaque case référence un tableau
// d'entiers de taille 3

// Utilisation :
for (int i=0 ; i<matrix.length ; i++) {
for (int j=0 ; j<matrix[i].length ; j++) {
matrix[i][j] = i*j;
}
}

NOTA-BENE : il est possible de créer des formes non rectangulaires :

float triangle[][];
int dim;
// ...
triangle = new float[dim][];
for (int i=1 ; i<dim ; i++) {
triangle[i] = new float[i];
}

Quelques (rares) fonctions à connaître sur les tableaux de tableaux :


- Arrays.deepEquals();
- Arrays.deepToString();

52
Références, tableaux, chaînes de caractères, types énumérés simples

C. Chaînes de caractères

Attention
Deux classes complémentaires en Java :
1. chaînes immuables (non modifiables) : String
2. chaînes modifiables : StringBuffer

La classe String
Chaînes immuables
 Chaînes littérales : "une chaîne"
 Concaténation par l'opérateur +
Exemple :

int age = 24;


// Création :
String s1 = "Age : " + age;
// Création par conversion :
double x = 1.618;
String s2 = String.valueOf(x);
// Utilisation :
int l = s1.length();
char c = s1.charAt(0);
int diff = s1.compareTo(s2);
boolean tst = s2.equals(s1);
s2 = s1;
s2 = "Bonjour";
String[] sub = s1.split(":");

Attention
En java, pour accéder à la longueur, il faut écrire :
s.length() si s est de type String
et t.length si t est un tableau !

Remarque : Les méthodes compareTo() et


compareToIgnoreCase()
Les méthodes compareTo() et compareToIgnoreCase() prennent en paramètre un
objet de type String et le compare à l'instance courante.
Plus précisément, s1.compareTo(s2) retourne :
 0 ssi les deux chaînes sont identiques ;
 un entier k négatif ssi s1 se situe avant s2 sans l'ordre lexicographique ;
 un entier k positif sinon.
La valeur exacte de k lorsqu'elle est non-nulle est rarement utile en pratique
(indication du caractère à partir duquel s1 et s2 se différencient sauf cas particulier
où l'une des deux chaînes est sous-chaîne de l'autre ; voir la documentation de la
classe String pour plus de détails).
Comme son nom le suggère, la méthode compareToIgnoreCase() ignore les
variations de « casse », autrement dit les différences entre majuscules et minuscules.

53
Complément
Le classe String comporte de nombreuses fonctions utilitaires :
 test d'égalité partielle :
boolean regionMatches(int deb, String s2, int deb2, int fin2)
 test de début/fin :
boolean startsWith(String) ; boolean endsWith(String),...
 extraction de sous-chaîne :
String substring(int deb, int fin)
void getChars(int deb, int fin, char[] dest, int destDeb)
 découpage :
String[] split(String delim)
 suppression des blancs de début et fin :
String trim()
 changement de casse :
String toLowerCase() ; String toUpperCase() ; ...
 substitution de caractères :
String replace(char ancien, char nouveau)
 conversion en chaîne des types de base (méthodes statiques) :
String.valueOf(int) ; String.valueOf(double) ; ...
 ...

La classe StringBuffer
Chaînes modifiables
Exemple :

// Création en spécifiant la « capacité » initiale :


StringBuffer vide = new StringBuffer(1000);
// Création à partir d'une String :
StringBuffer buf = new StringBuffer("Bonjour");

// Utilisation :
int l = buf.length();
char c = buf.charAt(0);
buf.setCharAt(0, 'L');
buf.insert(3, "gues ");
buf.append("née");
buf.deleteCharAt(6);
String s = buf.toString();
String s2 = buf.substring(7, 11);

Attention
Entre variables de type StringBuffer :
 pas de compareTo() ni de compareToIgnoreCase()
 equals() ne teste pas l'égalité des caractères de la chaîne
 pas d'opérateur + pour concaténer
par contre (buf + s) et (s + buf) sont OK si s est une String, mais le
résultat est alors de type String

54
Références, tableaux, chaînes de caractères, types énumérés simples

Complément : capacité et longueur


La capacité d'un StringBuffer correspond au nombre maximum de caractères qu'il
pourra contenir sans qu'il soit nécessaire de déplacer son contenu en mémoire pour
disposer de plus d'espace.
La longueur d'un StringBuffer correspond à longueur de la chaîne de caractères
stockée dedans (la longueur est toujours inférieure ou égale à la capacité).
La capacité initiale peut être choisie via le constructeur comme dans l'exemple ci-
dessus (par défaut, la capacité initiale est de 16 caractères). Lorsque la capacité est
insuffisante pour réaliser une opération de type insert() ou append() elle est
automatiquement augmentée mais cette augmentation de capacité a un coût en
terme de performances à l'exécution. Le programmeur a ainsi le choix entre laisser
Java gérer automatiquement la capacité ou la gérer lui-même lorsqu'il connaît par
avance la longueur maximum des chaînes qui seront stockées.
Les variables de type StringBuffer se caractérisent par le fait que leur capacité et
leur longueur peuvent évoluer au fil des opérations effectuées alors que pour les
String la longueur est figée une fois la String initialisée (et la capacité est égale à la
longueur).

Complément : la classe StringBuilder


La classe StringBuilder est une variante de la classe StringBuffer (mêmes
fonctionnalités). Elle est plus performante que la classe StringBuffer, mais n'est pas
utilisable en cas de multi-threading car ses méthodes sont « non-synchronisées » (cf.
Synchronisation des exécutions p 210).

Conseil
Les classes String et StringBuffer comportent bien plus de méthodes que
présentées ci-dessus ; penser à consulter la documentation en-ligne pour approfondir
le sujet.

D. Types énumérés simples


Définir un nouveau « type énuméré » permet de typer proprement une variable
pouvant prendre un ensemble restreint de valeurs
Mot-clef : enum
Exemple :

enum CouleurFeu {
VERT, ORANGE, ROUGE
}
// . . .
CouleurFeu col = CouleurFeu.ROUGE;
// . . .
switch(col) {
case CouleurFeu.VERT : passer() ; break ;
case CouleurFeu.ORANGE : freiner() ; break ;
case CouleurFeu.ROUGE : stopper() ; break ;
}

Remarque
Pour plus de détails, voir la section consacrée aux types énumérés (cf. Types
énumérés p 89).

55
E. Références constantes
Une référence constante est une référence associée de façon définitive à un tableau
ou à un objet donné
Mot-clé : final
Exemple :

final double [] tab = new double[10];

// La référence (tab) est figée :


tab = new double[20]; // ici ERREUR

// Le contenu du tableau reste modifiable :


tab[0] = 1.732; // OK
tab[0] = 3.; // OK

56
IV - Fonctions

IV

Introduction 57
Type de retour et instruction return 58
Appel (ou « invocation » ) de fonction 59
Fonction et portée 59
Programme principal 60
Passage des paramètres 60
Récursivité 62
Surcharge (ou « overloading ») 62
Fonctions à nombre variable d'arguments 62
Fonctions « natives » 63

A. Introduction
 Eléments essentiels de structuration en programmation « impérative »

 En Java, une fonction se caractérise par :


- son nom
- une liste (possiblement vide) de paramètres typés
- un type de retour
- un corps (la séquence d'instructions de la fonction)
- une visibilité, une liste d'exceptions, ... (voir plus loin)

57
Premier exemple de fonction

Définition : Signature (ou en-tête) et prototype


 On appelle « signature » ou « en-tête » d'une fonction son nom + la liste de
ses paramètres (avec pour chacun son type)
 On appelle « prototype » d'une fonction son nom + la liste de ses paramètres
(avec pour chacun son type) + son type de retour

Attention
 En Java, chaque fonction est obligatoirement définie dans une classe (ex. : la
classe prédéfinie Math regroupe des fonctions mathématiques).
 Contrairement à d'autres langages, les fonctions en Java ne s'imbriquent pas
(i.e. toutes les fonctions d'une classe sont définies les unes après les autres).

B. Type de retour et instruction return


Type de retour : n'importe quel type, ou bien void
Instruction de retour : return (suivi de la valeur de retour éventuelle)
Exemple :

class MaClasse {
/* indexDe() retourne l’index de la valeur v
dans t (ou -1 si pas trouvée) */
public static int indexDe(float v, float[] t) {
int len = t.length;

58
Fonctions

for (int i=0 ; i<len ; i++) {


if (t[i] == v) {
return i;
}
}
return -1;
}
}

Rappel
Attention à bien respecter les conventions de nommage vues précédemment :
 maFonction() // 1° lettre en minuscule pour les fonctions
 MaClasse // 1° lettre en majuscule pour les classes

C. Appel (ou « invocation » ) de fonction


Cas général préfixer par le nom de la classe, exemples :

y = Math.sin(x);
k = MaClasse.carre(i);

A l'intérieur de la même classe, préfixer est inutile, exemple :

class MaClasse {
public static int carre(int i) {
return i*i;
}
public static void main(String[] args) {
int x = MaClasse.carre(5);
System.out.println(x); // affiche 25
int y = carre(6);
System.out.println(y); // affiche 36
}
}

D. Fonction et portée
Les variables déclarées dans une fonction sont locales à cette fonction
Idem pour les paramètres
Exemple :

class Portee {
public static int calcul(int val) {
int tmp = 3*val;
return tmp;
}
public static void main(String[] args) {
int tmp = 1;
System.out.println( calcul(9) );
// Que vaut la variable tmp ici ?
// et val ?
}
}

59
E. Programme principal
En Java, l'exécution de programme consiste en la recherche et l'appel d'une fonction
(publique) particulière
1. nommée main
2. prenant impérativement un (et un seul) paramètre de type String[]
3. ne retournant rien
Exemple, avec utilisation du paramètre :

class Echo {
public static void main(String [] args) {
for (String s : args) {
System.out.print(s + " ");
}
}
}
// Exemple d'exécution (en mode texte)
// L'utilisateur demande l'exécution du programme echo
// avec 3 arguments :
// java Echo un deux trois
// un deux trois

Attention : signature imposée de la fonction main


Pour qu'un programme Java s'exécute, la fonction main() doit impérativement avoir
toutes les caractéristiques listées ci-dessus.
En particulier, il doit y avoir un paramètre de type String[], même si on ne s'en
sert pas dans le reste du code !

F. Passage des paramètres


Principe

En Java, le passage des paramètres s'effectue toujours « par valeur » (le


paramètre formel prend pour valeur une copie de la valeur du paramètre effectif) :

 Passage par valeur pour les types « primitifs » :

public static void echange(int i, int j){


int tmp = i; // i et j : copies locales
i = j;
j = tmp;
}
public static void main(String[] args){
int a=1, b=2;
echange(a, b); // a et b ne sont pas modifiés
}
 Passage par valeur (i.e. recopie) des références :

public static void ech(String s1, String s2) {


String tmp = s1; // s1 et s2 : copies locales
s1 = s2;
s2 = tmp;
}
public static void main(String[] args) {

60
Fonctions

String a="oui", b="non";


ech(a, b); // a et b ne sont pas modifiés
}

Quid des objets référencés ?


public static void increm(int t[]) {
for (int i=0 ; i<t.length ; i++) {
t[i]++;
}
}
public static void tronquer(StringBuffer b) {
b.deleteCharAt(b.length() - 1);
}
public static void main(String[] args) {
int tab[] = {1, 2, 3};
increm(tab); // tab vaut {2, 3, 4}
StringBuffer buf = new StringBuffer("oui");
tronquer(buf); // buf vaut "ou"
}

NOTA-BENE : la référence est passée par valeur (la référence passée en paramètre
est une copie de l'originale), mais l'objet référencé peut néanmoins être modifié par la
fonction (la référence copiée tout comme la référence originale pointent vers le même
objet).

Remarque
En Java (contrairement à ce qui se passe dans d'autres langages) l'ordre d'écriture
des fonctions n'a pas d'importance : une fonction peut être invoquée depuis une ligne
qui précède sa définition dans le fichier.
Toutefois, il est vivement recommandé d'écrire les fonctions dans un ordre qui facilite
la compréhension du programme.

Exercice
class Passage {
public static int fonc(int x) {
x++;
return x;
}
public static void main(String[] args) {
int v = 1;
int y = fonc(v);
// Que valent y et v ici ?
int[] tab={1, 2, 3};
f2(tab);
// Etat de tab maintenant ?
}
public static void f2(int[] t) {
t = new int[] {2, 2};
}
}

61
G. Récursivité
Une fonction peut s'appeler elle-même à condition de bien gérer l'arrêt de la récursion
(à défaut : récursion infinie bug à l'exécution)
Exercice : cette fonction est incorrecte. Pourquoi ?

class ExempleRecursif {
public static double puiss(double x, int n){
if ( n==1 ) {
return x;
}
else {
return x*puiss(x, n-1);
}
}
//...
}

H. Surcharge (ou « overloading »)


Possibilité de définir (dans la même classe) plusieurs fonctions de même nom,
différenciées par le nombre et/ou le type des arguments :

class NomClasse {
public static int longueur(String s){
return s.length();
}
public static int longueur(int i){
String si = String.valueOf(i);
return si.length();
}
public static void main(String [] args) {
int k = 12345;
int lk = longueur(k); // lk vaut 5
String s = "oui";
int ls = longueur(s); // ls vaut 3
}
}

Remarque
Lors d'un appel de fonction, les arguments doivent être du type prévu ou d'un type
convertible automatiquement vers le type prévu.

I. Fonctions à nombre variable d'arguments


Possibilité de terminer la liste des paramètres d'une fonction par une « ellipse »
permettant un appel de fonction avec un nombre variable d'argument(s) de même
type (sauf si le type est Object) :

public static double[] f(int exp, double... nb) {


double[] res = new double[nb.length];
for (int i=0 ; i<res.length ; i++) {
res[i] = Math.pow(nb[i], exp);
}
return res;

62
Fonctions

}
//...
double[] t1=f(2, 2.57); // nb.length vaut 1 dans f
double[] t2=f(2, 7.5, 8, 8.5); // nb.length vaut 3
double[] t3=f(2); // nb.length vaut 0

NOTA-BENE :
 Le paramètre avec « ellipse » est traité dans la fonction comme un tableau
 Possibilité d'arguments de types hétérogènes via le type Object (cf. la classe «
Object » p 134)

J. Fonctions « natives »
Le mot-clé native dans une déclaration de méthode indique que cette méthode n'est
pas codée en Java, mais dans un autre langage, i.e. C ou C++.
Le code de la fonction sera recherché dans un fichier à part (une méthode native n'a
donc pas de corps).

public class NativeExample {


// ...
public native void ff(String s);
static { // bloc statique pour charger le code natif correspondant
System.loadLibrary ("nativeExample");
}
// ...
public static void main (String[] args) {
NativeExample n = new NativeExample(); // excute le bloc statique
NativeExample.ff("hello");
// ...
}
}
Java inclut par ailleurs :
 Java Native Interface (JNI) : spécification des règles à respecter dans le
nommage et le typage côté C/C++ ;
 javah : outil permettant de générer un fichier d'en-tête et un squelette de
programme C/C++ à partir d'un source Java comportant une ou plusieurs
occurrences du mot-clé native.

63
Algorithmique,
V-

complexité, tris
V

Algorithme 65
Calculabilité 66
Heuristique 67
Complexité, efficacité 67
Algorithmique, classification des algorithmes, … 69
Problématique du tri 69
Tri par sélection 70
Tri par insertion 71
Tri bulle 72
Tri rapide 74
Complexité des algorithmes de tri 77

A. Algorithme
Définition : Algorithme
Spécification d'un schéma de calcul sous forme d'une suite finie d'opérations
élémentaires obéissant à un enchaînement déterminé.11

Dans cette définition, le mot « spécification » doit être compris dans un sens assez
large : un algorithme peut être spécifié en langage naturel, dans un pseudo-langage,
dans un langage informatique, sous forme de diagramme, ... l'important étant que la
spécification en soit vraiment une en termes d'exhaustivité et de non-ambiguïté.
Dans son ouvrage de référence « The Art of Computer Programming (TAOCP) »,
Donald Knuth privilégie pour sa part un pseudo-langage de bas niveau : l'assembleur
MMIX, langage conçu spécifiquement par l'auteur pour garantir que chaque
algorithme est à la fois :
1. explicité dans ces moindres détails ;
2. facile à transcrire en code informatique sans perte d'efficacité.

11 - Cette définition ne fait pas référence à la notion de programme, ni d'ordinateur. C'est bien sûr
volontaire. D'autres définitions sont possibles :
- « processus systématique de résolution, par le calcul, d'un problème permettant de présenter les étapes
vers le résultat à une autre personne physique (un autre humain) ou virtuelle (un calculateur) » (Wikipedia) ;
- « Ensemble de règles opératoires dont l'application permet de résoudre un problème énoncé au moyen d'un
nombre fini d'opérations. Un algorithme peut être traduit, grâce à un langage de programmation, en un
programme exécutable par un ordinateur » (Encyclopédie Larousse).

65
Remarque
Si la définition ci-dessus est relativement récente (20° siècle), le mot « algorithme »
est relativement ancien : il provient de la transcription en latin d'Al-Khawarizmi,
mathématicien perse (9° siècle ap. J.-C.).
Le concept d'algorithme remonte à plus loin encore : l'algorithme d'Euclide pour le
calcul du PGCD fut explicité par son auteur en ~ 300 av. J.-C. ; d'autres algorithmes
sont semble-t-il plus anciens encore.

NOTA-BENE : un algorithme peut être mis en œuvre de différentes manières : sous


forme de programme informatique, de circuit électronique, de machine purement
mécanique, de « machine » biologique (cerveau), ...

Complément : Protection intellectuelle


Un algorithme en tant que tel ne peut normalement pas être breveté (en droit
européen et américain). Par contre, un programme informatique mettant en œuvre
un ou plusieurs algorithmes peut faire l'objet d'un brevet dans certains pays (e.g.
USA) mais pas en Europe. Sont brevetables les procédés industriels ou commerciaux
basés sur des algorithmes.12
Dans tous les cas, les programmes sont – dans tous les pays adhérant aux règles de
l'OMC – protégés en tant qu'œuvres littéraires par le droit d'auteur 13.

B. Calculabilité
Définition : Calculable (synonyme : décidable)
Caractérisation des problèmes (ou fonctions) qui peuvent être résolus par un
algorithme14.

Cette notion est beaucoup plus récente que celle d'algorithme (années 1930s :
théorie de la calculabilité par Hilbert, Gödel, Church, Turing, ...)

Définition : calculabilité (synonyme : décidabilité)


Concept à l'intersection des mathématiques et de l'informatique théorique ; la
calculabilité s'intéresse à la distinction fondamentale entre problèmes calculables /
non-calculables, aux conséquences de cette distinction, ...

Remarque
Dans la suite de ce cours, on s'intéressera uniquement aux problèmes « calculables ».

12 - En pratique, délimiter une frontière entre algorithme, logiciel et procédé en vue d'accorder ou refuser un
brevet peut être particulièrement délicat, d'où les litiges nombreux en ce domaine. Le problème est aggravé
par le nombre relativement faible de personnes maîtrisant à la fois les aspects techniques (informatique
théorique) et légaux (droit de la propriété intellectuelle).
13 - La protection liée au droit d'auteur est en théorie automatique, elle est liée à l'écriture d'une œuvre
originale. Il est toutefois prudent de se placer en situation de pouvoir prouver formellement sa qualité
d'auteur, et aussi de pouvoir dater sa création. Cela peut être réalisé en déposant une copie du programme
(source et/ou code binaire) chez un huissier, ou un organisme spécialisé tel que l'Agence pour la Protection
des Programmes (APP) en France.
14 - Plus formellement (au sens de la théorie de la calculabilité), un problème est décidable si, et seulement
si, il peut être décidé (calculé) par l'un ou l'autre des dispositifs suivants : fonctions récursives, machine de
Turing, lambda-calcul, machine à compteurs, automate cellulaire, machine de Blum-Shub-Smale, etc. Ces
différents dispositifs étant fondamentalement tous équivalents en ceci qu'ils permettent de résoudre
exactement la même classe de problèmes : les problèmes décidables.

66
Algorithmique, complexité, tris

C. Heuristique
Définition : Heuristique
Méthode de calcul qui, sans être un algorithme, fournit rapidement (en temps
polynomial) une solution – possiblement non-optimale voire approximative – à un
problème.

En informatique, les heuristiques sont utilisées lorsqu'un problème :


1. est réputé non-calculable ;
2. ou lorsque les algorithmes les plus performants sont trop lents et/ou trop
gourmands en mémoire ;
3. ou lorsque la résolution par heuristique se révèle la plus simple à programmer
tout en fournissant un résultat satisfaisant.

Exemples :
 les méthodes permettant de faire (bien) jouer un ordinateur au jeu d'échecs ;
 les méthodes permettant de reconnaître en temps réel des panneaux routiers à
partir d'un flux d'images provenant d'une caméra embarquée ;
 …

NOTA-BENE : Le mot « heuristique » vient du grec « je trouve » !

D. Complexité, efficacité
Définition : Complexité
Etude des ressources nécessaires à l'exécution d'un algorithme en « temps »
et en « espace ».
NOTA-BENE : dans cette définition,
 le temps correspond au nombre d'opérations élémentaires exécutées ;
 et l'espace à la quantité de mémoire nécessaire pour stocker les
instructions du programme et les données (y compris les données
intermédiaires produites au cours du calcul).

Cette définition ne fait pas directement référence à la notion de programme, ni


d'ordinateur. C'est volontaire : il s'agit de quantifier de manière théorique les
performances intrinsèques d'un algorithme, c-à-d. indépendamment :
1. de son implantation (e.g. sous forme de programme informatique) ;
2. de la machine sur laquelle il va s'exécuter.
Pour ce faire, on commencera par caractériser, sous forme d'un entier n, la taille
des paramètres d'entrée du problème, ce qui est généralement aisé : pour une
liste on choisira le nombre d'éléments, pour un graphe le nombre de nœuds, pour un
polynôme on pourra considérer le degré ou le nombre effectif de monômes, ...
Il conviendra ensuite d'étudier la manière dont chaque grandeur (temps et
espace) évolue en fonction de n lorsque n tend vers l'infini (autrement dit le
comportement asymptotique des fonctions temps et espace).
Ainsi, pour la complexité en temps », on cherchera à déterminer l'ordre de grandeur
du nombre d'opérations élémentaires exécutées par l'algorithme lorsque n tend vers
l'infini : de manière asymptotique on caractérisera chaque algorithme par une
fonction de n telle que : n (linéaire) ou n^2 (quadratique) ou 2^n (exponentiel) ou ...
Dans les faits, les complexités en temps les plus courantes, sont, par ordre de

67
complexité croissante : 1 (temps constant), log n, n (linéaire), n log n, n^2
(quadratique), n^3, 2^n (exponentiel) et n! (factorielle).
On utilisera la notation t(n) = O(...) 15 pour exprimer le fait que la complexité en
temps correspond à l'ordre de grandeur du nombre d'opérations élémentaires
exécutées lorsque n tend vers l'infini.
On pourra ainsi écrire que la complexité en temps de tel algorithme est en O(n^2).
Idem pour la complexité « en espace ».

Remarque : Complexité « en moyenne » et « au pire »


Pour faire abstraction des jeux de données effectifs, il existe deux approches
complémentaires :
 considérer parmi toutes les possibilités, le jeu de données le plus
« défavorable » (i.e. celui menant au temps le plus grand) on parle alors de
complexité « au pire » ;
 considérer la moyenne sur l'ensemble de tous les jeux de données possibles
on parle alors de complexité « en moyenne ».
Les deux notions sont pertinentes lorsqu'on s'intéresse à un algorithme : la
complexité en moyenne permet naturellement d'évaluer le comportement ordinaire,
celui qui sera a priori observé sur un grand nombre d'exécutions. La complexité « au
pire » nous renseigne quant à elle sur ce qui peut arriver de pire en termes de
dégradation des performances liée à la nature des données : c'est un élément à
prendre en compte lorsqu'il est nécessaire de garantir un certain niveau de
performance pour chaque exécution, et pas juste en moyenne.

Complément : Lien avec la loi de Moore


Rappel : la loi de Moore (dans sa 2° version de 1975) prédit un doublement à prix
constant du nombre de transistors sur un micro-processeur tous les 2 ans. Couplé
avec l'augmentation des cadences d'horloge et autres améliorations techniques, cette
« loi » s'est traduite dans les faits par un doublement de la vitesse des ordinateurs
tous les 18 mois depuis son énoncé.
Supposons que ce doublement de la vitesse des machines continuera au même
rythme durant la décennie à venir.
La conséquence sur la vitesse des programmes est évidente si on raisonne à
jeu de données identique : tous les programmes pourront s'exécuter ~ 2 fois plus
vite tous les 18 mois, soit ~ 100 fois plus vite au bout de 10 ans (à condition de
changer d'ordinateur bien sûr !)
Mais quelle est son incidence sur la taille des données qu'il est possible de
traiter à temps d'exécution constant ?
Tout dépend de la complexité en temps des algorithmes utilisés.
Avec un algorithme de complexité linéaire, acheter un ordinateur neuf permettra de
traiter des données ~ 2 fois plus grandes tous les 18 mois, et donc des données ~
100 fois plus grandes au bout de 10 ans. Naturellement, si l'algorithme est de
complexité log(n), le gain sera encore plus important. Inversement si la complexité
en temps est quadratique le gain sera de « seulement » ~ 10 fois au bout de 10 ans ;
si elle est exponentielle, ou pire, factorielle, le gain sur 10 ans (ou même 100 ans)
sera minime dans la taille des données qu'il sera possible de traiter en un temps
donné.

15 - La notation « O majuscule » fait partie des notations Bachmann–Landau permettant de caractériser une
fonction par une autre, plus simple, dont le comportement asymptotique est identique. Les autres notations
pertinentes à cet égard sont : o, Ω, ω et Θ qui différent par la manière dont la seconde fonction s'approche de
la première lorsque n tend vers l'infini.

68
Algorithmique, complexité, tris

Autrement dit, la loi de Moore permet de miser à horizon 10 ans sur :


 un facteur 100 dans la vitesse des programmes à taille des données
identique (quelque soit la complexité des algorithmes utilisés) ;
 un facteur pouvant varier de 1 à plusieurs milliers dans la taille des
données pouvant être traités à temps d'exécution identique (selon la
complexité des algorithmes utilisés).
Le 2° point est essentiel de par ses conséquences pratiques : si un problème ne peut
être résolu sur ordinateur que sur des données de petite taille (car le meilleur
algorithme connu est typiquement de complexité exponentielle, ou pire), alors la loi
de Moore ne saurait suffire à progresser rapidement dans la possibilité de traiter des
données de tailles toujours plus grandes seule la découverte d'un meilleur
algorithme permettra le traitement de données de taille significativement plus grande.

Définition : Efficacité d'un algorithme


Par convention, un algorithme est considéré comme « efficace » si sa complexité
en temps est au pire polynomiale16.
On pourra qualifier de « très efficaces » les algorithmes en O(n log n), O(n) et, a
fortiori, ceux en O(log n).

E. Algorithmique, classification des algorithmes, …


Définition : Algorithmique, algorithmie
L'algorithmique (synonyme : algorithmie) est, au sein de l'informatique, la discipline
qui s'intéresse aux algorithmes : quel(s) algorithme(s) permet(tent) de résoudre quel
problème, avec quelle complexité, ...

Classification des algorithmes


Les algorithmes peuvent être classés selon plusieurs critères :
 par nature : séquentiel, parallèle ou distribué
 par famille de problèmes qu'ils résolvent : recherche, tri, parcours, chaînes,
numériques, géométriques, ...
 par mode de fonctionnement : itératif, récursif, force brute, glouton, ...
 …

F. Problématique du tri
Avec la recherche dans une liste ou un tableau, trier le contenu d'une liste ou d'un
tableau est l'une des opérations les plus courantes dans les applications
informatiques.
Il peut s'agir de trier des valeurs numériques par ordre croissant ou décroissant, des
valeurs littérales par ordre lexicocraphique, ou des valeurs de type quelconque, à
condition d'avoir défini une relation d'ordre permettant de répondre à la question :
entre deux valeurs x et y quelconque, est ce que x est inférieur à y ou pas (la relation
d'ordre n'a pas forcément besoin d'être totale) ?

16 - Il s'agit d'une définition à la fois formelle et arbitraire. Elle se révèle en pratique tout à fait pertinente
dans la mesure où la quasi-totalité des algorithmes de complexité polynomiale sont dans les faits en O(n^2)
ou O(n^3), et pas en O(n^1000) !

69
On distingue :
 les cas où il est possible de recopier et/ou dupliquer l'ensemble des données à
trier (si accessibles et pas trop volumineuses) ;
 ceux où il est nécessaire d'opérer sur place (i.e. par permutations successives
de quelques valeurs) tris « en place ».
Pratiquement, sur des données composites (instances de classe par exemple), le tri
se fera suivant un critère défini par le programmeur à partir de tout ou partie des
attributs non-statiques de la classe (cf. Attribut statique p 85).
Aussi, lorsqu'il s'agit d'objets de grande taille, il est essentiel de procéder par
indirection pour éviter de déplacer l'ensemble des données (c'est ce qui se passe
automatiquement en Java via le mécanisme des références qui s'impose au
programmeur dès qu'il manipule autre chose que des types primitifs).

Dans la suite de cette section, on s'intéressera aux différentes manières de trier « en


place » un tableau. La complexité en espace sera la même pour tous ces tris (la
quantité de mémoire nécessaire quand n tend vers l'infini sera de l'ordre de n par
définition de ce qu'est un tri « en place »). La complexité en temps sera étudiée pour
chaque algorithme envisagé.

G. Tri par sélection


Trier le tableau d'entier
12 7 20 25 9 2
Pour obtenir
2 7 9 12 20 25

Tri par sélection : principe


« placer le minimum au début du tableau »
 Trouver le plus petit élément du tableau et le placer au début
 Recommencer avec un tableau contenant les N-1 autres nombres

70
Algorithmique, complexité, tris

Tri par sélection : pseudo-code


Faire pour i variant de 0 à N-2 :
minimum = i
Faire pour j variant de i+1 à N-1 :
si t [j] < t [minimum]
minimum = j
echanger ( t, i, minimum )

Tri par sélection : complexité


Faire N-1 fois :
Faire i fois ( i=1 puis 2 ...puis N-2)
si t [j] < t [minimum] → i comparaisons
minimum = j → 0 à i affectations
échange de t [i] et t[minimum] → 1 échange
soit :
 Toujours n(n-1)/2 comparaisons
au pire en , en moyenne en

 Toujours n-1 échanges ~ 3n affectations


au pire en , en moyenne en

Conclusion
Retenir : tri en

H. Tri par insertion


Trier le tableau d'entier
12 7 20 25 9 2
Pour obtenir
2 7 9 12 20 25

71
Tri par insertion : principe
« placer chaque élément à sa place un par un »
 Placer l'élément t [1] dans le sous-tableau contenant t [0] et t [1].
 Placer t [2] dans { t [0], t [1], t [2] }
 Recommencer à placer t [i] dans le sous-tableau de taille i+1

Tri par insertion : pseudo-code


Faire pour i variant de 1 à N-1 :
aInserer = t[i]
Faire pour j de i-1 à 0 : // Variante
si aInserer < t[j] j = i-1;
// on décale Faire tant que j >= 0 et alnserer <
t[j+1] = t[j] t[j]
sinon // on décale
break // on sort... t[j+1] = t[j]
j--;
t[j+1] = aInserer // on place l'élément

Tri par insertion : complexité


Faire N-1 fois :
x = t [i+1] → 1 affectation
i nombres déjà triés :
Faire tant que x < t [j] → 0 à i comparaisons
t [j+1] = t [j] → 0 à i affectations
Mettre x dans la place laissée vacante.
t [j+1] = x → 1 affectation
Soit :
 Entre n-1 et n(n-1)/2 comparaisons
au pire en ,, en moyenne en

 Entre 2n et n(n-1)/2 affectations


au pire en , en moyenne en

Conclusion
Retenir : tri en

I. Tri bulle
Trier le tableau d'entier
12 7 20 25 9 2
Pour obtenir
2 7 9 12 20 25

72
Algorithmique, complexité, tris

Tri bulle : principe


« Faire remonter les éléments légers »
 A partir de la fin du tableau prendre 2 éléments consécutifs, Les échanger s'ils
ne sont pas dans le bon ordre
 Recommencer...
 Le 1er élément est alors le plus petit.
Recommencer avec un tableau contenant les N-1 autres nombres

Tri bulle : pseudo-code


Faire pour i variant de 0 à N-2 :
Faire pour j variant de N-1 à i+1
si t [j] < t [j-1]
echanger (t , j-1 , j)

Tri bulle : complexité


Faire N-2 fois :
Faire i fois
si t[j] < t[j-1] → i comparaisons
echanger ( t, j-1, j ) → 0 à i échanges
Soit :
 Toujours n(n-1)/2 comparaisons
au pire en , en moyenne en

 Entre 0 et n(n-1)/2 échanges


au pire en , en moyenne en

Conclusion
Retenir : tri en

73
J. Tri rapide
Trier le tableau d'entier
12 7 20 25 9 2
Pour obtenir
2 7 9 12 20 25

Tri rapide : principe


« diviser pour ... aller plus vite »
 Couper le tableau en deux tableaux dont les K éléments du 1er sont tous plus
petits que ceux du second
 Garder le Kième élément (bien placé)
 Recommencer avec les 2 tableaux de taille K-1 et N-K

Tri rapide : pseudo-code


Faire fois : "couper le tableau " :
Pour chaque tableau (produit d'un découpage précédent) de taille M entre début et
fin :
Considérer l'élément t[début] =pivot
Faire varier k entre début et fin et déplacer les éléments t[i] pour que :
t[i] <= pivot pour i < k et
t[i] > pivot pour i > k et
t[k] = pivot = t[début]
Récursivement, relancer le découpage entre début et k-1, et entre k+1 et fin (si
possible)
Exécuter triRapide(t, 0, N-1)

74
Algorithmique, complexité, tris

triRapide(t, debut, fin)


Si debut >= fin
retourner //c'est fini
Sinon
k = partitionner (t, debut, fin)
triRapide (t, debut, k-1) //partie gauche
triRapide (t, k+1 , fin) //partie droite

Méthode partitionner(t, debut, fin) : Version 1


partitionner(t, debut , fin)
pivot = t [debut] et g = debut+1 et d = fin;
faire tant que g < d //les indices ne se croisent pas
tant que t[d] > pivot d--
tant que t[g] <= pivot et g<d g++
si g < d // on n'a pas fini et il faut échanger
echanger( t , g , d) // n comparaisons et 0 à n échanges
// fin de la boucle, placer le pivot
Si pivot > t[d]
echanger( t , debut , d ) // 1 échange
retourner d

Méthode partitionner(t, debut, fin) : Version 2


partitionner(t, debut , fin)
pivot = t [debut] et g = debut+1 et d = fin;
faire tant que g<=d // les indices ne se croisent pas
si t[g] <= pivot g++
sinon
si t[d] < pivot
echanger( t , g, d) // n comparaisons et 0 à n échanges
sinon
d--
// fin de la boucle, placer le pivot
echanger( t , debut , d ) // 1 échange
retourner d

Méthode partitionner(t, debut, fin) : Version 3


partitionner(t, debut , fin)
pivot = t [debut] et placePivot = debut
faire i de debut+1 à fin
si t [i] < pivot // le pivot doit être décalé
placePivot++
echanger( t , placePivot , i ) // n comparaisons et 0 à n échanges
// fin de la boucle, placer le pivot sur placePivot
echanger( t, debut , placePivot ) // 1 échange
retourner placePivot

75
Tri rapide : complexité

Selon la taille des découpages, le nombre d'étapes varie entre et , le nombre


d'opérations peut donc varier entre et
 De n.log(n) à (n+2)(n+1)/2 comparaisons
au pire en ,
en moyenne en
 Entre 1 et n échanges
au pire en , en moyenne en

Conclusion
Retenir : tri en

76
Algorithmique, complexité, tris

K. Complexité des algorithmes de tri


Comparaisons Affectations

Pire Moy. Pire Moy.

Sélection

Insertion

Bulle

Rapide

A retenir au pire en moy.

Sélection

Insertion

Bulle

Rapide

77
Programmation par
VI -

objets
VI

Vocabulaire (classe, instance, objet, ...) 79


Classes, instances, ... 80
This 84
Static 85
Visibilité 88
Types énumérés 89

A. Vocabulaire (classe, instance, objet, ...)


Définitions :
 Classe = modèle d'objets ayant les mêmes types de propriétés et de
comportements
 Objet = instance d'une classe (possède ses propres valeurs pour chaque
attribut)
 Instancier une classe = créer une nouvel objet (instance) de cette classe

Un premier exemple : la classe Tour

79
Un autre exemple : la classe PolygoneRegulier

B. Classes, instances, ...


1. Classe
Classe = modèle permettant :
1/ de regrouper des données de types distincts attribut(s)
+
2/ de définir des comportements spécifiques méthode(s)
+
3/ de spécifier comment créer des instances de la classe constructeur(s)

 Les attributs (état) contiennent les données propres à l'objet


 Les méthodes (comportement) sont les opérations applicables à l'objet
 Invoquer le constructeur crée un nouveau objet
 La classe peut aussi posséder des attributs et des méthodes partagées par
toutes ses instances attributs et méthodes « statiques » (voir plus loin)

Exemple
// Définition de la classe Cercle :
class Cercle {
// I : définition des attributs :
double rayon=0;
// II : définition des constructeurs :
// NOTA-BENE : constructeur par défaut si non défini
// III : définition des méthodes :
double calculerSurface() {
return Math.PI*rayon*rayon;
}
}

// Utilisation de cette classe


// (ailleurs dans le programme) :
Cercle c = new Cercle();
// ...
c.rayon = 8 ;
double surface = c.calculerSurface();

80
Programmation par objets

NOTA-BENE : la syntaxe pour désigner un attribut ou une méthode d'une classe varie
selon qu'on se trouve dans le bloc correspondant à la définition de la classe, ou pas :
 accès direct aux attributs et méthodes (non-statiques) de l'instance courante
depuis l'intérieur de la classe
 accès via l'opérateur . (« point ») à l'extérieur de la classe

2. Attributs
Attributs = données propres à l'objet (sauf cas particulier des attributs statiques,
voir plus loin)

Un attribut peut-être de type primitif ou référence

Exemple :

// Une classe avec trois attributs :


class Salarie {
String nom ;
int age ;
double salaire ;
}

// Exemples d'accès aux attributs :


// ( on suppose x1 et x2 correctement déclarés
// et initialisés, voir ci-après )

System.out.print( x1.nom );

if ( x2.age > 62 ) { … }

NOTA-BENE : un attribut peut-être déclaré constant avec le mot-clé final

3. Méthodes
Méthodes = opérations pouvant s'appliquer aux instances de la classe (sauf cas
particulier des méthodes statiques, voir plus loin)

Exemple de méthodes dans la classe Salarie :

void vieillir() { age ++ ; }


// utilisation : x1.vieillir () ;

boolean estMajeur() { return age>=18 ; }


// utilisation : if(x2.estMajeur ()) { ... }

void modifSalaire(double d) { salaire=d ; }


// utilisation : x2.modifSalaire(4100.0) ;

4. Constructeur
Constructeur : permet de spécifier comment créer des instances de la classe
NOTA-BENE : la destruction des instances se fait automatiquement par le « ramasse
miettes » (garbage collector ou GC) qui élimine régulièrement tous les objets non-
référencés

81
Exemple de constructeur pour la classe Salarie :

public Salarie (String n, int a, double s) {


nom = n ;
age = a;
salaire = s;
}
// exemple d'utilisation :
Salarie x1 = new Salarie("Léa Duroc", 40, 5200.0);
Salarie x2 = new Salarie("MisterX", 35, 4000);
x2 = x1;
// le GC va détruire l'instance correspondant à "MisterX"
// qui n'est plus référencée suite à l'affectation ci-dessus.

IMPORTANT :
 jamais de type de retour lors de sa déclaration (sinon Java le considère comme
une méthode et pas comme un constructeur)
 nom = nom de la classe

Complément
 Une classe peut avoir plusieurs constructeurs à condition que leurs signatures
soient différentes (il ne peut pas y avoir deux constructeurs pour une même
classe avec exactement la même liste de paramètres).
 Un constructeur fréquemment utile prend pour seul paramètre une instance de
la classe afin de s'en servir comme modèle : on appelle un tel constructeur «
constructeur par recopie ». Dans son corps, on pourra recopier tous les
attributs de l'instance passée en paramètre, ou seulement certains en fonctions
des spécificités de la classe en question.

5. Instanciation (mot-clé : new)


Instancier une classe = créer un nouvel objet de cette classe
L'instanciation se fait par l'utilisation du mot-clé new :
MaClasse objetDeMaClasse = new MaClasse(..) ;
L'opérateur new crée un nouvel objet c'est à dire :
- appelle un constructeur
- alloue la zone mémoire nécessaire
- retourne la « référence » correspondant à cette zone mémoire

Attention
Comme pour les tableaux, on peut séparer
1. déclaration = typage
2. création = allocation mémoire
(voir exemple ci-après)

NOTA-BENE : les références non encore initialisées par new ont pour valeur null
lorsqu'elles sont dans un tableau ou dans une classe (attribut) ; dans les autres cas
(variables locales dans une fonction) elles n'ont pas de valeur du tout (erreur de
compilation)

82
Programmation par objets

Exemple
Salarie leDG ;
la variable leDG a été déclarée et typée (elle pourra stocker des références à des
instances de la classe Salarie)

// ....
leDG = new Salarie("Edgar Legrand", 53, 9500);
Un espace mémoire référencé par la variable leDG a été alloué et initialisé : il
contient l'objet créé, c'est à dire
1. une référence à une String contenant "Edgar Legrand "
2. un entier égal à 53
3. un double égal à 9500.0

6. Tableau d'objets
ATTENTION : un tableau d'objets est en fait un tableau de références vers objet :

Salarie[] tabS = new Salarie[90];


// tabS[0] ... tabS[89] valent tous null

Il faut donc créer les objets eux-mêmes (après avoir créer le tableau) :

tabS[0] = new Salarie("Edgar Legrand", 53, 9500);


tabS[1] = new Salarie("Léa Duroc", 40, 5200.0);
tabS[2] = new Salarie("MisterX", 35, 4000);
// ....

RAPPEL : l'opérateur d'affectation (=) entre références ne copie que la référence, pas
l'espace mémoire référencé :

Salarie s = new Salarie("Yves Zay", 61, 4700.0);


tabS[3] = s;
tabS[4] = s.clone();
tabS[5] = tabS[3] ;
s.age++ ; // modifie s et tabS[3] et tabS[5] mais pas tabS[4]
tabS[5].age++ ; // idem : s.age vaut désormais 63

7. L'instruction instanceof
L'opérateur instanceof permet de tester si un objet est, ou n'est pas, instance d'une
classe donnée.
Ainsi, r instanceof C vaut :
- true si r est une référence à un objet pouvant être considéré comme une
instance de la classe C
- false sinon (y compris si r == null)

Remarque
instanceof permet aussi tester si un objet est, ou n'est pas, instance d'une classe
qui implante une « interface » donnée (cf. Interfaces p 139).

83
8. Destructeur
Destructeur : permet de définir un comportement lié à la destruction d'une instance
 Si besoin, ajouter un destructeur à la classe en suivant la syntaxe :
protected void finalize() {...}
 Le code sera appelé automatiquement par le « ramasse-miettes »
(garbage collector ou GC) juste avant de supprimer chaque objet de la classe
 Sauf cas très particuliers, le destructeur n'est jamais invoqué explicitement
dans un programme
 Utile en particulier pour « fermer » proprement des fichiers associés à une
instance

Remarque
Le destructeur est appelé une seule fois par instance quoi qu'il arrive (donc pas ré-
appelée par le GC si appelé « à la main » avant)

C. This
1. this(...) dans un constructeur
Le mot-clé « this » suivi de parenthèses permet d'invoquer un autre constructeur de
la classe :

Salarie(String n, int a, double s) {


nom = n;
age = a;
salaire = s;
}
Salarie (String n, int a) {
this(n, a, 0.0);
}
Salarie (String n) {
this(n, 0);
}

2. this comme référence


Le mot-clé « this » en tant que référence désigne l'instance courante :

void changerAge(int age) {


this.age = age;
}

this permet d'accéder à l'attribut « age » qui est masqué dans la méthode
changerAge() par le paramètre de même nom

Remarque
this étant par définition une référence sur l'instance courante, on ne peut utiliser
this que là où une instance courante existe, c'est à dire : uniquement lors de
l'écriture du corps d'une méthode non-statique (cf. Mot-clé static p 85).

Il est fréquent d'utiliser la référence « this » comme paramètre pour désigner

84
Programmation par objets

l'instance courante lors d'un appel de méthode :


class Salarie {
// ....
public void dessinerDans ( Fenetre f ) {
String fichierImage = "images/ " + age%10 + ".ico";
afficher(f, fichierImage);
}
}

class Fenetre {
// ....
public void montrerImage (Salarie untel) {
untel.dessinerDans(this);
}
}

cette utilisation de this en tant que référence sur l'instance courante est
essentielle : c'est le seul moyen de se passer « soi-même» en paramètre quand on
écrit le code d'une méthode.

D. Static
1. Mot-clé static
Mot-clef static : indique que ce qui suit est lié à la classe en tant que telle plutôt qu'à
l'une de ses instances.
On peut donner le caractère « statique » à :
- un attribut (y compris un attribut constant) ;
- un bloc d'instruction (initialisateur) ;
- une méthode.

2. Attribut statique
Attribut statique : attribut lié à la classe, sa valeur est partagée par toutes les
instances de la classe (il n'existe qu'une seule zone en mémoire pour stocker l'unique
valeur commune à la classe).
Synonyme : attribut de classe

Exemple :

class Cercle {
double rayon;
Color couleur;
// rayon et couleur : attributs ordinaires
// (une valeur par instance)

static int nbCercles=0;


// attribut « de classe » (une valeur unique pour la classe)
// tous les Cercles partageront l'attribut « nbCercles »

public Cercle (double r) {


rayon = r;
nbCercles++;
couleur = affecterCouleurSelonNumero(nbCercles);
}
}

85
NOTA-BENE : un attribut statique peut-être déclaré constant avec le mot-clé final
(on parle alors de « constante de classe »), exemple :

class Direction {
public static final int NORD=1 ;
public static final int EST=2 ;
public static final int SUD=3 ;
public static final int OUEST=4 ;
}
// Utilisation :
// monRobot.tournerVers(Direction.EST) ;

3. Initialiseur statique
Initialiseur statique = bloc d'instructions exécuté une seule fois, lors du chargement
de la classe dans la machine virtuelle Java (au lancement du programme, donc bien
avant toute création d'instance).

Intérêt : permet d'initialiser une variable statique à l'aide de plusieurs instructions,


exemple :

class Cercle {
double rayon;
static int nbCercles=0;

static int [] tComp; // attribut de classe non initialisé !


static Color couleur; // idem

static { // initialiseur statique


tComp = new int [3] ;
for (int comp : tComp) {
comp = 100+100*Math.random() ;
}
// initialise couleur à une valeur aléatoire unique et
// ni trop claire ni trop sombre ( 100<=comp<200 )
couleur = new Color(tComp[0], tComp[1], tComp[2]);
}

// .…
}

86
Programmation par objets

4. Méthode statique
Méthode statique : méthode s'appliquant à la classe en tant que telle, et pas à une
instance en particulier

Synonyme : méthode de classe

Equivalent des fonctions « ordinaires » des langages non-objet

Exemples :

Math.log(double) // déclarée static dans Math

static void main(String[] args) {


// fonction principale
// (à déclarer impérativement comme static)
}

class Cercle {
static private int epaisseur=1;
static public void modifierEpaisseurDuTrait(int e) {
epaisseur = e;
}
}

5. Appel de méthode statique


Appel depuis une autre méthode de la même classe :

class Cercle {
// ...
public void bidule () {
modifierEpaisseurDuTrait(2) ;
}
}

Appel depuis l'extérieur de la classe :

Cercle.modifierEpaisseurDuTrait(2);
// il faut préfixer avec le nom de la classe

Remarque
Le même principe s'applique pour l'accès aux attributs statiques.

87
6. Static or not static ?

E. Visibilité
Recommandations pour l'usage des mots clés : public,
private, ...
Obligatoire :
- la classe contenant la fonction main doit être publique
- un fichier .java ne peut contenir qu'une classe publique (au maximum)
Conseillé :
- les attributs sont généralement privés si besoin, créer des « accesseurs »
(méthodes publiques qui renvoient ou modifient la valeur d'un attribut privé)
- sauf cas très particuliers : les constructeurs sont publics
- les méthodes auxiliaires purement internes à une classe sont évidemment privées
- les méthodes dialoguant avec d'autres classes seront publiques
Voir plus loin pour détails sur public / private / protected / ... (cf. Niveaux de visibilité
p 127)

Exemple
class Contact {
// Attributs -> private (ou protected) :
private String nom;
private String mail;
private long tel ;

// Constructeur(s) -> public :


public Contact (String n, String m, long t) {
nom = n ; mail = m ; tel = t;
normaliser();
}

// Méthode(s) : selon leur nature

// accesseur -> public :

88
Programmation par objets

public String renvoieNom() { return nom; }

// service rendu par la classe -> public :


public void envoyerMail(String s) { ... }

// Méthode(s) auxiliaire(s), à usage interne


// -> private (ou protected) :
private void normaliser() { ... }
}

F. Types énumérés
Mot-clef enum au lieu de class
Equivaut à une classe ayant un nombre FINI d'instances, toutes prédéfinies
Syntaxe spécifique, peut servir dans un switch voir types énumérés « simples » (cf.
Types énumérés simples p 55)

Exemple d'énumération « simple » :

enum Reponse {OUI, NON, PEUT_ETRE}


//...
Reponse r1 = Reponse.OUI ;

Intérêt double : lisibilité du code + fiabilité (impossible d'affecter une valeur non
prévue)

Types énumérés « élaborés »


Un enum étant une classe, il peut avoir des attributs et des méthodes
Exemple :

enum Jeune {
BEBE ("Bebe", 0, 3),
ENFANT ("Enfant", 3, 12),
ADO ("Adolescent", 12, 18) ;

private String type ;


private int ageMin ;
private int ageMax ;

Jeune (String t, int aMin, int aMax) {


type = t ; ageMin = aMin ; ageMax = aMax ;
}

public String renvoieType () { return type ; }


public String renvoieAgeMin () { return ageMin ; }
public String renvoieAgeMax () { return ageMax ; }
}

89
VII - Exceptions

VII

Principe des exceptions 91


Gestion des erreurs 91
Traitement des exceptions 93
Nature des exceptions 93
Catégories d'exceptions 94
Exceptions contrôlées ou non 94
Types d'exception usuels 95
Lancement d'exception 95
Création de nouveaux types d'exception 96
Clause throws 96
Assertions 97

A. Principe des exceptions


Mécanisme pour traiter les anomalies se produisant à l'exécution (division entière par
zéro, référence nulle, fichier inacessible, ...)
Principe fondamental séparer détection et traitement des anomalies :
 signaler tout problème dès sa détection
 mais regrouper le traitement des problèmes ailleurs, en fonction de leur
type

B. Gestion des erreurs


Exemple
Que fait-cette fonction ?

static void divTab(int [] tab) {


Scanner sc = new Scanner(System.in);
int index = sc.nextInt();
int div = tab[index];
for (int j=0 ; j<tab.length ; j++) {
tab[j] /= div;
}
}

91
Exemple
Gestion des erreurs sans utiliser d'exceptions :

static void divTab2(int [] tab) {


if( tab == null ) {
System.err.println("tab==null")
}
else {
Scanner sc = new Scanner(System.in);
int index = sc.nextInt();
if( index<0 || index>=tab.length ) {
System.err.println("index incorrect");
}
else {
int div = tab[index];
if( div == 0 ) {
System.err.println("diviseur nul");
}
else {
for (int j=0 ; j<tab.length ; j++) {
tab[j] /= div;
}
}
}
}
}

Exemple
Gestion des erreurs en utilisant des exceptions :

static void divTab3(int[] tab) {


try {
Scanner sc = new Scanner(System.in);
int index = sc.nextInt();
int div = tab[index];
for (int j = 0 ; j < tab.length ; j++) {
tab[j] /= div;
}
} catch (NullPointerException e) {
System.err.println("tab==null");
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("index incorrect");
} catch (ArithmeticException e) {
System.err.println("diviseur nul");
} finally { // on passe toujours ici }
}

NOTA-BENE :
 toute exception générée provoque l'arrêt brutal du programme ;
 pour éviter cela, prévoir la capture et le traitement des exceptions ;
 mots-clefs : try, catch et finally

Conseil
1. Eviter de créer un bloc try{...} catch ... séparé autour de chaque
instruction pouvant poser problème (car cela conduirait à un code pas

92
Exceptions

tellement plus clair qu'avec des if/else imbriqués) faire plutôt un bloc
try{...} catch ... le plus gros possible.
2. Ordonner les clauses catch du plus spécifique (en premier) au plus général
(vers la fin), avec si besoin une clause finally à la fin.

C. Traitement des exceptions


1. Si une exception est générée dans le bloc try { ... } :
i. l'exécution s'arrête là (on n'exécute pas les instructions du bloc try qui
suivent l'instruction à l'origine de l'erreur)
ii. on saute dans le premier gestionnaire catch compatible avec cette
exception (i.e. attrapant exactement le type d'exception généré, ou exception «
ancêtre » au sens de l'héritage)
iii. on exécute les instructions du bloc catch
iv. puis on continue APRÈS l'ensemble try {...} catch (...) {...}
2. Si pas de catch adéquat, on remonte au try « englobant » le plus proche, on y
cherche un catch correspondant, etc... avec possibilité de remonter ainsi
jusqu'à la fonction main
3. Si pas non plus de catch adéquat au niveau de la la fonction main arrêt
complet du programme
4. Le bloc finally est facultatif : il est exécuté à la fin du bloc try quoiqu'il arrive
(fin normale, sortie par return, sortie après catch, ou avec exception non
traitée)

D. Nature des exceptions


Définition
Une exception est une instance de la classe Exception ou d'une de ses sous-classes

Divers types d'exceptions (classes) sont prédéfinies en Java, et susceptibles d'être


générées automatiquement à l'exécution, par exemple :
 division par zéro (entre entiers) ArithmeticException
 indice de tableaux hors limites ArrayIndexOutOfBoundsException
 tentative « d'utilisation » d'une référence nulle NullPointerException
 fichier inaccessible FileNotFoundException
 tentative de lire au delà d'une fin de fichier EOFException
 …

NOTA-BENE : on peut aussi définir de nouveaux types d'exceptions (cf. Création de


nouveaux types d'exception p 96)

Rappel
Lorsqu'une variable c1 de type C (une classe quelconque) contient une référence
nulle, les écritures suivantes sont interdites (elles génèrent le lancement d'une
NullPointerException) :
 int x = c1.a ; // tentative d'accès à l'attribut a de la classe C ;
 c1.m() ; // tentative d'accès à la méthode m de la classe C ;

De même lorsqu'une variable t de type tableau contient une référence nulle, il est
interdit d'écrire :

93
 int l = t.length ; // tentative d'accès à la taille du tableau ;
 Arrays.sort(t) ; // cette méthode interdit les références nulles en
paramètre (cf. doc. de la classe prédéfinie Arrays)
Pour mémoire, une variable dont le type n'est pas un type primitif contient une
référence nulle tant que l'instance (ou le tableau) n'a pas été « créée » par new. Elle
peut aussi contenir une référence nulle si on lui affecte explicitement la valeur null
(par exemple pour provoquer la destruction de l'instance précédemment référencée
par cette variable).

E. Catégories d'exceptions
Classe mère : Throwable
Erreurs « système » : classe Error (dérivée de Throwable)
Autres anomalies : classe Exception (dérivée de Throwable) et ses sous-classes
Cas particuliers : classe RuntimeException (dérivée de Exception) et ses sous-
classes exceptions « non contrôlées » (voir plus loin)
Fonctionnement identique pour les erreurs et les exceptions :
 NomException(String) : constructeur avec message explicatif sur la cause
de l'exception
 String getMessage() : renvoie le message explicatif en question
 String toString() : renvoie le type de l'exception (nom de sa classe) et le
message explicatif
 void printStackTrace() : affiche la pile d'appel jusqu'au point de lancement
de l'exception

Complément : la classe Error (et les classes qui en dérivent)


La classe Error est réservée aux erreurs décelées par la machine virtuelle lors de son
fonctionnement « normal » consistant à interpréter du bytecode.
Exemple : la sous-classe OutOfMemoryError est lancée par la machine virtuelle quand
l'ordinateur manque de mémoire pour continuer l'exécution d'un programme.
Dans un code Java ordinaire on ne doit jamais instancier la classe Error et ses sous-
classes (on doit instancier et lancer uniquement des exceptions).

F. Exceptions contrôlées ou non


Les exceptions de type RuntimeException et ses sous-classes (par exemple
ArithmeticException, NullPointerException, ...) sont dites « non
contrôlées » (ou « unchecked »)
Java n'impose pas leur prise en compte (par défaut : arrêt du programme avec
message d'erreur standard)
Toutes les autres exceptions sont dites « contrôlées » (ou « checked »)
Java impose qu'elles soient prises en compte lors de l'écriture du programme, les
instructions susceptibles d'en lancer doivent donc se situer :
 soit dans un bloc try{} avec un catch() correspondant au type d'exception en
question ;
 soit dans une méthode dotée de la clause throws (cf. Clause throws p 96)
adéquate.

94
Exceptions

G. Types d'exception usuels

Remarque
Le diagramme ci-dessus présente quelques une des erreurs et exceptions les plus
courantes prédéfinies en Java.
Dans le diagramme chaque rectangle correspond à une classe et les flèches pointent
vers la classe « mère » au sens de l'héritage (cf. Héritage p 129).

H. Lancement d'exception
Possibilité de lancer « manuellement des exceptions » (en plus de celles générées
automatiquement)
Mot-clef : throw
Exemple :
if (test_anomalie) {
throw new Exception("blabla");
}
if (autre_test) {
throw new IllegalArgumentException("bla");
}

Effet : interrompt immédiatement le cours normal du programme pour rechercher un


gestionnaire adéquat englobant (cf. Traitement des exceptions p 93)

95
Conseil
Lancer de préférence une exception d'un type spécifique à l'anomalie (et contenant un
texte précisant la nature de l'anomalie).

I. Création de nouveaux types d'exception


Java permet de définir de nouveaux types d'exception : il suffit de créer une sous-
classe de Exception ou de RuntimeException (ou d'une de leurs sous-classes
prédéfinies) :

class MonException extends Exception {


MonException(String s) {
super(s);
//…
}
//…
}

// ... puis plus loin :


if (test_anomalie) {
throw new MonException("commentaire");
}

J. Clause throws
Chaque méthode doit utiliser une clause « throws » pour déclarer toutes les
exceptions « contrôlées » :
1. qu'elle envoie elle-même (par throw)
2. qu'elle « laisse passer » (i.e. émises par des méthodes appelées, et non
traitées localement par un try/catch)
Exemple :

// ...
void lire() throws MonException, IOException {
// lancement explicite d'une exception si pb. :
if (testAnomalie() == true) {
throw new MonException("bla");
}
// appel d'une méthode susceptible de générer
// une exception contrôlée de type IOException :
int car = System.in.read();
}

Conséquence devoir de capture : si une méthode m1 appelle une méthode m2


susceptible de lancer une exception contrôlée (donc avec une clause throws dans la
définition de m2), alors m1 doit impérativement :
- soit invoquer m2 dans un bloc try/catch permettant de capturer cette exception
- soit déclarer elle aussi cette exception dans une clause throws

Rappel
Toutes les exceptions sont « contrôlées » sauf celle dérivant de RuntimeException.

96
Exceptions

K. Assertions
Le mot-clé assert donne accès à un mécanisme de nature assez proche des
exceptions : les assertions.
Il s'agit de positionner dans un code java des lignes telles que :

assert r != null ;
assert t >= 0 : "t doit être positif ou nul !"

qui vont interrompre l'exécution du programme lorsque la condition est fausse – sous
réserve que le programme soit bien lancé dans un mode où les assertions sont
vérifiées. En effet, la vérification des assertions n'est pas le mode par défaut : pour
que les assertions soient vérifiées il faut lancer la machine virtuelle (le programme
java) avec l'option -enableassertions (ou -ea), sinon elles sont toutes ignorées afin
de ne pas ralentir l'exécution du code.
Comparé aux exceptions, il faut savoir que les assertions :
 sont destinées à effecteur des vérifications « de routine » de nature à détecter
des bugs de programmation : il ne faut surtout pas les utiliser pour gérer autre
chose, comme par exemple des erreurs de saisie de l'utilisateur, un fichier
inaccessible, ... toutes les anomalies qui ne sont pas liées à une mauvaise
écriture du code doivent être gérées par des exceptions et pas des assertions ;
 sont conçues pour faciliter la mise au point des programmes (c'est pourquoi le
dispositif est débrayable : une fois le programme débuggé on peut choisir de
supprimer la vérification des assertions pour privilégier la vitesse sur la
fiabilité) ;
 sont nettement plus simples à utiliser ;
 sont inactivées par défaut.

Remarque
Il est parfaitement possible de se passer complétement des assertions et utiliser
uniquement les exceptions (y compris pour gérer la détection des bugs). L'inverse est
faux : les exceptions sont un dispositif essentiel de Java qu'il est impératif de
connaître et maîtriser – ne serait-ce que pour pouvoir utiliser l'ensemble des classes
prédéfinies – on ne saurait donc s'en passer et n'utiliser que des assertions.

97
VIII - Entrées - Sorties

VIII

Catégories de flux et classes à connaître 99


Fiches pratiques (exemples) 101
Autres classes à connaître 107

A. Catégories de flux et classes à connaître


1. Les 4 grandes catégories de flux abstraits
Quatre classes « abstraites » (non instanciables), très générales, pour prendre en
charge : lecture / écriture et mode binaire / caractères :
- en mode binaire classes abstraites InputStream et OutputStream
- en mode caractères classes abstraites Reader et Writer
Ces classes fournissent des méthodes de « bas niveaux » toujours disponibles :
1. en mode lecture :
- int read() : prochain élément du flux (ou -1 si « fin de flux »)
- int read(byte[] buf) pour InputStream et int read(char[] buf) pour
Reader
- long skip(long nb) : saute nb éléments
- void close()
2. en mode écriture :
- void write(int c)
- void write (byte[] / char[] buf)
- pour Writer : void write(String s)
- void flush()
- void close()

Remarque
En tant que « classes abstraites (cf. Classe abstraite p 133) », ces classes servent de
modèles aux classes qui suivent ; toutes ces méthodes seront donc disponibles par la
suite dès lors qu'on voudra lire/écrire des données très élémentaires (de nature
caractères ou octets). Pour lire des données de nature différentes (chaînes de
caractères, nombres, instance de classes, ...) il conviendra d'utiliser d'autres classes
de plus haut niveau (voir ci-après).

99
Attention
 Les méthodes read() ci-dessus sont « bloquantes » : si il n'y a rien à lire sans
que l'on soit en fin de fichier alors le programme se bloque dans l'attente d'un
prochain octet ou caractère (cela ne peut pas arriver lors d'une lecture de
fichier sur disque dur mais peut survenir dans le cas d'une lecture sur le clavier
ou sur une connexion réseau), auquel cas le prochain octet ou caractère sera
automatiquement détecté et débloquera le read(), et le programme.
 Les méthodes int read(byte[] buf) et int read(chat[] buf) lisent au
maximum buf.length octets ou caractères, et retournent le nombre
d'éléments lus, ou -1 si fin de flux.

2. Principaux flux « concrets »

Quatorze classes de « bas niveau » déclinent les quatre classes précédentes selon
l'origine ou la destination des données :
 lecture/écriture (séquentielle) dans fichiers :
- en mode binaire : FileInputStream et FileOutputStream
- en mode caractères : FileReader et FileWriter
NOTA-BENE : nom du fichier en paramètre du constructeur
 lecture/écriture dans tableau en mémoire :
- en mode binaire : ByteArrayInput(/Output)Stream
- en mode caractères : CharArrayReader et CharArrayWriter
NOTA-BENE : tableau en paramètre du constructeur
 lecture/écriture dans une chaîne :
- en mode caractères : StringReader et StringWriter
NOTA-BENE : chaîne en paramètre du constructeur
 enchaînements de flux (« pipes ») :
- en mode binaire : PipedInputStream et PipedOutputstream
- en mode caractères : PipedReader et PipedWriter

100
Entrées - Sorties

3. Conversions pour flux binaire


Pour lire/écrire autre chose que des octets ou des tableaux d'octets, on utilise
des classes de plus haut niveau (classes qui fournissent des méthodes plus puissantes
que celles vues précédemment) :
1. Pour lire/écrire des types primitifs sous forme binaire
classes DataInputStream / DataOutputStream :
- création à partir d'un flux d'octets : new
DataOutputStream(outStream) ...
- méthodes de lecture pour les types de base : readFloat(),
readInt(),...
et idem en écriture : writeFloat(x), writeInt(i),...
2. Pour lire/écrire des objets sous forme binaire
classes ObjectInputStream / ObjectOutputStream :
- création à partir d'un flux d'octets : new ObjectOutputStream(outStream)
...
- mêmes méthodes que DataXXXStream + Object readObject() // (resp.
writeObject(o))
- les objets doivent être d'une classe implantant l'interface Serializable (cf.
Interfaces Serializable, Externalizable et mot-clé transient p 143)

4. Autres conversions de flux


 Flux « avec tampon » (pour éviter des accès disque ou réseau à chaque
lecture/écriture) :
classes BufferedInputStream / BufferedOutputStream
classes BufferedReader / BufferredWriter
 Flux pour écriture formatée en mode texte (comme pratiqué sur System.out) :
classe PrintWriter
fournit les méthodes : print(), println(), printf() ...
 Flux compressés : paquetage java.util.zip
classes ZipInputStream / ZipOutputStream
 Conversion flux octets / flux caractères :
classes InputStreamReader / OutputStreamWriter

B. Fiches pratiques (exemples)


1. En pratique : écriture d'un fichier « texte »
1. Importer les classes nécessaires : import java.io.*;
2. Ouvrir un flux de caractères vers un fichier :
PrintWriter out = new PrintWriter("nomFichier");
idem en mode « concaténation » :
PrintWriter out = new PrintWriter(new
FileOutputStream("nomFichier", true));
idem en mode « auto-flush » (sans concaténation) :
PrintWriter out = new PrintWriter("nomFichier", true);
3. Ecrire les caractères et/ou chaînes de caractères sur ce flux :
out.print(ch); // avec ch : char ou String
out.println(ch); // avec ch : char ou String
4. Fermeture du flux : out.close();
Remarque : chaque étape (sauf l'import) est susceptible de lancer une IOException
donc mettre les instructions à risque dans un bloc try/catch (ou bien, utiliser une
clause throws)

101
Exemple : Ecriture de deux lignes de texte dans un
fichier
import java.io.*;

// …
double x = 5.72 , y = -1.5;
// …
try {
PrintWriter out = new PrintWriter("f.txt");
out.println("x vaut : " + x);
out.println("y vaut : " + y);
out.close();
}
catch (FileNotFoundException e) {
System.err.println("f.txt ne peut pas être ouvert");
}
catch (IOException e) {
System.err.println("erreur d'entrée-sortie");
}

Complément : Les méthodes close() et flush()


Dans l'exemple ci-dessus, il ne faut pas oublier le out.close() sinon les caractères
risquent de ne pas être physiquement écrits sur le fichier – par exemple si le
programme a un bug et plante peu après la série de print().
Il faut en effet se souvenir que les écritures sur disque dur ne se font ni
instantanément ni de manière synchrone avec les instructions de type print().
Pour des raisons d'efficacité, les lectures et écritures sont généralement
« bufférisées » à au moins un niveau parmi machine virtuelle Java, système
d'exploitation et/ou contrôleur du disque.
Seul un appel à flush() ou close() garantit que les données précédemment
bufferisées au niveau de la machine virtuelle ont bien été transmises au système
d'exploitation et que ce dernier a reçu l'ordre de les inscrire sans délais sur fichier (ce
qui ne garantit pas formellement que l'écriture aura bien lieu mais en pratique cela
conduit à une écriture immédiate sauf soucis au niveau du matériel).
REMARQUE : lors de la création d'un PrintWriter on peut demander via l'option «
auto-flush » à ce qu'un appel à flush() soit systématiquement exécuté après chaque
appel à println(), printf() ou format().
Aussi, l'effet de out.close() est multiple :
 il exécute flush()sur le flux out ;
 puis libère les ressources allouées au niveau de la machine virtuelle et du
système d'exploitation.
NOTA-BENE : sauf terminaison prématurée du programme, tous les flux ouverts sont
automatiquement fermées à la fin de chaque programme : le close() n'est donc pas
strictement nécessaire en théorie, mais en pratique il est important pour se protéger
d'un risque de plantage du programme, et aussi pour synchroniser le code avec le
contenu d'un fichier ce qui peut-être essentiel si le fichier est accédé par ailleurs
depuis un autre programme, ou pour faciliter le debugage du code.

102
Entrées - Sorties

2. En pratique : lecture d'un fichier « texte » sans Scanner


1. Importer les classes nécessaires :
import java.io.*;
2. Ouvrir un flux de caractères depuis un fichier :
FileReader in = new FileReader("nomFichier");
3. Lire caractère par caractère sur ce flux :
ch = in.read();
// ch vaut -1 en fin de fichier
4. Fermeture du flux :
in.close();

Remarques :
 Chaque étape (sauf l'import) peut lancer une IOException bloc try/catch (ou
throws) .
 Pour lire des nombres ou toutes données structurées écrites sous forme texte,
utiliser la classe Scanner (voir exemple suivant)

Exemple : Comptage du nombre de lettres 'A' d'un


fichier
import java.io.*;

// …
int n = 0;
// …
try {
FileReader in = new FileReader("f.txt");
while ( ( ch = in.read() ) != -1 ) {
if (ch == 'A') n++;
}
in.close();
}
catch (FileNotFoundException e) {
System.err.println("f.txt ne peut pas être ouvert");
}
catch (IOException e) {
System.err.println("erreur d'entrée-sortie");
}

3. En pratique : lecture d'un fichier « texte » avec Scanner


1. Importer les classes nécessaires :
import java.io.*; import java.util.Scanner;
2. Ouvrir un flux de caractères depuis un fichier :
FileReader in = new FileReader("nomFichier");
3. Créer un scanner branché sur ce flux :
Scanner sc = new Scanner(in);
4. Lire une ligne entière via ce Scanner :
String l = sc.nextLine();
5. Tester la présence d'un double, et le lire si présent :
if( sc.hasNextDouble() ) {
double val = sc.nextDouble();
}
6. Fermeture du flux :
in.close();

103
Remarque : chaque étape (sauf l'import) peut lancer une IOException bloc
try/catch (ou throws)

Exemple : Lecture d'un fichier comportant une suite de


nombres entiers, et calcul de leur somme
import java.io.*;
import java.util.Scanner;

// …
int somme = 0;
try {
FileReader in = new FileReader("f.txt");
Scanner sc = new Scanner(in);
while (sc.hasNextInt()) {
somme += sc.nextInt();
}
in.close();
}
catch (FileNotFoundException e) {
System.err.println("f.txt n'existe pas");
}
catch (IOException e) {
System.err.println("erreur d'entrée-sortie");
}

Complément
Dans l'exemple ci-dessus il faut que le fichier comporte uniquement des entiers et des
séparateurs (blancs, passages à la ligne, ...) sinon la lecture du fichier – et le calcul
de la somme – s'arrête avec le premier élément invalide (lettre, ponctuation, ...) dans
la mesure où sc.hasNextInt() retourne faux si le prochain élément à lire sur le flux
ne peut pas être considéré comme un entier écrit en base 10.
Dans la variante ci-dessous, le code a été « amélioré » pour faire la somme de tous
les entiers d'un fichier, quelque soit ce qu'il contient par ailleurs. On y utilise toujours
un scanner mais, à chaque tour de boucle, on commence par vérifier qu'il reste
quelque chose à lire par sc.hasNext() avant de lire l'élément suivant en distinguant
selon sa nature (entier ou pas).

import java.io.*;
import java.util.Scanner;

// …
int somme = 0;
try {
FileReader in = new FileReader("f.txt");
Scanner sc = new Scanner(in);
while (sc.hasNext()) {
if (sc.hasNextInt()) {
somme += sc.nextInt();
}
else {
sc.next();
}
}
in.close();
}

104
Entrées - Sorties

catch (FileNotFoundException e) {
System.err.println("f.txt n'existe pas");
}
catch (IOException e) {
System.err.println("erreur d'entrée-sortie");
}

4. En pratique : écriture d'un fichier « binaire »


1. Importer : import java.io.*;
2. Ouvrir un flux d'octets vers un fichier :
FileOutputStream out = new FileOutputStream("nomFichier");
3. Brancher un flux d'écriture d'objets sur le flux d'octets :
ObjectOutputStream objOut = new ObjectOutputStream(out);
4. Ecrire les nombres et/ou objets sur ce flux :
objOut.writeInt(i); // i nb. entier
objOut.writeDouble(x); // x nb. flottant
// ...
objOut.writeObject(o);
// o objet d'une classe qui implante l'interface Serializable
5. Fermeture des flux : objOut.close();
Remarque : chaque étape (sauf l'import) peut lancer une IOException bloc
try/catch (ou clause throws)

Exemple : Ecriture d'un objet (en mode binaire) dans


un fichier
import java.io.*;

// …
Auteur a, b;
// …
try {
FileOutputStream out = new FileOutputStream("f.bin");
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(a);
objOut.writeObject(b);
b.modifier(.........); // attributs de b modifiés
objOut.reset(); // indispensable ici voir remarque !
objOut.writeObject(b);
objOut.close();
}
catch (FileNotFoundException e) {
System.err.println("f.bin ne peut pas être ouvert");
}
catch (IOException e) {
System.err.println("erreur d'entrée-sortie");
}

Remarque : la méthode reset()


Lorsqu'une même instance est passée en paramètre à writeObject() à plusieurs
reprises, il faut impérativement invoquer la méthode reset() sur le flux comme dans
l'exemple ci-dessus (sinon, c'est la version initiale de l'instance qui est écrite à
nouveau sur le flux).

105
Complément : Sérialisation / désérialisation
On appelle sérialisation ou linéarisation (en anglais serialization ou
marshalling) l'opération consistant à transformer des données en mémoire vive
(d'essence possiblement complexe telles qu'un arbre ou un graphe) en une série
d'octets en vu, typiquement, d'une sauvegarde sur fichier ou d'une transmission par
connexion réseau. L'opération inverse s'appelle désérialisation.
Dans le cadre d'un langage objet, il est ainsi fréquemment nécessaire de la sérialiser /
désérialiser des objets (instances des classes). Or, ce n'est pas une tâche triviale
dans le cas général dans la mesure où :
1. les données « propres » à un objet (celles qu'il convient de sauvegarder si on
veut pouvoir re-créer ensuite l'objet) se compose de l'ensemble de ses
attributs non-statiques, ainsi que ceux de sa classe mère (et récursivement
jusqu'à la classe racine)
2. chaque attribut dont la nature est « référence non-nulle » pointe soit sur un
tableau, soit sur objet, qu'il convient donc de sérialiser également. Le tout
forme un graphe avec possibilités de cycles.
3. en cas de sauvegarde sur fichier, il faut anticiper le problème que posera la
modification du programme entre l'instant où des données sont sérialisées et
celui où l'on cherchera à les relire pour recréer un objet : rien n'interdit que la
définition des classes correspondants aux objets sauvegardées ait été modifiée,
par exemple via l'ajout ou la suppression d'un attribut.
Pour simplifier le travail des programmeurs (et dans le même temps améliorer la
fiabilité des programmes), Java inclut en standard un mécanisme de sérialisation /
désérialisation capable de fonctionner automatiquement sur n'importe quel objet de
n'importe quelle classe, et pas seulement les classes prédéfinies. C'est bien sur ce
mécanisme qui est mis en œuvre de manière transparente par les méthode
writeObject() et readObject() sous réserve que la classe « implante l'interface
Serializable » (cf. Interfaces Serializable, Externalizable et mot-clé transient p
143).

5. En pratique : lecture d'un fichier « binaire »


1. Importer : import java.io.*;
2. Ouvrir un flux d'octets depuis un fichier :
FileInputStream in = new FileInputStream("nomFichier");
3. Brancher un flux de lecture d'objets et de données sur le flux d'octets :
ObjectInputStream objIn = new ObjectInputStream(in);
4. Lire les nombres et/ou objets sur ce flux :
int i = objIn.readInt();
double x = objIn.readDouble();
// ...
Object o = objIn.readObject();
5. Fermeture des flux : objIn.close();

Remarques :
 chaque étape (sauf l'import) peut lancer une IOException bloc try/catch
(ou throws)
 la méthode readObject() peut en outre lancer d'autres exceptions
 penser à convertir ce que retourne readObject() dans le bon type (celui de
l'objet écrit à cet endroit du fichier)

106
Entrées - Sorties

Exemple : Lecture d'un objet (en mode binaire) depuis


un fichier
import java.io.*;

// …
Auteur a;
// …
try {
FileInputStream in = new FileInputStream("f.bin");
ObjectInputStream objIn = new ObjectInputStream(in);
a = (Auteur) objIn.readObject();
objIn.close();
}
catch (FileNotFoundException e) {
System.err.println("f.bin ne peut pas être ouvert");
}
catch (IOException e) {
System.err.println("erreur d'entrée-sortie");
}

Remarque
Il peut être utile de connaître davantage de détails sur le fonctionnement des
méthodes readObject() et writeObject(), surtout lorsqu'on ne se satisfait pas du
comportement par défaut consistant à lire/écrire tous les attributs de la classe : voir
plus loin pour un complément à ce propos nécessitant d'avoir déjà vu les notions
d'héritage et d'interfaces (cf. Interfaces Serializable, Externalizable et mot-clé
transient p 143).

C. Autres classes à connaître


1. Entrées-sorties en mode « random »
RandomAccessFile : classe permettant des lectures/écritures simultanées, et aussi
des lectures/écritures non-séquentielles
 constructeur : RandomAccessFile(filename,mode)
mode valant "r" (readonly) ou "rw" (read/write)
 écrire sur le fichier :
- raf.writeInt(i); // i entier
- raf.writeFloat(x); // x flottant
- raf.writeUTF(s); // s String
//...
 lire sur le fichier :
- int i = raf.readInt();
- float x = raf.readFloat();
- String s = raf.readUTF();
- String l = raf.readLine();
//...
 taille : int len = raf.length()
 déplacement dans le fichier : raf.seek(pos);

107
2. Manipulation de fichiers et répertoires
File : classe pour manipuler fichiers/répertoires (accès à la taille, listage du contenu,
suppression, renommage, ...)
 constructeurs :
- File(String name)
- File(String path, String name)
- ...
 méthodes :
- boolean exists()
- long length()
- File getParent()
- boolean isDirectory()
- String[] list()
- void delete()
- void mkdir(),
- boolean renameTo(File f)
- ...

108
Listes, piles, files,
IX -

arbres
IX

Problématique commune 109


Listes 110
Piles 113
Files 116
Arbres 117

A. Problématique commune
Trouver une structure de données qui permette de représenter en mémoire, et
manipuler, efficacement une suite d'éléments de même type.

En pratique, il s'agit de satisfaire simultanément un maximum d'objectifs parmi :


 minimiser l'occupation en mémoire ;
 minimiser le temps d'accès en moyenne et/ou au pire lors de l'accès à un
élément (pour le modifier par exemple) ;
 idem pour les autres opérations élémentaires usuelles : ajout, suppression,
recherche d'un élément ;
 idem pour les opérations portant sur la totalité des éléments : parcours, tri,
vidage, remplissage aléatoire, …

Atteindre tous ces objectifs à la fois est impossible en général. Le mieux que l'on
puisse faire consiste à choisir la « meilleure » structure de données dans un
contexte donné, c'est-à-dire celle qui présente le compromis optimal lorsque l'on
tient compte :
1. de la nature des éléments à manipuler ;
2. de l'application à réaliser, chaque application se caractérisant par une
distribution différente dans la fréquence relative des opérations ci-dessus.

Aussi, il est important de bien connaître les structures de données classiques que
sont les listes, piles, files et arbres (et pour chacune de comprendre les différentes
implantations possibles) afin de savoir bien choisir la combinaison type abstrait -
implantation la mieux adaptée à la résolution d'un problème donné.

109
Exemple
Un tableau d'entier conviendrait-il pour ranger efficacement des entiers dans l'ordre
croissant ?

B. Listes
1. Introduction
Une liste est une suite finie de N+1 couples (ai, pi)  E  P  {null} telle que :
 (ai , pi ) s'appelle un maillon
 E est l'ensemble des éléments ai
 P est l'ensemble des positions pi
 valeur ((ai, pi)) = ai  E
 position (a0, p0) = premier  P
 position ((ai, pi)) = pi -1  P i > 0
 pn = null  P

Une liste sera donc définie par :


- les N éléments ai
- premier P : la position du premier maillon
- une bijection « successeur » de P dans P telle que : successeur(pi ) = pi + 1

Attention
Une liste est ordonnée par la fonction de succession (rang = n ième maillon de la liste),
mais la position peut n'avoir aucun rapport avec cet ordre.

110
Listes, piles, files, arbres

2. Fonctions de manipulation
 Les accesseurs
renvoient des positions de maillons
 Les transformateurs
modifient une liste (peuvent éventuellement renvoyer une liste modifiée)
 Les observateurs
renvoient des renseignements divers

Exemple : Exemples d'accesseurs :


renvoyerLePremierDeLaListe : liste position
renvoyerLeDernierDeLaListe : liste position
donnerPosition : liste, rang position
donnerPositionSuivant : liste, position position
donnerPositionPrécédent : liste, position position

Exemple : Exemples de transformateurs :


Peuvent changer la liste ou en restituer une autre modifiée
creerListe : liste
ajouterDernier : liste, élément liste
enleverDernier : liste liste ou
inserer : liste, élément, rang liste
supprimer : liste, rang liste ou

Exemple : Exemples d'observateurs :


longueurDeLaListe : liste entier
estVide : liste booléen
rechercher : liste, élément entier (1er rang trouvé)
valeur : liste, position élément
imprimerTout : liste
imprimer : liste, rangDébut, rangFin

111
3. Implantation

 Implantation statique par tableau


- Les éléments sont placés dans les cases d'un tableau
- la position est définie par l'index dans le tableau (ai, pi) = (t[i], i + 1)

 Avantages
- Accès direct à l'élément par l'indice
 Inconvénients
- Insertion, suppression, ajouts délicats
- Taille maximum fixée à l'avance

 Implantation statique par tableau chaîné


- Les éléments sont placés dans les cases d'un tableau dans l'ordre de leur
création
- la position (indice) est définie dans un autre tableau (ou dans une nouvelle
dimension du tableau) (ai, pi) = (t[i], p[i])

 Avantages
- Accès semi-direct à l'élément par l'indice
- Réarrangement facile
 Inconvénients
- Taille maximum fixée à l'avance
- Comment ajouter rf ?

112
Listes, piles, files, arbres

 Implantation dynamique par références chaînées


- Les éléments sont placés au fur et à mesure dans une place mémoire qu'on
alloue à leur création
- la place réservée en mémoire contient un maillon, c'est à dire l'élément ai,,
et la référence pi du maillon suivant (ai, pi)

 Avantages
- Taille maximum non fixée à l'avance, occupation mémoire optimale (si on
néglige l'espace occupé par les références vers les maillons suivants)
- Réarrangement facile
 Inconvénients
- Parcours séquentiel obligatoire pour accéder à un élément

4. Applications
 Liste ordonnée pour ranger des éléments suivant un ordre prédéfini
(insertion, suppression)
- augmente le temps d'insertion d'un nouvel élément
- diminue le temps de restitution (évite un tri)
- Ex : répertoire alphabétique, actions datées, catalogue de références, …
 Pile et File pour simplifier à l'extrême le jeu d'instructions
- Pile : on met et retire un élément uniquement en fin de liste
- File : on ajoute les éléments en fin de liste, on les retire en début de liste

C. Piles
1. Introduction

 Une pile est une liste à accès restreint, c'est une suite d'éléments accessible
uniquement par le sommet
 Une pile est une liste de type « LIFO » (Last In First Out)
 Fonctions essentielles d'une pile:
- Créer une pile
- Empiler un maillon
- Dépiler un maillon
- Obtenir l'élément « sommet » (peut-être combiné à « dépiler »)
- Vérifier si la pile est vide

113
2. Fonctions de manipulation
 Si E est l'ensemble des éléments et P l'ensemble des piles, les fonctions
d'accès à une pile sont :
méthode arguments retour action

creer() P renvoie une


pile vide

sommet() P E renvoie
l'élément situé
au sommet

empiler(e) PxE P renvoie une


pile à laquelle
on a ajouté
l'élément e au
sommet

dépiler() P P renvoie une


si pile non vide pile à laquelle
on a enlevé le
sommet (ou )

estVide() P B renvoie un
booléen : vrai
si la pile est
vide, faux
sinon
 Selon la manière d'implanter une pile, on peut modifier le type, ou les
arguments de ces fonctions. (par ex : dépiler() peut renvoyer le sommet et pas
la pile)

3. Piles : implantation
 Selon l'utilisation souhaitée, on peut implanter une pile par tableau statique ou
chaîné ou par allocation dynamique de mémoire.
 Tableau : dans le cas d'un tableau simple, il faut un tableau de N éléments et
un entier désignant le sommet courant.
Attention, la taille est fixée, d'où la gestion nécessaire d'un dépassement (pile
pleine)
 Chaînage : il faut soit utiliser un tableau chaîné (statique), soit considérer une
structure maillon qui contient la partie « élément », et une référence au maillon
suivant (dynamique)

114
Listes, piles, files, arbres

4. Application
 La pile (stack) est beaucoup utilisée en programmation (pile d'appels, pile
d'erreurs).
 La gestion de la récursivité fait généralement appel à une pile.
 Certaines calculettes utilisent la notion de pile pour éviter la gestion des
parenthèses.

Exemple d'utilisation d'une pile : gestion de la pile d'appels d'une fonction récursive

public static long factorielle(long n) {


if (n==1) { return 1L ; }
else { return n*factorielle(n-1); }
}

115
D. Files
1. Introduction

 Une file est une liste à accès restreint ; c'est une suite d'éléments accessible
par le sommet en entrée, par la base en sortie
 Une file est une liste de type « FIFO » (First In First Out)
 Fonctions essentielles d'une file:
- Créer une file
- Ajouter un maillon (au sommet)
- Retirer un maillon (à la base)
- Vérifier si la file est vide

2. Fonctions de manipulation
 Si E est l'ensemble des éléments et F l'ensemble des files, les fonctions d'accès
à une file sont :

méthode arguments retour action

creer() F renvoie une file


vide

ajouter(e) FxE F renvoie une file


à laquelle on a
ajouté
l'élément e au
sommet

enlever() F FxE renvoie une file


à laquelle on a
enlevé la base
(ou )

estVide() F B renvoie un
booléen : vrai
si la pile est
vide, faux
sinon

 Selon la manière d'implanter une file, on peut modifier le type, ou les


arguments de ces fonctions. (par ex : enlever() peut renvoyer le sommet et
pas la file)

116
Listes, piles, files, arbres

3. Implantation
 Seule une implantation de type « chaînée » convient pour une file.
L'implantation en tableau simple nécessiterait de réorganiser le tableau à
chaque suppression

4. Applications
 Les files sont souvent utilisées pour gérer « l'attente ».
 Les files d'attente d'impressions, les buffers sont autant de files

Buffer stdin (clavier) - Saisie au clavier de : « ls -l tp3 »

E. Arbres
1. Introduction
Structure d'arbre
 Un arbre est une extension de la notion de liste dans laquelle un maillon peut
avoir plusieurs suivants.
 C'est donc une suite d'éléments qui ont chacun 0, 1, ou plusieurs suivants.
 En conséquence, il y a plusieurs façon de définir un ordre, c'est à dire le
« rang » d'un élément.

2. Récursivité
Un arbre peut toujours être considéré d'une manière récursive par sa racine et un
ensemble d'arbres liés à cette racine (les sous-arbres).

117
3. Vocabulaire
 « racine », « feuilles »
 « nœud », « branche »
 « fils », « père », « frères »
 « ascendants »
 « descendants »
 « arc », « chemin »
 « sous-arbre »
 « niveau »
 « profondeur »
 « forêt »
 « complet »
 « dégénéré »
 « général »
 « binaire »

4. Arbres binaires
 Un arbre binaire, est une arbre général dont les nœuds ne peuvent avoir plus
de 2 fils.
 En pratique, il existe une équivalence entre arbre général et arbre binaire.

5. Numérotation des nœuds


Deux façons de numéroter (ordonner) les nœuds d'un arbre (et parmi elles, plusieurs
variantes possibles) :

118
Listes, piles, files, arbres

6. Parcours
Dans une numérotation dynastique, on distingue essentiellement 3 modes de
parcours d'un arbre binaire - selon la position de la racine dans le parcours -
(récursivité):
Le parcours R G D dit parcours préfixé.
Le parcours G R D dit parcours infixé.
Le parcours G D R dit parcours postfixé.

7. Exemple de parcours RGD en java


Fonction récursive effectuant un parcours RGD d'un arbre pour l'imprimer :

void afficherRGD() {
if ( !(estVide())) {
imprimeRacine();
gauche.afficherRGD();
droit.afficherRGD();
}
else {
imprimerVide();
}
}

8. Fonctions de manipulation d'arbres binaires


 Si E est l'ensemble des éléments et A l'ensemble des arbres binaires, ci
dessous quelques exemples de fonctions applicables aux arbres binaires:

creer() A A renvoie un arbre vide

racine() AxA E renvoie l'élément racine

ajouteg(a) A A ajoute/remplace le sous arbre


(resp. ajouted(a)) gauche (resp. droit) par un
arbre a

enleveg() A A renvoie l'arbre amputé du


(resp. enleved(a)) sous arbre gauche (resp.
droit)

gauche() A A envoie le sous arbre gauche


(resp. droit(a)) (resp. droit) ou

estVide() A B renvoie le booléen vrai si


l'arbre est vide, faux sinon
 Attention : avec la notion d'arbre, il faut toujours penser« récursivité »

119
9. Implantation
Par Chaînage :
 Il faut considérer une structure récursive qui contient, à chaque niveau :
- la partie « élément » (racine)
- Des références aux sous arbres comme - par exemple - une liste de sous-
arbres
Dans le cas d'un arbre binaire :
- une référence à un arbre : le sous arbre gauche
- une référence à un arbre : le sous arbre droit

Par Tableau :
 Il faudrait un tableau de N éléments et (pour un arbre binaire) deux tableaux
de N entiers pour représenter les indices (dans le tableau) des fils à gauche et
à et droite.
 Très peu utilisé par sa structure figée et les « trous » laissés lorsque l'arbre
n'est pas complet.

10. Applications
Gestion syntaxique d'une expression logique parenthésée

Principe :
 Si opérateur alors on crée un sous-arbre dont l'opérateur est la racine
 Sinon (opérande) on crée une feuille

Le parcours parcours préfixé ( R G D ) ou « notation polonaise » donnera


l'expression :
/*+abc*a+bc

Le parcours infixé ( G R D ) donnera l'expression :


a + b * c / a * b + c, PAS CONVENABLE ici car revient à retirer les parenthèses
parcours G D R

Le parcours postfixé ( G D R ) ou « notation polonaise inverse » donnera


l'expression
ab+c*abc+*/

120
Listes, piles, files, arbres

Arbres Binaires de Recherche


Représentation de données en vue d'une utilisation ordonnée
Principe : rangement au fur et à mesure : à gauche si « avant », à droite sinon

 Le parcours GRD donne les éléments en ordre alphabétique (DRG en ordre


alphabétique inversé)

121
Paquetages,
X-

importation
X
Paquetage 123
Paquetage et visibilité 123
Importation 124
Nommage des paquetages 124
Organisation en fichiers, compilation et exécution 124
Paquetages standards de Java 125

A. Paquetage
Entité de structuration regroupant plusieurs classes et/ou interfaces et/ou sous-
paquetages
Les packages définissent des espaces de nommage (ou namespace) distincts
(réduit les risques de conflits dans les noms de classes)
Le paquetage d'appartenance est indiqué au début du fichier source par :
package nomPackage;
Les fichiers .class de chaque paquetage doivent impérativement être placés dans un
répertoire ayant le nom exact du paquetage
Les paquetages (et classes) sont recherchés dans une liste de répertoires (et/ou de
fichiers zip) fixée par la variable d'environnement : CLASSPATH

Attention
Par défaut (lorsque le mot-clé package est omis en début de fichier) les classes et
interfaces sont définis dans le « paquetage anonyme » à éviter, sauf pour de petits
programmes.

B. Paquetage et visibilité
Par défaut, les classes et interfaces ne sont visibles que dans le paquetage où elles
sont définies
seules celles qui sont déclarées « publiques » pourront être importées dans d'autres
paquetages.
Exemple :

public class Cercle {


// classe visible dans son package
// et dans tous les packages qui l'importent
}

123
class Auxiliaire {
// classe visible dans son package uniquement
// (pas de possibilité de l'importer)
}

Par défaut, les attributs et méthodes sont visibles dans tout le paquetage de la classe
où ils sont définis (et nulle part ailleurs).
Les mots-clés public, protected et private appliqués aux attributs et méthodes
permettent de modifier la visibilité « paquetage » par défaut.

C. Importation
Pour utiliser une classe (publique) C à l'extérieur de son package P :
 la désigner par son nom complet : P.C
 ou alors l'importer en début de fichier par : import P.C;
puis la désigner par son nom court : C
Possibilité d'importer toutes les classes publiques d'un package P par : import P.*;

Autre possibilité : importer uniquement certains attributs et/ou méthodes statiques


d'une classe (publique), exemple :
import static java.lang.Math.PI;
// permet d'écrire plus loin dans le fichier :
// double d = 2 * PI;

NOTA-BENE : importer des attributs et/ou méthodes non-statiques n'est pas possible
(cela n'aurait guère de sens).

Conseil
L'importation statique doit être utilisée avec parcimonie (le système de nommage par
défaut de Java est conçu pour faciliter l'écriture de grands programmes en évitant les
conflits de noms, y compris lorsque le code évolue dans le temps).
On évitera en particulier d'utiliser le caractère * pour importer tous les attributs et
méthodes statiques d'une classe, sauf à la rigueur pour les classes les plus connues
de Java telles que java.lang.Math.

D. Nommage des paquetages


Attention au nommage des paquetages : choisir un nom clair, concis et qui,
néanmoins, minimise tout risque de conflit de nom (présent ou futur)
Usage en Java le nommage de style « hostname inversé », exemple :
fr.institution.service.nom_paquetage

E. Organisation en fichiers, compilation et exécution


Au maximum une classe ou interface publique par fichier source (auquel cas, le nom
du fichier doit impérativement être celui de la classe ou interface publique contenue
dans le fichier)
Il peut y avoir d'autres classes et interfaces non publiques dans le même fichier
La compilation du fichier f.java produit autant de fichiers (suffixés par .class) qu'il y
a de classes dans le fichier f.java
Exécution (à partir d'un terminal) du main de la classe C située dans le package P :

124
Paquetages, importation

- depuis le répertoire du package P : java C


- depuis le répertoire parent : java P.C

F. Paquetages standards de Java


Nombreux paquetages « standards » en Java 4000+ classes toujours disponibles
(sous réserve de les importer) quels que soient la machine, l'OS, ...
Quelques packages standards parmi les plus utilisés :
 java.lang : classes de base du langage
 java.util : classes utilitaires, structures de données, ...
 java.io : classes liées aux entrées-sorties
 java.math : calculs en précision arbitraire
 java.text : internationalisation
 java.awt : graphisme (Abstract Window Toolkit)
 java.applet : appliquettes
 javax.swing : graphisme « 2ème génération »
 java.sql : bases de données (JDBC)
 java.security : cryptage, authentification, ...
 ...

Complément : les « compacts »


Il est possible en Java de se limiter volontairement à un sous-ensemble du langage
afin de réduire la taille de la machine virtuelle nécessaire à l'exécution du code (utile
pour exécuter du code Java sur des machines disposant de peu de mémoire).
Java définit ainsi trois sous-ensembles dénommés « compact 1 », « compact 2 » et
« compact 3 » qui se différencient par les paquetages accessibles.

Conseil
Penser à la documentation en-ligne de Java pour approfondir tel ou tel paquetage,
voir aussi les nombreux tutoriaux disponibles (cf. Annexe : ressources
complémentaires sur Java p 219).

125
Compléments sur les
XI -

classes
XI

Niveaux de visibilité 127


Classes ou interfaces internes 128
Classes locales et classes anonymes 128
Héritage, classe racine, ... 129
Introspection 137

A. Niveaux de visibilité
Objectif : sécuriser l'écriture des programmes composés d'un grand nombre de
classes.

Quatre niveaux de visibilité en Java pour les attributs et méthodes :


- private : accessible seulement depuis l'intérieur de la classe
- package : accessible seulement depuis le même package (visibilité par défaut)
- protected : idem + depuis les classes dérivées même situées dans un autre
package
- public : accessible partout

Deux niveaux de visibilité pour les classes et interfaces :


- package : accessible seulement depuis le même package (visibilité par défaut)
- public : accessible partout

Trois mots-clés : private, protected et public (package est la visibilité par défaut en
l'absence de qualificatif)

Voir les règles de bon usage dans le chapitre sur les classes (cf. Visibilité p 88).

127
Exemple
class Employe {
private String nom;
protected int age;
protected int salaire;
public toString() {...}
double calculerPrime() {....}
// ...
}

public class MonProgramme {


// ...
Employe e = new Employe( ... ); // OK ssi même package
String s = e.toString(); // OK (public)
double prime = e.calculerprime(); // OK ssi même package
e.age++ ; // OK ssi même package (protected)
int x = e.salaire ; // OK ssi même package (protected)
e.nom = "Durand"; // ERREUR (private)
// ...
}

Complément
La visibilité « protected » n'a de sens spécifique que lorsqu'une (au moins) des
classes filles est située dans un package différent.

B. Classes ou interfaces internes


 Une classe « interne » (ou « nichée ») est une classe définie à l'intérieur
d'une autre (au même niveau que attributs/méthodes)
 Idem pour les interfaces « internes » (ou « nichées »)
 Intérêt : classes (ou interfaces) utilitaires très liées à classe englobante
 Pour les classes internes, 2 catégories :
- static : classes « normales » mais fortement liées à la classe englobante
- membres : associées à chaque instance ; peuvent accéder directement aux
attributs privés de classe englobante

C. Classes locales et classes anonymes


 Une classe « locale » est une classe définie à l'intérieur du corps d'une
méthode
 Une classe locale ne peut pas être statique
 Classe anonyme = classe locale sans nom, définie juste à l'intérieur d'un new
Usage possible : pour créer une instance unique d'une classe très particulière
ou bien une implantation ad hoc d'une interface (i.e. gestionnaires
d'événements (cf. Événements et programmation événementielle p 186))

128
Compléments sur les classes

D. Héritage, classe racine, ...


1. Notion de hiérarchie de classes

2. Héritage
Intérêt de l'héritage : réutiliser une classe existante en l'adaptant ; créer des
variantes d'une classe ; ...
Mot-clef : extends

class Figure {
private String nom;
private Position pos;
public Figure(Position p){ pos = p; }
public void deplacer(int dx, int dy) {
pos.ajouter(dx, dy);
}
}

class Cercle extends Figure {


// Un cercle est un cas particulier de Figure,
// la classe Cercle hérite de tous les
// attributs et méthodes le la classe Figure
// ...
}

En Java, héritage simple uniquement (pas plus d'une classe mère)

129
3. Héritage, attributs et méthodes
Une sous-classe (ou classe fille ou classe dérivée) hérite de tous les attributs
et méthodes (y compris statiques) de sa super-classe (ou classe mère) :

Cercle c = new Cercle();


// appel d'une méthode héritée
c.deplacer(2, -1);

Une sous-classe peut évidemment définir des attributs et méthodes


supplémentaires qui lui sont spécifiques :

class Cercle extends Figure {


private double rayon;
public double circonference() {
return 2*Math.PI*rayon;
}
}

4. Héritage et visibilité
Une classe fille ne peut accéder qu'aux attributs et méthodes « public » ou
« protected » de sa classe mère (ainsi qu'aux attributs et méthodes « package » ssi
elle appartient au même paquetage que sa classe mère) :

class Cercle extends Figure {


//...
void essai() {
// essai d'accès à un attribut privé
// de la classe mère :
String s = nom; // ERREUR !
}
}

5. Héritage et références
Toute référence vers une instance de la classe fille peut être vue aussi comme une
référence vers la classe mère (conversion automatique fille mère) :

Figure f = new Cercle();


// OK : affectation d’un Cercle dans une Figure

Cercle c = new Cercle(1);

if ( f.contient(c) ) {
// OK : passage d’un Cercle en paramètre
// à une méthode attendant une Figure

ATTENTION : l'opération inverse est interdite :

Cercle c = new Figure(); // Interdit !


// On doit respecter le sens de l'héritage
// y compris dans sa signification
// « est un cas particulier de »

130
Compléments sur les classes

Complément : instanceof et héritage


Il est possible (et recommandé) d'utiliser le mot-clé instanceof pour distinguer les
instances de différentes sous-classes à partir d'une référence dont le type est celui de
leur classe mère.

Exemple : étant données


- une classe Figure dont hérite plusieurs sous-classes : Triangle, Cercle, ...
- une référence f de type Figure
alors f instanceof Cercle retourne vrai ssi f réfère spécifiquement un objet de
type Cercle (et pas un objet d'une autre sous-classe de Figure).

6. Héritage et constructeurs
Les constructeurs ne sont pas hérités, mais on peut appeler ceux de la classe mère
avec super(...) :

class Cercle extends Figure {


//...
Cercle(float r, Position pos) {
super(pos); // appel du constructeur Figure(pos)
rayon = r;
}
}

NOTA-BENE :
 l'appel super(...) doit impérativement être la 1ère instruction du constructeur
 si la 1ère instruction n'appelle ni le constructeur de la classe mère, ni un autre
constructeur de la classe fille, alors il y a appel automatique de super() sans
argument
 ordre des opérations :
1/ appel du constructeur de la classe mère
2/ initialiseurs et blocs d'initialisation
3/ corps du constructeur fille

7. Redéfinition, spécialisation, masquage


Méthodes et attributs héritées peuvent être redéfinis dans les classes filles, mais le
vocabulaire et les conséquences différent :
 pour les méthodes non-statiques : on parle de « spécialisation » (en anglais :
overriding) = possibilité de définir un comportement spécifique pour les
opérations héritées (en définissant une méthode ayant exactement la même «
signature » mais un code différent)
 pour les attributs : la redéfinition est possible (y compris avec un typage
différent que dans la classe mère) mais rarement pertinente
 pour les méthodes statiques : la redéfinition est possible mais rarement
pertinente
Dans les trois cas, il y a alors « masquage » de l'attribut ou méthode hérité
En cas de masquage, le mot-clé super permet d'accéder si besoin aux attributs et
méthodes de la classe mère rendus inaccessibles autrement (voir exemple)
class Cercle extends Figure {

131
private float rayon;
//...
public void afficher() {
// si besoin, appel de la méthode de même
// nom dans la classe mère :
super.afficher();
// traitement spécifique à la classe fille :
System.out.println("rayon=" + rayon);
}
}

Remarque
 La visibilité d'une méthode redéfinie peut être différente (mais seulement
augmentée).
 En cas de masquage, c'est le type de la référence qui détermine quel attribut
est pris en compte par défaut entre celui de la classe fille et celui héritée mais
masqué.
 Il est possible d'accéder à un attribut (mais pas à une méthode) masqué d'une
classe ancêtre quelconque en utilisant la syntaxe : ((ClasseAncêtre)
this).attributMasqué
 L'annotation (cf. Annotations p 177) @Override permet d'expliciter l'intention
du programmeur de redéfinir une méthode héritée, syntaxe : @Override public
void afficher() { .... }
 La redéfinition d'un attribut non-statique crée en pratique un 2° attribut pour
chaque instance de la classe fille (Java alloue une zone mémoire
supplémentaire et stocke les 2 valeurs).

8. Polymorphisme dynamique
Quand on manipule un objet via une référence à une classe mère, ce sont toujours les
méthodes (non statiques) de la classe effective de l'objet qui sont appelées :
Figure f = new Cercle();

// ...
f.afficher();
// appel afficher() de Cercle bien que
// f est une référence de type Figure !

9. Méthode abstraite
Une méthode « abstraite » est une méthode dont on a spécifié la signature mais
pas écrit le corps
Mot-clef : abstract

class Figure {
//...
public abstract void colorier();
}

Méthode destinée à être (re)définie dans les classes filles


Ne peut exister que dans une classe elle-même déclarée abstraite (voir ci-après)
Impossible pour les méthodes « statiques »

132
Compléments sur les classes

10. Classe abstraite


Une classe « abstraite » est une classe non instanciable (elle sert uniquement de
classe mère)
Introduite par le mot-clef : abstract

abstract class Figure {


//...
}

Toute classe qui contient au moins une méthode abstraite (ou qui en hérite une sans
la redéfinir) doit obligatoirement être déclarée abstraite

Remarque : constructeur(s) dans une classe abstraite


Bien que non instanciable, une classe abstraite peut inclure un (ou plusieurs)
constructeurs. Ces constructeurs ne pourront être invoqués que dans le cadre de
l'instanciation d'une classe fille non-abstraite (via l'instruction super() en début du
constructeur de la classe fille). Intérêt : initialiser les attributs définis au niveau de la
classe abstraite ; factoriser les opérations à effectuer dans tous les cas lors de la
création des instances des classes filles.

11. Classe non dérivable


C'est une classe qui ne pourra pas servir de classe mère
Mot-clef : final

final class ClasseTerminale {


//...
}

Intérêt : sécuriser, fiabiliser le développement de gros programmes


Exemple : beaucoup de classes du paquetage java.lang

12. Méthode non redéfinissable


Il est possible en Java d'interdire la redéfinition d'une méthode dans les classes filles
Mot-clef : final

Exemple :

abstract class Figure {


Position pos;
final public deplacer(int dx, int dy) {
pos.ajouter(dx, dy);
}
}

133
13. Héritage et tableau
Si une classe Fille dérive de Mere, alors Fille[] est considéré comme un « sous-
type »17 de Mere[].
Cela se traduit par le fait qu'un tableau d'instances de Fille sera autorisé partout où
un tableau d'instances de Mere est attendu. Exemple :

Fille[] tabF = new Fille[3];


Mere[] tabM = tabF; // OK
// ...
// ATTENTION
// même manipulé via un Mere[],
// un tableau de Fille ne peut contenir
// que des références à Fille :
tabM[0] = new Mere(); // Erreur

14. la classe « Object »


La classe Object est à la racine de l'arbre d'héritage des classes en Java ; elle
est donc l'ancêtre de toutes les classes.

La classe Object définit plusieurs méthodes héritées par toutes les classes (et
applicables aussi aux tableaux) :
 boolean equals(Object obj)
par défaut, retourne this==obj (compare les références), mais conçue pour
être redéfinie afin de comparer véritablement les contenus (ex : classe String)
 int hashCode()
par défaut, retourne un entier raisonnablement utilisable dans une table de
hashage (entier déduit de l'adresse mémoire de l'objet), conçue pour être
redéfinie si besoin pour optimiser les performances du hashage
 String toString()
par défaut, retourne "NomClasse@"+hashCode(), mais conçue pour être
redéfinie pour produire une représentation textuelle pertinente de l'objet
 finalize()
par défaut, ne fait rien, mais conçue pour être redéfinie si besoin pour
spécifier quoi faire lors de la destruction de l'objet avant de libérer la mémoire
 Object clone() : voir ci-après
 Class getClass() : voir ci-après
 notify(), notifyAll(), wait() : voir le chapitre sur les Threads (cf.
Synchronisation des exécutions p 210)

NOTA-BENE : les méthodes getClass(), notify(), notifyAll(), wait() sont


déclarées « final » dans la classe Object et ne peuvent donc pas être redéfinies ; les
autres peuvent et doivent être redéfinies lorsque nécessaire.

17 - Le concept de Sous-type est proche mais différent de celui de sous-classe et d'héritage. Il dépasse le
cadre des langages objets ; il veut dire que les instances du sous-type sont systématiquement substituables
aux instances du type. A la différence de l'héritage, il ne signifie pas que le sous-type est défini à partir du
type en termes de sémantique et/ou d'implantation. Dans le cas de tableaux d'objets on préférera employer
le vocabulaire type/sous-type dans la mesure où les tableaux en Java ne sont pas eux-mêmes des classes.

134
Compléments sur les classes

Attention : redéfinition de la méthode equals()


La méthode doit impérativement être réflexive, symétrique, transitive, consistante, et
retourner false si une seule des références comparées vaut null.

Suggestion : penser à utiliser instanceof() pour écrire equals(), exemple :

class Cercle{ //...


public boolean equals(Object o){
if (o instanceof Cercle){
boolean x = centre.equals(o.centre);
x = x && (rayon==o.rayon);
return x;
}
else {
return false;
}
}
}

Remarque : redéfinition de la méthode hashCode()


En cas de redéfinition de la méthode equals(), il est vivement recommandé de
redéfinir aussi la méthode hashCode().
Il est en effet essentiel que la méthode hashCode() retourne la même valeur pour
toutes les instances considérées comme égales par la méthode equals() redéfinie.
A défaut, certaines méthodes prédéfinies de Java produiront des résultats erronés
(i.e. la méthode add() de la classe HashSet).

Conseil
Sous Eclipse, le plus efficace pour redéfinir les méthodes equals() et/ou hashCode()
consiste à les générer à partir du menu « Source -> Generate hashCode() and
equals() ». D'une manière générale beaucoup de tâches plus ou moins complexes
et/ou fastidieuses peuvent être effectuées efficacement à l'aide des menus « Source »
et « Refactor » d'Eclipse (génération d'un constructeur, création d'un bloc try/catch,
etc.).
L'équivalent existe sur NetBeans (alternative à Eclipse).

Remarque : redéfinition de la méthode finalize()


Il est possible de bloquer la destruction d'un objet via sa méthode finalize() en re-
créant une ou plusieurs références pointant sur l'objet.
Dans tous les cas, la méthode finalize() n'est jamais invoquée plus d'une fois sur
un même objet (y compris si de nouvelles références ont été crées sur l'objet lors
d'un appel précédent à finalize().

135
15. Méthode clone()
La méthode clone() de la classe Object permet de dupliquer un tableau ou une
instance (recopie des attributs)
Sur les tableaux, clone() est directement utilisable :

int[] tab = { 1, 2, 3, 4 } ;
int[] tab2 = tab.clone() ;

ATTENTION : pour les tableaux multi-dimensionnels et pour les tableaux d'objets car
la méthode clone() telle que définie dans la classe Object copie les références (et
pas les objets référencés)

Sur les objets, clone() n'est pas toujours utilisable par défaut les objets ne sont
pas « clonables », pour pouvoir leur appliquer la méthode clone() il faut :
1. déclarer que la classe implante l'interface Cloneable
2. redéfinir la méthode clone() en tenant compte des spécificités de la classe
(e.g. attributs de type référence)

NOTA-BENE : certaines classes pré-définies en Java (mais pas toutes) implantent


l'interface Cloneable (voir la documentation en-ligne des classes Java) ; pour les
classes définies par l'utilisateur, c'est à lui de décider si il veut ou pas qu'elles soient
clonables, et le cas échéant, si il convient ou pas de redéfinir la méthode clone()
héritée.

Conseil : rendre « clonable » une classe avec des


attributs de type référence
Si une classe Cls contient des attributs de type référence et qu'on veut la rendre
« cloneable » , le mieux à faire consiste à :
1. inclure dans Cls un constructeur par recopie : Cls(Cls x)){...}
2. redéfinir la méthode clone() de Cls en utilisant le constructeur par recopie :
Object clone() { return (Object) new Cls(this); }
3. déclarer que Cls implante l'interface Cloneable

16. Programmation « générique » via la classe Object


La classe Object permet aussi de faire de la programmation générique, i.e. des
classes ou fonctions qui peuvent fonctionner avec des instances de n'importe quelles
classes
Exemple de fonction générique :
int chercher(Object o, Object[] tab) {
for (int i=0 ; i<tab.length ; i++) {
if (o.equals(tab[i])) {
return i;
}
return -1;
}
}

Exemple de fonction « générique » prédéfinie en Java :


java.util.Arrays.sort(Object[] tab)

136
Compléments sur les classes

NOTA-BENE : depuis Java 1.5, la programmation « générique » se fait plutôt sous


forme paramétrée

E. Introspection
Chaque classe (et interface) est représentée par une instance de la classe Class (cf.
La classe Class p 164)
La classe Class permet d'instancier une classe à partir de son nom :

Class cl;
cl = Class.forName("NomPackage.NomDeClasse");
Object o = cl.newInstance();

Les classes Class, Method, Field et Constructor permettent d'explorer (et invoquer)
dynamiquement du code Java (on parle alors d'introspection) :

Method[] getDeclaredMethods()
Field[] getDeclaredFields()
Constructors[] getDeclaredConstructors()
Class[] getInterfaces()
Class getSuperClass()
boolean isInterface()
// ...

Complément
On appelle « introspection » (en anglais : reflection), la possibilité dans un langage
de programmation de pouvoir étudier dynamiquement le code en cours d'exécution,
avec dans le cas d'un langage objet, la possibilité de naviguer dans le réseaux de
classes/attributs/méthodes.
Certains programmes sont de fait bien plus simples à écrire si on peut utiliser ce
mécanisme.
Exemple : supposons que pour tester une classe on souhaite disposer d'une interface
homme-machine qui donne accès à la liste complète des méthodes définies dans cette
classe ; en utilisant l'introspection pour construire la liste des fonctions de la classe on
est certain que la liste sera toujours à jour sans pour autant avoir à la mettre à jour,
d'où un gain de temps (et de fiabilité).
En Java, l'introspection est possible à travers les méthodes de la classe Class, Field
et Method.
Elle inclut la possibilité d'instancier une classe et/ou d'invoquer une méthode dont le
nom est déterminé à l'exécution du code.
Toutefois, il n'est pas possible en Java d'utiliser la classe Class pour modifier une
classe à l'exécution (i.e. ajouter ou supprimer un attribut ou une méthode par
exemple).
ATTENTION : l'introspection peut permettre de contourner le typage fort au niveau
du compilateur Java mais ce faisant on prend le risque de générer des erreurs
(IllegalArgumentException) lors de l'exécution du programme. Autrement dit, le
typage fort en Java n'est pas juste lié aux vérifications effectuées par le compilateur
(et qui se matérialisent par des interdits sous Eclipse), il est plus fondamentalement
lié aux mécanismes de contrôle qu'applique systématiquement la machine virtuelle au
bytecode lors de son exécution. On ne peut donc pas utiliser l'introspection pour
contourner le typage de Java et programmer ainsi comme on le ferait dans un
langage faiblement typé !

137
Conseil
Penser au tutoriel d'Oracle18 sur le sujet pour approfondir cet aspect du langage (le
tutoriel d'Oracle est organisé sous forme de sentiers dont un sentier intitulé « The
Reflection API ».)

18 - http://docs.oracle.com/javase/tutorial/

138
XII - Interfaces

XII
Interfaces 139
Exemple d'interfaces 140
Autres exemples d'interfaces 140
Interfaces prédéfinies en Java 141
Héritage entre interfaces 141
Implantation d'une interface par une classe 141
Interface dans une déclaration d'attribut, variables, ... 141
Interfaces en paramètres de méthodes 142
Interfaces « marqueurs » 142
Interfaces Serializable, Externalizable et mot-clé transient 143
Interfaces fonctionnelles 144
Passage d'une fonction/méthode en paramètre de méthode
144
Méthodes par défaut 146
Corps de méthodes statiques dans une interface 146
Comparaison interfaces / classes abstraites 147

A. Interfaces
Interface = ensemble de signatures = ensemble de méthodes toutes abstraites

Intérêt : équivaut à un « type abstrait de données » ; permet de spécifier des


fonctionnalités indépendamment de leur implantation ; permet ensuite de
vérifier/imposer la présence de ces fonctionnalités au niveau d'une classe ou d'une
instance.

NOTA-BENE : contrairement à une classe, une interface ne peut jamais être


instanciée ; son rôle consiste à servir de modèle à des classes.

Remarque
En Java, une interface peut aussi contenir :
 des constantes de classe ;
 des méthodes « par défaut » (cf. Méthodes par défaut p 146) ;
 des méthodes statiques avec leur corps (cf. Corps de méthodes statiques dans
une interface p 146).

139
Complément
Les constantes définies dans une interface sont toujours public, static et final :
ces mots-clés peuvent donc être omis, ils sont implicites dans le contexte d'une
interface.
De même, les méthodes définies dans une interface sont toujours abstraites et
publiques (sauf cas particulier des méthodes « par défaut ») : inutiles donc de les
qualifier de public et abstract.

B. Exemple d'interfaces
Définition d'une interface, puis d'une classe qui « implante » cette interface :

public interface Mesurable {


public double calculerSurface();
public double calculerPerimetre();
// Toute classe « mesurable » devra obligatoirement
// implanter ces deux méthodes
// (sinon ce sera une classe abstraite).
}

public class Cercle implements Mesurable {


// ………
public double calculerSurface() {
return ( PI*rayon*rayon );
}
public double calculerPerimetre() {
return( 2*PI*rayon );
}
// ………
}

C. Autres exemples d'interfaces


interface Redimensionnable {
void grossir(int facteur);
void reduire(int facteur);
}

interface Coloriable {
// NOTA-BENE :
// possibilité de définir des constantes :
Couleur ROUGE = new Couleur("rouge");
Couleur NOIR = new Couleur("noir");
//...
void colorier(Couleur c);
}

interface Pile {
void empiler(Object o);
void depiler();
boolean estVide();
//...
}

140
Interfaces

D. Interfaces prédéfinies en Java


Il existe beaucoup d'interfaces prédéfinies en Java, parmi les plus importantes :
 cœur du langage : Appendable, Cloneable, Comparable,
Iterable, Runnable ...
 E/S : Serializable, Externalizable, Closeable, ...
 collections : Collection, List, Queue, Set, Map, Comparator, ...
 threads : Runnable, ...
 IHMs (AWT) : LayoutManager, Ajustable, Icon, ImageObserver,
ImageProducer, ActionListener, KeyListener, ...
 ...

E. Héritage entre interfaces


Une interface peut « dériver » (ou « hériter ») d'autres interfaces :
interface Externalizable
extends Serializable {
// .........
}

F. Implantation d'une interface par une classe


Une interface peut être « implantée » par un nombre quelconque de classes.
Une classe peut implanter zéro, une, ou plusieurs interfaces, exemple :
class C implements Runnable, Cloneable {
// .........
}

G. Interface dans une déclaration d'attribut, variables,


...
Lors d'une déclaration d'attributs ou de variable, il est possible d'indiquer une
interface à la place du type :
Coloriable fig;
Cercle c = new Cercle(...);
// ...
fig = c; // OK si Cercle implante Coloriable

NOTA-BENE : une référence à une interface peut désigner toute instance de toute
classe qui implante l'interface en question.

Attention
Les méthodes applicables dépendent de la nature de la référence :
Cercle cercle = new Cercle();
Redimensionnable redim = cercle;
Coloriable col = cercle;

// cercle, col et redim sont trois vues différentes


// du même objet.

141
// ATTENTION : dans un tel cas, les méthodes applicables
// dépendent de la vue utilisée :

col.colorier(Coloriable.ROUGE); // OK
col.grossir(2); // ERREUR
redim.grossir(2); // OK
cercle.colorier(Coloriable.ROUGE); // OK

H. Interfaces en paramètres de méthodes


Dans une signature de méthode, il est également possible d'indiquer une interface à
la place du type :

void envoyer(Serializable item) { .... }


// ...
envoyer(c); // OK si Cercle implante Serializable

RAPPEL : une référence à une interface peut désigner toute instance de toute classe
qui implante l'interface en question.

Autre exemple :
interface Comparable {
int compareTo(Object o);
}

class Tri {
public static void trier(Comparable[] tab) {
//...
if (tab[i].compareTo(tab[j]) > 0) {
//...
}
}
}

class W implements Comparable {


//...
public int compareTo(Object o) { ... }
}

W[] tabW = new W[10];


// ...
Tri.trier(tabW);

I. Interfaces « marqueurs »
Définition
On appelle interface « marqueur » ou « interface de marquage » (en anglais :
marker interface) une interface qui ne contient aucune méthode ni constante, et
sert juste à préciser une propriété des classes qui l'implantent.

Exemples de telles interfaces pré-définies en Java :


- interface Cloneable pour identifier les classes dont les instances peuvent être
dupliquées par appel à la méthode clone() (cf. Méthode clone() p 136)
- interface Serializable pour identifier les classes dont les instances peuvent être
« sérialisées » (cf java.io) ; idem pour : Flushable, Closeable.

142
Interfaces

J. Interfaces Serializable, Externalizable et mot-clé


transient
Complément
Les méthodes readObject() et writeObject() (cf. En pratique : écriture d'un fichier
« binaire » p 105) vues précédemment sont assez simples d'emploi tant qu'on se
limite à leur fonctionnement par défaut.

Etant donné leur grande utilité, il est toutefois souhaitable d'aller plus loin dans leur
étude et réaliser que leur fonctionnement dans le cas général dépend de deux
interfaces prédéfinies en Java : Serializable et Externalizable.

En effet, selon qu'une classe « implante » ou pas ces interfaces, le fonctionnement


des méthodes readObject() et writeObject() sera radicalement différent :

 Si la classe implante l'interface Externalizable alors :


a. elle implante mécaniquement Serializable (car l'interface
Externalizable hérite de Serializable) ;
b. elle doit contenir deux méthodes : readExternal() et writeExternal()
qui seront automatiquement invoquées, respectivement, en cas de
readObject() et writeObject() ;
c. ces méthodes doivent comporter l'intégralité du code nécessaire pour
réaliser correctement ces opérations sur n'importe quelle instance de ces
classes (y compris pour ce qui concerne l'ensemble des données des classes
parentes) ;
d. aucune autre méthode ne sera automatiquement invoquée.

 Si la classe implante Serializable sans implanter Externalizable alors :


a. par défaut, readObject() et writeObject() liront/écriront l'ensemble des
attributs de la classe et des classes parentes, à l'exception des attributs
déclarées explicitement comme transient ;
NOTA-BENE : dans une classe, le mot-clé transient sert à indiquer, le cas
échéant, les attributs qui ne doivent pas être sauvegardés (ces attributs ne
seront pas écrits avec le reste des attributs de la classe, et lors de la lecture
ils seront initialisés à la valeur par défaut de leur type) ;
b. il est possible en – cas de besoins très particuliers – de gérer à la main ces
opérations en redéfinissant dans la classe les trois méthodes suivantes :
 void writeObject(java.io.ObjectOutputStream out) throws
IOException
 void readObject(java.io.ObjectInputStream in) throws
IOException, ClassNotFoundException
 void readObjectNoData() throws ObjectStreamException
ATTENTION : ces méthodes doivent prendre en charger la sauvegarde et la
relecture des attributs définis dans la classe mais pas ceux définis dans les
classes parentes qui seront gérés automatiquement (de manière analogue,
récursivement donc) ;
c. lorsque l'on rend « serialisable » une classe dont la classe mère ne l'était
pas, il est nécessaire que la classe mère comporte un constructeur par
défaut (sans paramètre).
[ lire la documentation de l'interface Serializable pour plus de détails. ]

 Si la classe n'implante ni Serializable ni Externalizable alors :


a. les objets de cette classe ne peuvent pas être lus ou sauvegardés par les
méthodes readObject() / writeObject() ;
b. par défaut on est dans ce cas, mais il faut savoir que l'implantation d'une

143
interface est quelque chose qui s'hérite, autrement dit : une classe est «
serializable » si elle est déclarée comme telle ou si l'une des classes dont
elle hérite implante l'interface Serializable (idem pour Externalizable).

K. Interfaces fonctionnelles
Définition
Interface contenant une et une seule méthode abstraite non-statique.

Une interface fonctionnelle peut contenir un nombre quelconque de :


 méthodes non-statiques ;
 méthodes « par défaut » (cf. Méthodes par défaut p 146).

Complément
L'annotation (cf. Annotations p 177) @FunctionalInterface avant une définition
d'interface permet de s'assurer que l'interface comporte bien une et une seule
méthode abstraite non-statique (surtout elle empêche qu'un programmeur y ajoute
involontairement une seconde méthode abstraite dans le futur et transforme ainsi une
interface fonctionnelle en interface ordinaire).

L. Passage d'une fonction/méthode en paramètre de


méthode
Jusqu'à la version 1.8 de Java (2014), le seul moyen de passer une fonction en
paramètre à une méthode m() consistait à :
1. définir une interface I pour encapsuler la fonction à passer en paramètre ;
2. définir une classe Ck implantant I pour chaque fonction fk différente susceptible
d'être passée en paramètre à m() ;
3. définir m() comme prenant en paramètre un objet de type I ;
4. lors de l'invocation de m(), passer comme paramètre effectif correspondant à I
une instance de la classe Ck.

Exemple :
interface FonctionAUneVariable {
double appliquer(double d);
}
class Sin implements FonctionAUneVariable {
public double appliquer(double d) { return Math.sin(d); }
}
class DoubleExp implements FonctionAUneVariable {
public double appliquer(double d) {
return Math.exp(Math.exp(d));
}
}

class CN {
public static double integrer(FonctionAUneVariable f,
double deb, double fin, double pas) {
double s=0.0 , x=deb;
long n = (long) ((fin-deb)/pas)+1;
for (long k=0 ; k<n ; k++, x+=pas) {
s += f.appliquer(x);
}

144
Interfaces

return s*pas;
}
}
// ............
double d1 = CN.integrer(new Sin(), 0, Math.PI, 0.001);
double d2 = CN.integrer(new DoubleExp(), 0, 4, 0.01);
// d1 vaut 2.0 et d2 vaut 12416347058128187000000,0

Remarque
La même technique peut être utilisée pour le type de retour : le type de retour d'une
méthode peut être une interface permettant indirectement de désigner une méthode
ou fonction.

A partir de la version 8 de Java, le même exemple peut se coder beaucoup plus


simplement en combinant interfaces fonctionnelles, « lambda expressions » et
l'opérateur :: :
@FunctionalInterface
interface FonctionAUneVariable {
double appliquer(double d);
}

class CN {
public static double integrer(FonctionAUneVariable f,
double deb, double fin, double pas) {
double s=0.0 , x=deb;
long n = (long) ((fin-deb)/pas)+1;
for (long k=0 ; k<n ; k++, x+=pas) { s += f.appliquer(x); }
return s*pas;
}
}

// ............
double d1 = CN.integrer(Math::sin, 0, Math.PI, 0.001);
double d2 = CN.integrer((d) -> Math.exp(Math.exp(d)), 0, 4, 0.01);

NOTA-BENE :
 la notation C::m permet de désigner directement la méthode m définie dans la
classe C ;
 l'opérateur -> sert à définir une lambda expression (indispensable dans
l'exemple ci-dessus vu que la fonction double-exponentielle n'est pas définie en
tant que telle comme l'est la fonction sinus dans la paquetage Math).

En utilisant l'interface fonctionnelle prédéfinie « Function » du package


java.util.function, il est possible d'alléger encore le code (plus besoin de coder
d'interface telle que FonctionAUneVariable lorsque quelque chose d'équivalent
existe dans le package java.util.function) :
import java.util.function.Function;

class CN {
public static double integrer(Function<Double, Double> f,
double deb, double fin, double pas) {
double s=0.0 , x=deb;
long n = (long) ((fin-deb)/pas)+1;
for (long k=0 ; k<n ; k++, x+=pas) { s += f.apply(x); }
return s*pas;

145
}
}

// ............
double d1 = CN.integrer(Math::sin, 0, Math.PI, 0.001);
double d2 = CN.integrer((d) -> Math.exp(Math.exp(d)), 0, 4, 0.01);

NOTA-BENE :
 l'interface fonctionnelle prédéfinie Function<T, V> comporte une méthode
abstraite unique apply() prenant en paramètre une instance de la classe T et
retournant une instance de la classe V ;
 en typant le premier paramètre de la méthode integrer() par
Function<Double, Double> f, on indique que la méthode integrer() accepte
comme premier paramètre toute fonction prenant en paramètre (et retournant)
une instance de la classe Double (le type Double étant compatible avec le type
primitif double, on peut comme dans l'exemple invoquer integrer() avec une
fonction travaillant sur des double comme Math.sin()).

Remarque
Les lambda-expressions, les références sur méthodes/fonctions ainsi que le package
java.util.function ne sont pas détaillés dans ce document.

M. Méthodes par défaut


Contexte : si on ajoute a posteriori une méthode m() à une interface I alors il faut
ajouter cette nouvelle méthode dans toutes les classes qui implantent I.
Problème : comment faire si I fait partie d'une bibliothèque de classes très
répandue ; si I est implantée dans des milliers de programmes codés par des
centaines de programmeurs ?
Solution : utiliser le mot clé default pour assortir chaque nouvelle méthode d'une
implantation par défaut (éventuellement vide).
Effet obtenu : les classes qui implantent I sans implanter m() héritent de
l'implantation par défaut (donc pas besoin de toutes les modifier).

Attention
 Les méthodes par défaut ne peuvent pas utiliser les variables d'instance de la
classe.
 Si dans deux interfaces il existe une méthode par défaut commune (avec la
même signature) alors tout classe qui implante ces deux interfaces devra
impérativement surcharger cette méthode (erreur de compilation sinon).
 Soit une classe C qui implante une interface I où est définie une méthode par
défaut m(), alors si m() est surchargée dans C, son implantation par défaut
dans I reste accessible depuis la classe C avec la syntaxe : I.super.m();

N. Corps de méthodes statiques dans une interface


Il est possible de définir des méthodes statiques dans une interface dont le code sera
partagé par toutes les classes qui implantent cette interface.
Mise en œuvre : utiliser le mot clé static et définir le corps de la méthode.
Intérêt : proposer des méthodes utilitaires destinées à faciliter la programmation des
classes implantant cette interface.

146
Interfaces

O. Comparaison interfaces / classes abstraites


Beaucoup de points communs :
 non-instanciables ;
 contiennent des définitions de méthodes avec ou sans leur implantation.
Principales différences « techniques » :
 possibilité de définir des attributs non-statiques dans les classes abstraites ;
 les mots-clés liés à la visibilité (public/private/...) sont sans effet dans les
interfaces ;
 une classe peut « implanter » un nombre quelconque d'interfaces ; elle ne peut
« hériter » que d'une seule classe (abstraite ou pas).
En termes d'usage :
 les classes abstraites servent à définir un début d'implantation (modèle de
ses classes filles, définition des éléments communs) ;
 les interfaces servent à caractériser, spécifier formellement quelque
chose (un type, une propriété, ...)

Conseil : lorsque les deux sont techniquement


possibles, comment choisir entre définir une interface et
une classe abstraite ?
Il vaut mieux définir une classe abstraite :
 lorsqu'elle représente clairement un sur-ensemble de ses classes filles, et de
ses classes filles uniquement ; lorsque cette caractérisation de la relation
classes mère abstraite / classes filles est à la fois intangible et essentielle
(exemple : FigureGeometrique en tant que classe mère abstraite de
Rectangle, Cercle, ...) ;
 lorsque vous pourriez ultérieurement avoir besoin d'y définir des attributs non-
statiques ou d'y qualifier certains éléments de public/private/...
Inversement, une interface est préférable :
 si les classes ayant vocation à implanter cette interface sont de nature très
différentes (exemple : les interfaces Cloneable, Comparable, ...) ;
 si il s'agit de spécifier un comportement (liste de méthodes) sans aucun début
d'implantation (ni constructeur, ni attribut, ni corps de méthode).

147
Collections (listes,
XIII -

ensembles, files,
tables) XIII
Introduction 149
Deux versions : « paramétrée » ou pas 150
Les classes Collections et Arrays 151
Fiches pratiques et exemple d'utilisation 151
Principales interfaces et classes 154

A. Introduction
Collection = structure de donnée permettant de rassembler plusieurs éléments (ex. :
tableau, liste, …)

Java propose dans le paquetage java.util plusieurs sortes de collections :


 les listes : collection forcément ordonnée, avec possibilité de répétition du
même élément
 les ensembles (plusieurs variantes) : aucun élément dupliqué
 les files (plusieurs variantes) : correspond au type abstrait « file »
 les tables d'association (plusieurs variantes) : série de couples [clef
valeur ]

Les principales collections de java.util

149
Complément
Le paquetage java.util s'enrichit régulièrement, au fil des nouvelles versions du
langage Java 1.8 propose ainsi 9 sortes de collections (interfaces correspondant à
un type abstrait) et plus de 20 implantations (classes).

D'autres paquetages proposent d'autres sortes de collections


(java.util.concurrent, en particulier, propose des collections fort utiles dans un
contexte multi-threadé).

Remarque
A chaque sorte de collection correspond :
 une interface (spécification du type abstrait en question)
 une ou plusieurs classes qui implantent cette interface (avec des stratégies
différentes en termes de stockage en mémoire et/ou d'algorithmes).

Attention
Plusieurs restrictions à connaître lorsqu'on utilise les collections de Java :
 Les collections ne peuvent contenir que des objets (pas de types
primitifs)
 Les types ArrayList, ArrayList<String> et ArrayList<Integer> (par
exemple) sont distincts et incompatibles (bien qu'il n'y ait en fait qu'une
unique classe ArrayList)
 Il est impossible de créer des tableaux dont les éléments sont d'un type
paramétré (new ArrayList<String>[3] est par exemple illégal !)
utiliser à la place des collections de collections, e.g. :
ArrayList<ArrayList<String>> lili ;
lili = new ArrayList<ArrayList<String>>() ;

B. Deux versions : « paramétrée » ou pas


Il existe deux versions de chaque interface et classe :

1. version « paramétrée » par le type des éléments :


- stocke des éléments de n'importe quelle classe (pas de types élémentaires)
- interdit de mélanger des éléments de nature différente (typage fort)
- aucune opération particulière à coder lors des sorties de la collection
- version à privilégier sauf cas très particuliers (e.g. contenu hétérogène)

2. version « non paramétrée » :


- stocke des éléments de la classe Object (converstion automatique vers
Object à l'entrée dans la collection => aucun contrôle du typage en entrée)
- permet de mélanger des éléments de nature différente
- nécessite de convertir depuis la classe Object vers la classe véritable lors
des sorties de la collection

150
Collections (listes, ensembles, files, tables)

C. Les classes Collections et Arrays


La classe Collections contient de nombreuses fonctions utilitaires sur les
collections :
 trier : sort()
 rechercher le plus petit/grand élément : min() et max()
 remplir toutes les cases avec un même élément : fill()
 réarranger aléatoirement : shuffle()
 tester la présence d'éléments communs dans deux collections : disjoint()
 compter le nb. d'occurences d'un élément : frequency()
 …

NOTA-BENE : la classe Arrays contient le même genre de fonctions pour les tableaux.

D. Fiches pratiques et exemple d'utilisation


1. Utilisation d'une liste
import java.util.*;
class Individu {
// ...
}
 Création d'une liste d'individus :
LinkedList <Individu> rep = new LinkedList <Individu>();
 Ajout d'un individu xà la liste :
rep.addFirst(x); // ajoute en première position
rep.addLast(x); // ajoute en dernière position
rep.add(i, x); // ajoute en i-ème position
 Retrait d'un individu de la liste :
rep.removeFirst(); // retire le 1er élément
rep.removeLast(); // retire le dernier élément
rep.remove(i); // retire le i-ème élément
rep.remove(x); // retire la 1ère occurrence de l'objet x
 Accès à un individu de la liste :
x = rep.get(i); // pour récupérer le ième de la liste

2. Parcours avec un Iterator


 Création d'un itérateur qui pointe AVANT la position 0 :
ListIterator <Individu> iter = rep.listIterator(0);
 Existence d'un élément suivant / précédent :
boolean ok = iter.hasNext(); // renvoie true ou false
boolean ok = iter.hasPrevious(); // renvoie true ou false
 Renvoyer l'élément suivant / précédent :
Individu x = iter.next();
Individu x = iter.previous();
 Renvoyer l'indice de l'élément suivant/précédent :
int i = iter.nextIndex();
int i = iter.previousIndex();

151
3. Exemple d'utilisation de la classe LinkedList
On crée une liste de String (de type LinkedList) sur laquelle on exécute quelques
méthodes de l'interface List :

import java.util.*;

public class ExempleList {

public static void main(String[] args) {

List<String> pn; // DECLARATION D'UNE LISTE


pn = new LinkedList<String>(); // CHOIX DE L'IMPLANTATION

pn.add("Paul"); // INSERTION
pn.add(0, "Léa"); // INSERTION (EN *DEBUT* DE LISTE)
pn.add("Julie"); // INSERTION (EN FIN DE LISTE)

System.out.println(pn); // AFFICHAGE

int n = pn.size(); // ACCES A LA TAILLE


System.out.println("Nombre d'elements = " + n);
pn.set(1, "Marc"); // REMPLACEMENT D'UN ELEMENT

// ACCES A UN DES ELEMENTS DE LA LISTE :


String nom = pn.get(1); // ->"Marc"
System.out.println(nom);

// SUPPRESSION D'UN ELEMENT :


pn.remove(1); // retire "Marc"
// ...

On utilise un itérateur pour parcourir pn :


// PARCOURS DE LA LISTE AVEC UN ITERATEUR :
ListIterator<String> iter = pn.listIterator();
while (iter.hasNext()) {
// tant qu'il reste un élément, accès à l'élément suivant :
String s = iter.next();
System.out.println(s);
if (s.equals("Léa")) {
iter.add("Jean"); // modification via l'itérateur
}
}

String s = iter.previous(); // retour en arrière


iter.remove(); // modification via l'itérateur

pn.add("Alain"); // modification sans passer par l'iterateur !


System.out.println(pn); // OK

// ATTENTION : l'itérateur n'est plus valide après


// modification de la liste originale :
System.out.println(iter.next()); // INTERDIT !
// -> ConcurrentModificationException

152
Collections (listes, ensembles, files, tables)

4. Définition d'une relation d'ordre / l'interface Comparable


L'interface Comparable<E> spécifie que toute instance de la classe qui l'implante peut
être comparée à toute instance de la classe E. Elle contient une seule méthode :
public int compareTo(E autre);
qui doit retourner une valeur :
 < 0 ssi this « est avant » autre,
 > 0 ssi this « est après » autre,
 = 0 ssi les deux objets sont « égaux »

Elle permet d'utiliser les fonctions pré-programmées telles que sort(), exemple :
Class C implements Comparable <C> {
//...
public int compareTo(C autre) { ... }
}

Utilisation avec une liste l d'instances de la classe C :


Collections.sort(l);
Idem avec un tableau :
Arrays.sort(tab);

5. Définition d'ordres multiples / l'interface Comparator


L'interface Comparator<E> permet de définir plusieurs relations d'ordre (via plusieurs
implantions) ; elle nécessite de définir une méthode de signature :
public int compare(E e1, E e2);
qui doit retourner une valeur :
 < 0 ssi e1 « est avant » e2,
 > 0 ssi e1 « est après » e2,
 = 0 ssi les deux objets sont « égaux »

Elle permet d'utiliser les fonctions pré-programmées telles que sort() pour réaliser
des tris multi-critères, exemple :
class ComparePrix implements Comparator <Produit> {
public int compare (Produit o1, Produit o2) {
return (int) (o1.getPrix () - o2.getPrix () )
}
}
class CompareNom implements Comparator <Produit> {
public int compare (Produit o1, Produit o2) {
return o1.getNom.compareTo( o2.getNom () );
}
}

Utilisation avec une liste :


Collections.sort(listeProduits, new ComparePrix());
Collections.sort(listeProduits, new CompareNom());
Idem avec un tableau :
Arrays.sort(tabProduits, new ComparePrix());
Arrays.sort(tabProduits, new CompareNom());

153
E. Principales interfaces et classes
1. L'interface Collection
L' interface Collection (ou plutôt l'interface Collection<E>, où E est le type des
éléments) regroupe les méthodes communes à toutes les collections :
 taille : int size()
 test si vide : boolean isEmpty()
 ajout : boolean add(E elt)
 suppression : boolean remove(E elt)
 suppression de tous les éléments : void clear()
 recherche : boolean contains(E elt)
 création d'un itérateur : Iterator<E> iterator()
 conversion en tableau : Object[] toArray()
 ...

Remarque
 add(elt) renvoie false uniquement dans le cas où elt figure déjà dans la
collection et que celle-ci interdit les duplicata.
 La présence de méthodes add() , clear() et remove() véritablement
utilisables n'est pas garantie pour toutes les implantations qui implantent cette
interface : certaines implantations peuvent en effet lancer l'exception
UnsupportedOperationException quand on les appelle (cf. documentation des
différentes implantations).

2. L'interface Iterator
L'interface Iterator permet de parcourir n'importe quelle sorte de collection.
Un itérateur :
 s'obtient par appel de iterator() sur la collection à parcourir
 contient les méthodes :
- boolean hasNext()
- E next()
- void remove()

Attention
Il faut impérativement re-créer nouveau itérateur (par appel de iterator()) dès que
la collection originale a été modifiée [ par appel à add(), remove(),... en dehors de
l'itérateur ]

3. Les listes / interface List


L'interface List dérive de Collection, avec en plus des méthodes pour l'accès par
position, et itérateur spécifique :
 E get(int index)
 E set(int index, E elt)
 void add(int index, E elt)

154
Collections (listes, ensembles, files, tables)

 E remove(int index)
 int indexOf(E elt)
 ListIterator<E> listIterator(int debut)
 ListIterator<E> listIterator()
 ...

Trois implantations :
 classe LinkedList<E> (liste doublement chaînée)
 classe ArrayList<E> (tableau)
 classe Vector<E> (implantation similaire à ArrayList mais « synchronized » +
méthodes additionnelles)

Complément : principales différences entre les classes


ArrayList et Vector
 Vector est « synchronized » (utile en cas multithreading (cf. Programmation
multi-threadée p 207)) alors que ArrayList ne doit pas être utilisé sans
précaution depuis plusieurs threads
 Vector propose quelques méthodes additionnelles (voir documentation), dont :
containesAll(), copyInto(), ...
 Vector pemet au programmeur de spécifier de combien la taille effective du
tableau augmente lorsque sa capacité maximale est atteinte
 Historiquement, Vector est une classe ancienne qui existait avant l'introduction
des Collections dans Java 1.2

En pratique, et dans le cas d'un usage dans un seul thread, la classe ArrayList est
plus efficace (parcours, recherche, ...) et la classe Vector plus puissante ; il est donc
recommandé d'utiliser la classe ArrayList dès lors qu'on n'a pas besoin de ce
qu'ajoute la classe Vector.

4. L'interface ListIterator
L'interface ListIterator<E> est spécifiquement conçu pour parcourir les listes :
 s'obtient par appel de listIterator() sur la liste à parcourir
 étend l'interface Iterator<E> en ajoutant des méthodes :
- pour parcourir en sens inverse : previous(), hasPrevious(), ...
- pour insérer : add(E elt)
- pour modifier : set(E elt)
- …

ATTENTION : même restriction qu'avec les Iterator en cas de modification de la liste


originale en dehors de l'itérateur.

5. Les piles / classe Stack


La classe Stack dérive de la classe Vector, en ajoutant les méthodes :
 empiler : push(E item)
 sommet : E peek()
 dépiler : E pop()

155
Remarque
En héritant de la classe Vector, la classe Stack de Java fournit une implantation du
type abstrait pile qui inclut des méthodes permettant d'accéder directement à
n'importe quel élément, et pas juste au sommet comme on pourrait s'y attendre pour
une pile.

6. Les ensembles / interfaces Set et SortedSet


Principale différence avec les listes : dans un ensemble, il est interdit de mettre deux
fois le même élément.

L'interface Set<E> contient les mêmes méthodes que Collection<E>, plus les
méthodes suivantes :
 Test d'inclusion : e1.containsAll(e2)
 Union : e1.addAll(e2) [modifie e1 !]
 Intersection : e1.retainAll(e2) [modifie e1 !]

L'interface SortedSet<E> y ajoute des méthodes pour :


 accéder au plus grand ou au plus petit : last(), first()
 extraire un sous-ensemble : subSet(E min, E max), ...

Deux implantations :
 classe HashSet<E> pour Set<E> (utilisant une table de hachage HashMap<E,
Object>)
 classe TreeSet<E> pour SortedSet<E> (utilisant un « arbre bicolore »
TreeMap<E, Object>)

7. Les files d'attente / interface Queue


L'interface Queue<E> offre les fonctionnalités d'une file d'attente.

En plus des méthodes de Collection, on trouve :


 essai d'ajout : boolean offer(E elt) : [idem add(elt), sauf que la réussite
de l'ajout dans la file n'est pas garanti (cas d'une file pleine...)]
 récupération et suppression de l'élément en tête (si file non vide) : E poll()
 E remove() : idem poll(), mais lance NoSuchElementException si la file est
vide
 accès à la tête de file : E peek()
 E element() : idem peek() mais lance NoSuchElementException si la file est
vide

NOTA-BENE : il existe une variante BlockingQueue<E> qui, en cas d'essai d'accès à


la tête, bloque jusqu'à ce que la file soit non-vide.

156
Collections (listes, ensembles, files, tables)

8. Implantations de l'interface Queue


La principale implantation de l'interface Queue est la classe PriorityQueue<E>
(éléments traités selon leur ordre « naturel »)

Autres implantations, dans le paquetage java.util.concurrent :


 LinkedBlockingQueue<E> : une FIFO (« First In First Out ») bloquante.
 ArrayBlockingQueue<E> : une FIFO (« First In First Out ») bloquante à
capacité limitée (stockage dans un tableau).
 PriorityBlockingQueue<E> : idem PriorityQueue<E> mais en version
bloquante
 DelayQueue<E> : les éléments doivent implanter l'interface Delayed, et ne sont
traités qu'une fois leur « délai » expiré, en commençant par ceux ayant expiré
les premiers

9. Les tables d'association / interface Map


Une table d'association = série de couples (clef valeur) telle que :
1. toute clef est présente au plus une fois dans la table
2. chaque clef est associée à une unique valeur

Principales méthodes de l'interface Map<K,V>


[ paramétrée par les types respectifs K et V des clefs et des valeurs] :
 ajout d'un couple : put(K clef, V valeur)
 valeur associée à une clef : V get(Object clef)
 suppression : V remove(Object clef)
 taille : boolean isEmpty() et int size()
 recherche par clef : boolean containsKey(Object clef)
 recherche par valeur : boolean containsValue(Object val)
 collection des valeurs : Collection<V> values()
 ensemble des clefs : Set<K> keySet()
 ensemble des couples clef-valeur : Set<Map.Entry<K,V>> entrySet()
[ chaque couple est une instance de Map.Entry<K,V> ]

10. Table d'association triée / interface SortedMap


SortedMap<K,V> est un cas particulier de Map<K,V> qui garantit que les couples sont
stockés par ordre croissant de clef

Méthodes supplémentaires par rapport à Map :


 K firstKey()
 K lastKey()
 SortedMap headMap(K clefLimite)
 SortedMap tailMap(K clefLimite)
 SortedMap subMap(K clefMin, K clefMax)

157
11. Principales implantations de l'interface Map
Deux implantations principales :
 HashMap<K,V> = implantation de Map<K,V> par hachage
 TreeMap<K,V> = implantation de SortedMap<K,V> par « arbre bicolore »

Il existe une autre implantation de Map, très voisine de HashMap : la classe


Hashtable. En plus des méthodes standards de Map, elle possède les méthodes
suivantes :
 liste des éléments : Enumeration elements()
 liste des clef : Enumeration keys()

12. Collections et enum


La classe EnumSet<E extends Enum<E>> est une implantation de Set spécialisée (et
optimisée) pour le stockage de valeurs d'un même type énuméré (enum) :
 pas de constructeur : la création se fait par une des méthodes « static » de la
classe ; exemple :

Set<MonEnum> s;
s = EnumSet.allOf(MonEnum.class);

 Manipulation avec les méthodes standard d'un Set

Complément
EnumMap<K extends Enum<K>, V> est une classe offrant une implantation de Map
spécialisée et optimisée pour des tables d'association dont les clefs sont des valeurs
d'un même type énuméré.

158
Le paquetage
XIV -

java.lang
XIV
Le paquetage java.lang 159
La classe Math 160
La classe StrictMath 161
La classe System 161
La classe Runtime 162
La classe Process 162
Les classes « enveloppes » 162
La classe Character 163
La classe Number et ses classes filles 163
La classe Enum 164
La classe Class 164
La classe Field 165
La classe Method 166
Interfaces pré-définies à connaître 166

A. Le paquetage java.lang
Contient une trentaine de classes parmi les plus importantes de Java :
 la classe « racine » : Object (cf. la classe « Object » p 134)
 les classes : String, StringBuffer, StringBuilder (cf. Chaînes de caractères
p 53)
 des classes essentielles : Math, System, Runtime, ClassLoader, Thread, ...
 huit classes « enveloppes » permettant d'encapsuler les huit types
élémentaires dans des objets : Boolean, Character, Integer, Long, Short,
Byte, Double, Float
 la classe abstraite Number (classe mère d'Integer, Double, Float, ...)
 la classe abstraite Enum (classe mère des types énumérés)
 des classes permettant « l'introspection » : Class, Method, Field, …

Contient aussi quelques interfaces importantes : Comparable, Runnable, ...

NOTA-BENE : ce paquetage est importé automatiquement.

159
B. La classe Math
Constantes : Math.PI, Math.E

Calcul entre flottants (type double en entrée et en sortie) :


sin(), cos(), tan(), acos(), ... toDegrees(), toRadians()
sqrt(), exp(), log(), log10(), pow(), ...
nextUp(), nextDown(), ceil(), floor(), rint(), …

Calcul entre entiers (type int ou long) avec lancement d'une exception en cas de
dépassement :
addExact(), subtractExact(), multiplyExact(), ... toIntExact()

Autres fonctions :
 int round(float) , long round(double) : arrondis à l'entier le plus proche
 float signum(float), double signum(double) : selon le signe, retourne -1.0
, 0.0 ou 1.0
 abs(a), min(a,b), max(a,b)
pour a et b : int, long, float ou double
 double random() : nombre compris dans l'intervalle [ 0.0 ... 1.0 [ et tiré, par
défaut, d'une série pseudo-aléatoire nouvelle à chaque exécution du
programme19

NOTA-BENE : toutes les méthodes de la classe Math sont statiques (elles s'invoquent
en les préfixant par le nom de la classe : Math.sin(x), Math.sqrt(y), ...)

Complément : Arrondis
Plusieurs fonctions permettent d'arrondir une valeur flottante :
 ceil(x) : arrondi à l'entier supérieur ou égal (sous forme de double)
 floor(x) : arrondi à l'entier inférieur ou égal (sous forme de double)
 rint(x) : arrondi à l'entier le plus proche (sous forme de double)
 round(x) : arrondi à l'entier le plus proche (sous forme d'entier)
 (int) x : conversion explicite en entier (consiste à supprimer tout ce qui suit
la virgule)

EXEMPLE :
double x = -5.75;
double a = Math.ceil(x); // a vaut -5.0
double b = Math.floor(x); // b vaut -6.0
double c = Math.rint(x); // c vaut -6.0
int m = Math.round(x); // m vaut -6
int n = (int) x; // n vaut -5

Remarque
 Ne pas confondre la classe Math (du paquetage java.lang) et le paquetage
java.math (cf. La classe Number et ses classes filles p 163).
 Les fonctions dans la classe Math utilisent autant que possible les routines
19 - Pour la génération de nombres pseudo-aléatoires, voir aussi la classe java.util.Random.

160
Le paquetage java.lang

optimisées disponibles au niveau de l'environnement matériel (e.g.


processeur) ; elles peuvent donc produire des résultats différents selon les
machines (voir ci-après).

C. La classe StrictMath
StrictMath est identique à la classe Math en termes de fonctionnalités, mais avec
des caractéristiques différentes en termes de performances et de portabilité :
 utilise des algorithmes standards définis dans la bibliothèque mathématique
fdlibm « Freely Distributable Math Library »
 résultats des calculs strictement identiques quelque soit le matériel utilisé
 performances possiblement inférieures comparées à celles de la classe Math
(lorsque le hardware utilisé fournit des routines optimisées).

Conseil
 Si la vitesse est primordiale utiliser la classe Math
 Si la portabilité des résultats des calculs est essentielle utiliser la classe
StrictMath.

Remarque
Selon les machines il est tout à fait possible qu'une partie (voire la totalité) des
méthodes des classes Math et StrictMath retournent exactement les mêmes
résultats.

Complément : le mot-clé strictfp


Dans la même veine que la classe StrictMath, le mot clé strictfp (pour Strict
Floating Point) sert à indiquer que les calculs en virgules flottantes doivent se faire
dans le strict respect des spécifications Java, même si cela engendre une dégradation
de performance. Il peut être utilisé lors de la définition d'une méthode, d'une classe
ou d'une interface. Par défaut (en omettant le mot-clé strictfp ) les machines
virtuelles Java sont autorisées à optimiser certains calculs et/ou à tirer profit de telle
ou telle possibilité du matériel (processeur), ce qui peut conduire à des différences
dans les résultats de calculs en virgules flottantes entre deux exécutions d'un même
programme sur des machines différentes.

D. La classe System
La classe System contient beaucoup de choses très utiles :
 lancement forcé du Garbage Collector : System.gc()
 ordre de fin d'exécution : System.exit(int status)
 accès aux variables d'environnement : String System.getProperty(Sring
name)...
 copie rapide de tableau : System.arraycopy(src, deb, dest, debD, len)
 entrée-sorties standards : InputStream System.in, PrintStream System.out
et System.err
 redirection des I/O : System.setIn(InputStream), ...
 réglage sécurité : System.setSecurityManager(SecurityManager)
 heure (en ms depuis 1/1/1970) : long System.currentTimeMillis()

161
E. La classe Runtime
La classe Runtime est instanciée une fois (et une seule) dans chaque programme Java
s'exécutant.
Principales méthodes :
 récupération d'une instance correspondant au programme courant :
Runtime.getRuntime()
 lancement de programme externe (dans un process séparé) : Process
exec(String commande)
exemple : Runtime.getRuntime().exec("ls -l *.c");
 bilan sur l'utilisation de la mémoire : long freeMemory() et totalMemory()

F. La classe Process
La classe abstraite Process permet de gérer les programmes externes lancés en tant
que processus séparés vua la méthode exec() (cd. classe Runtime) :
 attente de fin et récupération du status : int waitFor()
 suppression du process : destroy()
 connexion avec les I/O standard :
- InputStream getInputStream() : récupère la sortie standard (pour lire
dessus)
- OutputStream getOutputStream() : permet de se connecter à l'entrée
standard du process (pour écrire des choses dessus)

G. Les classes « enveloppes »


Pour chacun des 8 types élémentaires (boolean, char, int, ...), il existe une classe
« enveloppe » (ou « wrapper ») correspondante (Boolean, Character, Integer, ...)
pour pouvoir manipuler si nécessaire des valeurs élémentaires comme des objets.
Elles ont toutes :
 un constructeur à partir d'une valeur du type primitif correspondant ;
 un constructeur à partir de String, et une méthode statique équivalente
NomClasse.valueOf(String) ;
 une méthode toString() ;
 un attribut TYPE avec l'objet de type Class correspondant.

Remarque
Les conversions dans les deux sens entre chaque type primitif et sa classe
« enveloppe » se font automatiquement :

Integer objEntier = 4;
// OK : équivalent de = new Integer(4);

Double objDouble = Double.valueOf("1.618");


double x = 10.*objDouble;
// OK : équivalent de = 10.*objDouble.doubleValue();

Object[] tab = new Object[3];


tab[0] = true;
tab[1] = 'W';
tab[2] = 33;

162
Le paquetage java.lang

// OK : équivalent de tab[0]= new Boolean(true);


// tab[1]= new Character('W');
// tab[2]= new Integer(33);

H. La classe Character
Character est la classe « enveloppe » du type primitif char :
 ne contient quasiment que des fonctions (méthodes statiques)
 test de la nature d'un caractère :
- boolean Character.isLetter(char),
- Character.isDigit(char),
- Character.isWhiteSpace(char),
- ...
 Accès au type précis d'un caractère :
- int Character.getType(char ch) renvoie un identifiant parmi :
Character.LOWERCASE_LETTER, Character.DECIMAL_DIGIT_NUMBER, ...
 changement de casse :
- char Character.toLowerCase(char), ...
 ...

I. La classe Number et ses classes filles


Classe abstraite Number = classe mère des classes Byte, Integer, Double, ...
Contenu communs aux classes « enveloppes » numériques :
 valeurs min/max du type : constantes de classe MIN_VALUE et MAX_VALUE
 méthodes de conversion : byte byteValue(), int intValue(), float
floatValue(), ...

Classes Integer, Byte, Short, Long :


 très similaires
 évaluer un entier écrit sous forme de chaîne de caractères :
int Integer.parseInt(String), byte Byte.parseByte(String), ...
 idem en précisant une base :
int Integer.parseInt(String s, int base)
 écriture en base 2 à 36 :
String Integer.toString(int val, int base)
 ...

Classes Double et Float :


 très similaires
 évaluer un entier écrit sous forme de chaîne de caractères :
double Double.parseDouble(String), ...
 infinis :
float Double.POSITIVE_INFINITY,
float Double.NEGATIVE_INFINITY,
boolean Double.isInfinite(double)
 valeur indéterminée : boolean Double.isNaN(double)
 ...

163
Complément : le paquetage java.math
Deux classes du paquetage java.math héritent également de la classe Number :
 BigInteger : entiers en précision arbitraire, nombreuses fonctions disponibles
dont certaines particulièrement pertinentes en cryptographie :
isProbablePrime(), modInverse(), ...
 BigDecimal : chiffres décimaux de très grande précision, gestion fine des
arrondis, possibilité de contrôler la précision des calculs20.

NOTA-BENE : comme pour la classe String, les instances de ces deux classes sont
immuables (une fois crée un objet de type BigInteger ne peut pas être modifié).
Outre ces deux classes, java.math inclut MathContext pour spécifier la précision des
calculs et les modalités d'arrondis dans le contexte de la classe BigDecimal.

ATTENTION : le gain en précision et en possibilité de contrôle se paie cher en termes


de performance (les temps de calculs avec des BigDecimal sont ainsi ±100 à 1000
fois plus lents qu'avec des double selon la précision demandée) et aussi de lisibilité du
code.

J. La classe Enum
Enum est la classe abstraite ancêtre de tous les types énumérés (i.e. définis avec le
mot-clef enum).

Enum implante l'interface de comparaison Comparable de sorte que toute valeur d'un
type énuméré est automatiquement comparable à toute autre valeur d'un même type
énuméré ; l'ordre « naturel » utilisé par la méthode compareTo(Enum autre) est
l'ordre de déclaration des constantes dans le type énuméré.

K. La classe Class
La classe « Class » contient la représentation abstraite des classes, interfaces et
tableaux :
 obtention d'une instance de la classe Class :
- via une instance : o.getClass()
- ou par le nom : Class.forName("NomCompletClasse")
 littéraux : NomClasse.class
(ex: String.class désigne la classe String)
 instanciation : Object newInstance()
 exploration des membres de la classe :
- Method[] getDeclaredMethods()
- Field[] getDeclaredFields()

20 - Contrôler finement la précision des calculs et des arrondis et particulièrement utile en finance lorsqu'il
s'agit de manipuler des valeurs monétaires ; on pourra donc utiliser des instance de BigDecimal plutôt que
des long pour représenter des montants exprimées dans une devise donnée (les types float et double
sont à proscrire car le manque de précision des calculs rend très difficile l'obtention de résultats
systématiquement juste ─ au centime près ─ ce qui est bien sur essentiel dans un contexte bancaire ou
autre).

164
Le paquetage java.lang

- Constructor[] getDeclaredConstructors()
- Class[] getInterfaces()
- Class getSuperClass()
- ...
 recherche d'un membre donné par son nom :
Method getMethod(String), Field getField(String), ...
informations sur la classe :
- nom complet : String getName()
- toString() : idem, précédé de « class » ou « interface » selon les cas
- boolean isInterface()
- boolean isArray()
- boolean isPrimitive()
- int getModifiers() : retourne un « masque » de la forme
Modifier.PUBLIC|Modifier.STATIC...
- type des éléments (pour tableaux seulement) : Class getComponentType()
 test d'appartenance d'un objet à la classe (instanceof dynamique) : boolean
isInstance(Object)
 accès aux annotations éventuelles (cf. Annotations p 177) :
- Annotation[] getAnnotations()

Définition : métaclasse
En termes de langages objets, on appelle couramment « métaclasse » une classe
permettant de représenter le concept de classe au sein du langage.
Tous les langages objets ne comporte pas cette notion, et quand elle existe, elle peut
s'incarner de différentes manières offrant plus ou moins de possibilités au
programmeur.
L'un des intérêts des métaclasses est de permettre l'introspection (cf. Introspection p
137).

L. La classe Field
La classe Field contient la représentation abstraite des attributs :
 implante l'interface Member :
- String getName()
- int getModifiers()
- Class getDeclaringClass()
 autres méthodes :
- set(Object instance, Object valeur)
- void Object get(Object instance)
- Class getType()
(renvoie instances spéciales int.class, double.class, boolean.class,... si
type primitif)
- Annotation[] getAnnotations()

165
M. La classe Method
La classe Method contient la représentation abstraite des attributs :
 implante l'interface Member Field (cf. La classe Field p 165)
 autres méthodes :
- Class[] getParameterType()
- Class getReturnType()
- Object invoke(Object instance, Object[] args)
- Annotation[] getAnnotations()

N. Interfaces pré-définies à connaître


Le paquetage Java.lang définit une dizaine d'interfaces dont :
 CharSequence : implantée par les classes qui représentent une séquence de
caractères (String, StringBuffer, StringBuildr, CharBuffer, ...)
 Appendable : implantée par les classes permettant l'opération ajout de
caractères (StringBuffer, FileWriter, PrintWriter, ...)
 Cloneable : voir description de méthode clone() dans section sur
classes/objets
 Comparable : interface de comparaison (voir section sur java.util)
 Iterable<T> : interface déclarant l'unique méthode Iterator<T> iterator(),
et caractérisant les types permettant les « itérations simplifiées »21
 Readable : source de caractères (implantée notamment par FileReader,
StringReader, ...)
 Runnable : voir section sur les thread
 ...

21 - C'est-à-dire les instruction de type for (item : séquence) { ... } (cf. Boucles d'itération
« simplifiées » p 40).

166
Autres classes et
XV -

interfaces à
connaître XV

Le paquetage java.util 167


Les classes Scanner et Pattern 168
La classe Random 170
La classe Objects 171
Localisation et internationalisation 172

A. Le paquetage java.util
Le paquetage java.util contient beaucoup de classes relativement importantes :
 classes et interfaces liées aux « collections » (cf. Introduction p 149)
 interface Formattable, classes Formatter, .. (cf. Entrées-sorties p 42)
 classes Scanner
 classe Random
 classe Objects
 classes Locale, ResourceBundle, ...
 classe Currency
 classes Calendar, Date, Timer, TimeZone, ...
 interface Observable et classe Observer
 ...

Remarque
Depuis la version 1.8 de Java 1.8, le paquetage java.time fournit un ensemble de
classes à la fois pratique et très complet pour gérer tous les aspects liés au temps
(instants, durées, temps universel, temps local, calendriers alternatifs, etc.)
Ces classes ne sont pas détaillées dans ce document ; si besoin penser à consulter le
tutoriel d'Oracle22 qui comporte un sentier intitulé « Date-Time APIs ».

22 - http://docs.oracle.com/javase/tutorial/

167
B. Les classes Scanner et Pattern
La classe Scanner permet de « parser » (en français : décortiquer ou « analyser
syntaxiquement ») tout ce qui est « Readable23 » (flux, Strings, etc.) :
import java.util.Scanner;

// . . .
String tst = "bleu 12 rouge 1,618";
Scanner sc = new Scanner(tst);
String s = sc.next(); // s vaut "bleu"
int k = sc.nextInt(); // k vaut 12
double x = sc.nextDouble(); // InputMismatchException !
// . . .
Scanner sc2 = new Scanner(System.in);
if (sc2.hasNextDouble()) {
double y = sc2.nextDouble();
// . . .
}

La classe Pattern du paquetage java.util.regex permet de définir et rechercher


des « expressions régulières » :
if ( Pattern.matches("[a-d].*[0-9]", chaine) ) { ... }
Pattern pat = Pattern.compile("[^aeiouy]*\s");

Usage conjoint avec Scanner :


if (scFlux.hasNext(pat)){ ... }

Complément : expressions régulières


On appelle expression régulière (ou expression rationnelle24 ou motif ou
pattern) une chaîne de caractères qui utilise une syntaxe précise, typiquement à
base de quelques caractères spéciaux ─ habituellement : . ? + * [ ] ( ) ^ et \ ─
pour décrire un ensemble de chaînes de caractères possibles.

Exemples :
 7.[xy] représente l'ensemble des chaînes composées de trois caractères,
commençant par le chiffre 7 et finissant par une lettre x ou y ;
 [a-zA-Z]* représente l'ensemble des chaînes composées exclusivement de
lettres (minuscules ou majuscules de l'alphabet latin).

On utilise très fréquemment des expressions régulières en informatique pour filtrer


des données textuelles (par exemple dans une messagerie pour identifier des spams,
ou dans un langage de script tel que PERL).
Toutefois, selon les langages et outils informatiques, il existe des différences de
syntaxe notamment concernant la sophistication des notations disponibles et l'usage
23 - L'interface java.lang.Readable sert à identifier les classes pouvant servir de sources de caractères.
Elle est implantée par une dizaine de classes prédéfinies de Java dont BufferedReader,
CharArrayReader, FileReader, InputStreamReader, StringReader, ...
24 - La dénomination d'expression rationnelle fait référence aux « langages rationnels » (ou langages de type
3) qui regroupent l'ensemble des langages formels analysables par un automate fini. Il suffit donc d'un tel
automate pour « comprendre » n'importe quelle expression régulière (les langages formels plus riches de
type 0, 1 et 2 nécessitent quant à eux des dispositifs plus puissants pour être analysés).
La dénomination d'expression régulière fait référence aux grammaires régulières qui sont le type de
grammaires permettant d'engendrer les langages de type 3.

168
Autres classes et interfaces à connaître

des parenthèses et des accolades.


Pour ce qui concerne Java, la syntaxe utilisée est particulièrement riche ; elle est très
proche de celle de PERL 5, Python, JavaScript, ... ; cette syntaxe est détaillée dans la
documentation en-ligne de la classe Pattern.
Pour un usage courant, il faut savoir que :
 . signifie un caractère quelconque ;
 [ ] définit un ensemble de caractères, exemple : [abc] a, b ou c ; [0-9]
un chiffre ;
 [! ] définit un ensemble de caractères exclus, exemple : [!xy] n'importe
quel caractère sauf x et y ;
 * signifie motif précédent répété zéro, une ou plusieurs fois ;
 *{n,m} signifie motif précédent répété au moins n fois et au plus m fois,
exemple : ab*{2,3}c abbc ou abbbc ;
 + signifie motif précédent répété une ou plusieurs fois ;
 ? signifie motif précédent répété zéro ou une fois ;
 | correspond à un « ou » entre deux motifs.

ATTENTION : ne pas confondre le concept d'expressions régulières et les « méta-


caractères »25 utilisés couramment dans les langages de commande (Shell UNIX,
DOS, ...) pour l'interprétation des noms de fichiers (les caractères utilisés sont
presque les mêmes, l'usage est similaire mais la syntaxe est radicalement différente ;
aussi, les expressions régulières constituent un dispositif beaucoup plus « puissant »
pour filtrer des données textuelles).

Exemple : Lecture depuis le clavier (sans gestion


d'erreurs)
Scanner scin = new Scanner(System.in);
System.out.println("Entrez une chaine : ");
String s = scin.next();
System.out.println("Entrez un entier : ");
int n = scin.nextInt();
System.out.println("s=" + s + ", n=" + n);

Exemple : Lecture d'un fichier ligne par ligne avec


affichage de son contenu sur l'écran
try {
Scanner sc = new Scanner(new FileReader("f.txt"));
String ligne;
while (sc.hasNextLine()) {
ligne = sc.nextLine();
System.out.println(ligne);
}
}
catch (FileNotFoundException e) {
System.err.println(e);
}

25 - Autrement dit, les caractères suivants : ? * [ ] ! \ et ~.

169
Exemple : Lecture depuis le clavier avec utilisation d'un
pattern et gestion d'erreurs
Scanner sc = new Scanner(System.in);

Pattern p = Pattern.compile( "[Yy]" );

try {
String s1 = sc.next(p);
// accepte uniquement Y ou y
}
catch(InputMismatchException e) {
System.out.println("Y ou y attendu");
}

Conseil
L'ensemble formé des classes Scanner et Pattern constitue l'outil à utiliser en priorité
chaque fois qu'il faut analyser des données en mode texte dont la structure n'est pas
complétement triviale, et ce, quelque soit la source de ces données (fichier, chaîne de
caractères, socket, ...)
Toutefois, comme pour tout aspect un peu complexe de Java, il ne faut pas chercher
à tout découvrir – et encore moins tout mémoriser – par avance.
Mieux vaut adopter une démarche pragmatique consistant à bien mémoriser les
principes puis, lorsqu'on en a besoin, rechercher les détails dans la documentation de
référence (qu'il convient d'avoir toujours accessible, soit via Internet, soit en ayant
une copie physique sur son disque dur). Tout aussi utile : penser à rechercher des
exemples dans une base telle que http://www.java2s.com (généralement plus
efficace que de chercher un exemple avec Google).

C. La classe Random
Comparée à la méthode Math.random()26, la classe Random permet :
 de contrôler le caractère reproductible ou pas de la séquence générée ;
 d'obtenir des valeurs flottantes avec une distribution de type gaussienne plutôt
qu'uniforme ;
 de générer autre chose que des double (e.g. des boolean, int, long, byte...).

Exemple
import java.util.Random;

// . . .

Random r = new Random();


r.setSeed(5); // pour rendre la séquence reproductible
// (par défaut, la séquence est différente à chaque exécution)

26 - RAPPEL : Math.random() retourne un double dans l'intervalle [ 0.0 ... 1.0 [ ; des appels successifs
produisent une série nouvelle à chaque exécution du programme ; la distribution des valeurs est
« approximativement uniforme »
cette fonction suffit tant qu'il s'agit de générer des double sans autre contrainte spécifique (caractère
reproductible de la séquence générée, caractère « sécurisé » ou pas, contextes multi-threadé, ...)

170
Autres classes et interfaces à connaître

int x = r.nextInt();
// x entier quelconque (2^32 valeurs possibles toutes équiprobables)

int y = r.nextInt(200);
// y dans l'intervalle [ 0 ... 200 [

boolean b = r.nextBoolean();

double d1 = r.nextDouble();
// d1 dans l'intervalle [ 0.0 ... 1.0 [
double d2 = r.nextGaussian();
// d2 double (valeur moyenne = 0.0 et déviation standard = 1)

Remarque : Intérêt de contrôler le caractère


reproductible de la séquence « aléatoire »
Il est essentiel de pouvoir décider si la séquence de nombres « aléatoires » sera
toujours la même ou pas lors d'exécutions répétées d'un programme. En effet, en
phase de mise au point, il est beaucoup plus simple de debugger un code qui produit
le même résultat à chaque exécution qu'un code qui se comporte différemment à
chaque fois du fait de tirages aléatoire différents. Inversement, dans un contexte
d'utilisation « normale », il est généralement préférable que les séquences générées à
chaque exécution soient différentes (exemple : utilisation de nombres aléatoires pour
faire varier des enchaînements dans un jeu).
Pour s'assurer que la séquence aléatoire soit reproductible, il suffit d'invoquer le
constructeur de la classe Random avec une « graine » identique ou d'invoquer la
méthode setSeed(), comme dans l' exemple ci-dessus.

Complément : les classes ThreadLocalRandom et


SecureRandom
Deux autres classes sont disponibles en Java pour répondre à des besoins plus
spécifiques :
 java.util.concurrent.ThreadLocalRandom : à privilégier lorsque plusieurs
threads font un usage intensif de nombre aléatoires ;
 java.security.SecureRandom : à privilégier lorsqu'il est essentiel que chaque
tirage « aléatoire » ne puisse en aucun cas être deviné sur la base des
nombres produits précédemment, ou de toute autre information accessible lors
l'exécution du programme27.

D. La classe Objects
La classe Objects28 contient une série de méthodes statiques utilitaires relatives
aux objets.
Les méthodes suivantes sont de simples variantes des méthodes équivalents de la
classe Object :
 compare(), equals(), deepEquals(), ...
[ elles permettent juste d'écrire Objects.equals(o1, o2) à la place de
o1.equals(o2) ]
D'autres méthodes de la classe Objects sont par contre fort pratiques lorsqu'une

27 - La cryptographie utilise fréquemment la génération de nombres aléatoires ; dans un tel contexte il


convient d'utiliser la classe SecureRandom du paquetage java.security.
28 - Objects avec un s, à ne pas confondre avec la classe Object (cf. la classe « Object » p 134).

171
variable de type référence peut (ou pas) contenir une référence nulle :
 hashCode(Object o)
retourne o.hashCode() ssi o est non-nul, et null sinon.
 toString(Object o, String msg)
retourne o.toString() ssi o est non-nul, et la chaîne msg sinon.

Rappel
Lorsqu'une référence o est nulle, une exception est lancée si on exécute
o.nomDeMethode() ou o.nomAttribut.

E. Localisation et internationalisation
Plusieurs classes java sont disponibles pour faciliter « l'internationalisation » des
programmes :
 classe Locale : permet l'identification d'une localisation en termes de langue et
de région (utilise les normes ISO 639 et 15924 pour les langues et les
alphabets et ISO 3166 pour les régions) ;
 classe ResourceBundle : permet d'isoler et gérer les données devant être
localisées ;
 classe Formatter (cf. Entrées-sorties p 42) : permet l'affichage des nombres,
dates, etc. selon la localisation ;
 classe Scanner (cf. Les classes Scanner et Pattern p 168) : permet la saisie des
nombres selon la localisation ;
 classe Currency : permet la manipulation des symboles correspondants aux
différentes devises (selon la norme internationale ISO 421729) ;
 ...

Définition : Localisation et internationalisation


On appelle localisation l'adaptation d'un programme informatique à une région et/ou
langue particulière. La localisation inclut différents aspects :
 la traduction de toute l'interface Homme-Machine ;
 la traduction des documentations (utilisateur, installation, etc.) ;
 la manière d'afficher (et saisir) les nombres, les dates, les monnaies, les
températures, les distances, les surfaces, etc. ;
 etc.

On appelle internationalisation l'effort consistant à rendre un programme


informatique facile à localiser ce qui (en Java) passe typiquement par :
 abstraire à l'aide de la classe ResourceBundle tout ce qui doit être localisé (en
particulier les fragments de textes utilisés pour l'interface Homme-Machine) ;
 stocker à l'extérieur du programme les versions pour chaque région/langue de
tout ce qui a été isolé dans des ResourceBundle ;
 utiliser une instance de la classe Locale pour représenter la localisation
correspondant à l'utilisateur ;
 utiliser des structures de données « localisables » et/ou afficher et saisir les
données localisables en tant compte du contenu de la localisation.

29 - La norme ISO 4217 définit une correspondance entre les noms, codes, et symboles des différentes
monnaies. Ainsi, le code numérique pour l'Euro est 978, le code sous forme de chaîne est "EUR" et le
symbole corespondant '€'.

172
Autres classes et interfaces à connaître

Conseil
Penser au tutoriel d'Oracle30 (sentier « Internationalization ») pour approfondir ces
notions de localisation et d'internationalisation, et apprendre comment les mettre en
œuvre en Java avec quelques exemples.

30 - http://docs.oracle.com/javase/tutorial/

173
Documentation
XVI -

automatique
(javadoc) XVI

Mise en œuvre :
 Nécessite d'insérer dans le code des commentaires spécifiques selon la
syntaxe :
/** bla-bla ...
(sur une ou plusieurs lignes)
*/
 javadoc NomClasse.java produit automatiquement des fichiers HTML
décrivant la classe et intégrant ces commentaires
racine = index.html

Remarque
 Les commentaires javadoc se placent juste avant les déclarations de :
- packages
- classes
- interfaces
- méthodes
- attributs
 Par défaut, seuls les éléments publics et protégés apparaissent (car ce sont les
seuls qu'ont à connaître les utilisateurs de la classe)

Complément : Tags dans les commentaires


Les commentaires javadoc peuvent comporter des « tags » qui seront formatés de
manière spécifique. Ils commencent en début de ligne par @, et vont jusqu'à fin de
ligne :
 @author nom (pour une classe ou interface)
 @param nom description (pour une méthode: commentaire sur un de ses
paramètres)
 @return description (pour une méthode : commentaire sur ce qui est
retourné)
 @exception nom description (pour une méthode : commentaire sur un type
d'exception potentiellement émise)
 @see NomClasse (lien hypertexte vers la documentation de la classe
NomClasse)
 @see NomClasse#nomMethode (idem, mais lien vers l'endroit où est décrite la
méthode nomMethode)

175
Attention
Javadoc est conçu pour documenter des packages/classes/interfaces Java afin de
faciliter leur utilisation lors de l'écriture de programmes.
Le lecteur de cette documentation est donc, typiquement, un programmeur qui
souhaite utiliser un code Java pré-existant le plus rapidement possible (sans
forcément en connaître tous les détails).
Javadoc n'est pas conçu pour :
 documenter les détails d'implantation à l'intérieur des méthodes, ou les choix
techniques effectués lors de la mise au point du programme utiliser pour cela
les commentaires ordinaires de Java ;
 produire un mode d'emploi du programme à l'intention de l'utilisateur final
pour cela, joindre une notice au programme et/ou prévoir une page d'aide dans
l'IHM.

176
XVII - Annotations

XVII
Annotations 177
Annotations standards (prédéfinies) en Java 178
Définition d'annotations 178
Le « checker framework » 179

A. Annotations
Définition
Métadonnées attachées à un élément du code source (se placent juste avant
l'élément annoté).
Ces métadonnées peuvent être exploitées :
 lors de la compilation (vérifications sémantiques, optimisations, ...) ;
 lors de l'exécution par la machine virtuelle Java (optimisations) ;
 lors de l'exécution par le code (via l'introspection) ;
 par des outils externes (javadoc, outils d'analyses, d'optimisation, ...)

Remarque
Tout ou presque peut être annoté dans un code java (déclarations, affectations,
invocations de méthodes, ...)

Syntaxe
1. annotations marqueurs : @TypeDAnnotation
2. annotations paramétrées : @TypeDAnnotation("valeur")
3. annotations multi-paramétrées : @TypeDAnnotation(attribut1 = "valeur1",
attribut2 = "valeur2", ...)
NOTA-BENE : chaque paramètre a un type (int, double, boolean, String, tableau, ...)

Exemple

class Mere {
public void demarrer() { ... }
public boolean ajuster(double[]) { ... }
}

class Fille extends Mere {


@Override
public void demarer() { ... }

177
// erreur de compilation « grâce » à l'annotation !
// ...
@Override
public boolean ajuster(double) { ... }
// erreur de compilation « grâce » à l'annotation !
}

Usages principaux
 permet de spécifier plus formellement certains aspects du code
typage plus rigoureux et/ou plus précis, possibilité de vérifications
automatiques additionnelles ;
code plus fiable ;
 permet d'expliciter l'intention du programmeur
code plus lisible, plus facile à maintenir ;
 permet d'inclure dans le code des directives destinées au compilateur, à la JVM
ou à des outils manipulant le code source ou le bytecode.

B. Annotations standards (prédéfinies) en Java


@Deprecated
@Override
@FunctionalInterface
@SafeVarargs
@SupressWarnings({"deprecation","unchecked",...})

C. Définition d'annotations
Possibilité de définir ses propres annotations
accessibles lors de l'exécution (introspection) ou depuis des outils externes.

Exemple : Définition d'une nouvelle annotation avant


son utilisation dans le code
public @interface MonAnnotation {
String arg1();
int arg2();
int arg3() default 0;
String[] arg4();
}

// .......

@MonAnnotation(arg1="hello", arg2=7, arg4={"a", "b"})


public class MaClasse {
// .......
}

Complément : Annotations relatives aux définitions


d'annotations
Plusieurs annotations standards de Java concernent la définition des annotations :

178
Annotations

 @Documented déclenche l'inclusion du contenu de l'annotation dans la


documentation produite par javadoc31 ;
 @Retention(RetentionPolicy.RUNTIME) déclenche l'inclusion du contenu de
l'annotation dans le bytecode ;
 @Target({ElementType.FIELD, ElementType.METHOD, ...}) spécifie les
éléments du code compatibles avec cette annotation ;
 ...

D. Le « checker framework »
Permet d'étendre l'ensemble des vérifications effectuées sur le code par rapport à ce
que réalise le compilateur Java.
Intérêt :
 détecter/prévenir de nombreux bugs ;
 expliciter avec précision l'intention du programmeur.
Mise en œuvre sous Java 8 : non fourni en standard, à télécharger/installer ; s'utilise
ensuite sous forme d'un « plugin » dans le compilateur java (disponible pour javac,
Eclipse et la plupart des compilateurs Java)

Annotations définies par le checker framework :


@NonNull, ...
@ReadOnly, ...
@Regex, ...
@Format, ...
...
@Length, @km, @m, @cm, ...
@Area, @m2, @km2, ...
@Mass, @kg, @g
...

31 - L'utilisation systématique de telles annotations est une alternative à l'usage de la notation /** ...
*/ ; elle peut permettre de structurer/formaliser le contenu des commentaires produits par javadoc ; elle
permet en outre leur inclusion dans le bytecode produit en cas d'utilisation combinée de @Documented et
@Retention(RetentionPolicy.RUNTIME).

179
Graphisme et
XVIII -

Interface Homme-
Machine (IHM) XVIII
Introduction 181
Composants prédéfinis d'AWT 182
Utilisation des conteneurs 184
Gestionnaires de présentation 184
Événements et programmation événementielle 186
Dessiner 192
Couleurs 193
Polices de caractères 194
Images 194
Dimensions de l'écran et des composants 195
Applet vs application 196
Ecrire une applet 196
Ecrire une application graphique 201
Swing 203
Pour aller plus loin... 205

A. Introduction
Deux sortes de programmes graphiques en Java
1. Les appliquettes (Applet)
- Elles peuvent fonctionner par le truchement d'un navigateur : Firefox, IE,
Safari, Chrome, ...
- ou via un programme spécifique : appletviewer
2. Les applications indépendantes
- Lancées exactement comme n'importe quelle application (non graphique)

Principaux packages java à disposition


 java.awt : composants et outils graphiques, audios, vidéos, ...
 java.awt.event : gestion des événements
 java.applet : création d'applets
 javax.swing : étend java.awt (plus complet mais plus complexe à maîtriser
qu'AWT)

NOTA-BENE : il existe d'autres packages pour faciliter la réalisation d'IHMs


sophistiquées : Java2D, JavaFX, SWT, Java3D, ...

181
Ce qu'il faut pour créer une IHM
 Des composants graphiques élémentaires
 Un (ou des) conteneur(s)
 Un gestionnaire de présentation associé à chaque conteneur
(éventuellement par défaut)
 Si besoin, des dessins (points, courbes, images, ...)
 Ajouter les composants graphiques au(x) conteneur(s) par l'intermédiaire du
gestionnaire de présentation
 Ecouter les événements associés aux composants graphiques (clavier, souris,
focus, choix, ...)

B. Composants prédéfinis d'AWT


AWT = Abstract Window Toolkit (boîte à outils standard en Java pour construire des
IHMs)

Complément : Swing et SWT


Au delà d'AWT il existe au moins deux autres boîtes à outils très largement utilisées
pour construire des IHMs en Java :
 Swing : fait partie du standard JAVA ; s'appuie sur AWT mais ajoute de
nombreux composants et fonctionnalités sans remettre en cause les principes
généraux d'AWT (modèle des événements) ;
 SWT : boîte à outils développée en dehors du standard Java mais largement
utilisée ; proposé comme alternative à l'ensemble AWT+Swing.

NOTA-BENE : Eclipse est écrit en Java avec une IHM programmée avec le package
SWT.

Composants « de base » et « conteneurs »


Les composants de base (boutons, etc.) dérivent, pour la plupart, de la classe
abstraite Component
Les conteneurs dérivent de la classe abstraite Container

182
Graphisme et Interface Homme-Machine (IHM)

Conteneurs prédéfinis d'AWT


Nom Fonction

Panel conteneur de base

ScrollPane conteneur pour composant unique à barre


de défilement

Frame fenêtre

Window fenêtre sans titre ni barre de défilement

Dialog fenêtre popup « modale »

FileDialog fenêtre de sélection de fichier

Applet applet (hérite de Panel, voir plus loin)

Autres composants prédéfinis d'AWT


Nom Fonction

Button bouton (cliquable)

Canvas zone pour dessiner

Checkbox case à cocher

Label texte constant

CheckboxGroup pour grouper des choix exclusifs

MenuBar barre de menu

Menu menu

MenuItem item de menu

CheckboxMenuItem item de menu à cocher

183
Nom Fonction

Choice liste déroulante de choix exclusifs

List liste de choix exclusifs ou non

ScrollBar barre de défilement

TextField zone de texte modifiable (une ligne)

TextArea idem (mais sur plusieurs lignes)

C. Utilisation des conteneurs


Pour être visible, un composant « de base » doit avoir été ajouté à un conteneur par
la méthode add() :
 c.add(Component co) : ajoute le composant co au conteneur c
 c.add(Component co, Object contrainte) : idem, avec une contrainte pour
le gestionnaire de présentation
Exemple : c.add(co, BorderLayout.WEST)
 c.add(Component co, int i) : place le composant en i-ème position (sauf
pour BorderLayout)

Autres méthodes disponibles dans les classes conteneurs :


 c.getComponentCount() : renvoie le nombre de composants dans c
 c.getComponents() : renvoie le tableau des composants dans c
 c.getComponentCount(int n) : renvoie le nième composant dans c
 c.remove(int n) : retire de c le nième composant
 c.removeAll() : retire tous les composants de c
 c.validate() : recalcule la disposition des composants (et des sous-
composants éventuels)
 Et bien d'autres ! Voir la documentation de la classe Container

Attention : la méthode validate()


Une fois un conteneur et ses composants visibles, il est toujours possible d'y ajouter
ou supprimer des composants via les méthodes add(), remove(), removeAll(), ...
L'effet de ces modifications ne sera toutefois pas visible avant appel de la méthode
validate(). En effet, pour des raisons de performance, le calcul de la disposition des
composants dans le conteneur n'est pas effectué automatiquement après tout
changement. Le calcul peut en effet être gourmand en temps de calcul lorsque des
conteneurs sont imbriquées sur plusieurs niveaux de profondeur. Par ailleurs, il est
fréquent de faire plusieurs appels successifs à remove() et add() lorsqu'on modifie le
contenu d'un conteneur. L'invocation de validate() est donc nécessaire pour
indiquer à Java qu'on a fini de modifier le conteneur et qu'on souhaite rendre visible
ces modifications.

D. Gestionnaires de présentation
Principe
La disposition des composants dans un conteneur est assurée par un «
gestionnaire de présentation » ou « Layout Manager »
Chaque conteneur a son propre LayoutManager qui place automatiquement les

184
Graphisme et Interface Homme-Machine (IHM)

composants qu'il contient


Plusieurs LayoutManagers sont pré-définis dans le package AWT, ils différent par leur
manière de disposer les composants dans « leur » conteneur
Pour affecter un gestionnaire à un conteneur :
c.setLayout(new GridLayout(2,4));

Remarque
 L'interface gestionnaire de présentation s'appelle LayoutManager, mais les
méthodes se nomment setLayout(...) et getLayout() [sans Manager après
Layout].
 Il est possible de spécifier un gestionnaire de présentation lors de la création
d'un Panel :
Panel c = new Panel(new GridLayout(2,4));
(pour un Frame ce n'est pas possible, il faut impérativement le créer puis
invoquer setLayout()).

FlowLayout
Fonctionnement du FlowLayout : de gauche à droite puis de haut en bas en
centrant, taille des composants fixe

BorderLayout
Fonctionnement du BorderLayout : 5 places prédéfinies, tailles ajustées selon la «
région »

GridLayout
Fonctionnement du GridLayout : Tableau en lignes, colonnes. Ajout par ligne puis
par colonne

185
Remarque
Il existe d'autres gestionnaires de présentation pré-définis dans AWT : CardLayout,
GridBagLayout, ...
Il en existe d'autres encore dans Swing (voir plus loin).

Complément : Gestionnaire de présentation par défaut


Si on n'affecte pas de LayoutManager à un conteneur via la métode setLayout(),
Java lui en affecte un par défaut :
 Pour les instances de Panel et Applet gestionnaire par défaut =
FlowLayout
 Pour les instances de Window et Frame gestionnaire par défaut =
BorderLayout

Exemple avec panel imbriqué


Dans cet exemple, différents conteneurs utilisent des gestionnaires de présentation
différents pour obtenir une disposition particulière :

 Fenêtre englobante : BorderLayout pour avoir les Labels au nord au sud et la


grille au centre
 Création d'un Panel pour la grille de boutons : GridLayout(5,5) pour avoir des
boutons de même taille

E. Événements et programmation événementielle


En Java, la réactivité des boutons, listes, menu, clic souris, déplacement souris, etc...
doit être assurée par une gestion d'événements : les composants graphiques
émettent des événements en réaction à certaines actions de l'utilisateur ; le
programme réagit alors à ces événements, ou pas, selon ce que le programmeur aura
décidé d'inclure dans son code.
Cela conduit à un style de programmation qui n'est plus « impératif » (séquentiel
selon un ordre des instructions déterminé par l'auteur du programme) mais dirigé par
les événements, on parle alors de « programmation événementielle »
En pratique, le programmeur sélectionne par avance les catégories d'événements qui
l'intéresse, puis écrit (dans des méthodes ad hoc) les fragments de code qui seront
invoqués si/quand tel ou tel événement se produit.

186
Graphisme et Interface Homme-Machine (IHM)

Catégories d'événements
Les événements AWT sont groupés en catégories
Chaque catégorie correspond à une classe prédéfinie en Java (et héritant d'AWTEvent)
Le nom de l'interface à implanter pour l'écoute = catégorie + « Listener »
Le nom des méthodes associées commence par le nom de la catégorie
Le paramètre passé à chaque méthode est un événement dont le type est une
classe de nom = catégorie + « Event »

Catégorie Méthode(s) Evénement

Action actionPerformed() ActionEvent

Item itemStateChanged() ItemEvent

MouseMotion mouseDragged() MouseMotionEvent


mouseMoved()

Mouse mousePressed() MouseEvent


mouseReleased()
mouseEntered()
mouseExited()
mouseClicked()

Catégorie Méthode(s) Evénement

Key keyPressed() KeyEvent


keyReleased()
keyTyped()

Focus focusGained() FocusEvent


focusLost()

Adjustement adjustementValueChanged() AdjustementEvent

Component componentMoved() ComponentEvent


componentHidden()
componentResized()
componentShown()

Catégorie Méthode(s) Evénement

Window windowClosing() WindowEvent


windowOpened()
windowIconified()
windowDeiconified()
windowClosed()
windowActivated()
windowDeactivated()

Container componentAdded() ContainerEvent


componentRemoved()

Text textValueChanged() TextEvent

187
Classification des événements par catégories vs
composants

Principes généraux des événements (AWT et Swing)

Modèle émetteur/récepteur, avec séparation claire entre :


1. les éléments d'interface qui émettent les événements ;
2. et des objets récepteurs qui « écoutent » les événements et agissent en
conséquence
Les événements sont structurés en classes qui héritent de la classe abstraite
AWTEvent
En pratique :
 Tout objet o qui doit réagir quand un type d'événement se produit dans un
certain composant c doit :
a. implanter l'interface adéquate (MouseListener, ActionListener, ...)
b. être enregistré dans la liste des objets intéressés par ce type d'événements
issus de ce composant (c.addMouseListener(o),

188
Graphisme et Interface Homme-Machine (IHM)

c.addActionListener(o), ...)
 quand un événement se produit sur le composant c, il est transmis à tous les
récepteurs enregistrés chez lui pour ce type d'événement, cela par appel de sa
méthode correspondante (e.g., pour appui sur bouton souris,
o.mousePressed(evt) pour tous les o concernés, et où evt est l'événement)

Classes « adaptateurs »
Pour chaque interface XxxListener est prédéfinie aussi une classe XxxAdapter qui
implante l'interface avec des méthodes toutes vides

Intérêt : un objet intéressé par une seule sous-classe d'événement (e.g. clic souris),
peut être défini comme héritant de la classe adaptateur correspondante, et du coup
n'avoir à redéfinir que la méthode souhaitée (e.g. hériter de la classe MouseAdapter
en redéfinissant uniquement mouseClicked())

NOTA-BENE : cette technique n'est possible que pour les classes qui n'héritent pas
d'une autre classe !

Comment écrire une méthode de gestion d'événements ?


Il faut utiliser les méthodes définies dans la classe de l'événement qu'on veut gérer :

1. Méthodes communes à tous les événements :


- Object getSource() : renvoie la référence du composant graphique qui a
émis l'événement
- int getID() : renvoie un code précisant la nature de l'événement

2. Méthodes spécifiques (selon le type d'événement) :


- ComponentEvent getComponent()
- InputEvent long getWhen(), int getModifiers(), void consume(),
boolean isConsumed()
- MouseEvent int getX(), int getY() : donnent les coordonnées de la
souris (relatives à la source écoutée)
- KeyEvent char getKeyChar() et int getKeyCode()
- WindowEvent getWindow()
- ActionEvent String getActionCommand()
- ItemEvent Object getItem() et int getStateChange()
- ContainerEvent Component getChild()

Remarque : importance de l'identificateur (ID) retourné


par la méthode getID()
Pour les événement de nature un peu complexe, l'ID permet de distinguer entre les
variantes de cet événement. Sa valeur correspond typiquement à l'une des
constantes définies au niveau de la classe d'événement considéré, par exemple :
MouseEvent.MOUSE_PRESSED, MouseEvent.MOUSE_MOVED, ... pour les MouseEvent, ou
bien KeyEvent.VK_ENTER, KeyEvent.VK_ESCAPE, ... pour les KeyEvent.

Penser à consulter la documentation de la classe d'événement utilisée dès qu'il


semble utile d'exploiter la valeur de l'ID pour coder le récepteur d'événement.

189
Où écrire une méthode de gestion d'événements ?
Plusieurs possibilités :
1. faire implanter l'interface récepteur adéquate par l'applet, la fenêtre principale,
ou la principale classe de l'interface graphique : efficace dans les cas les plus
simples
2. définir une classe dédiée qui implante l'interface récepteur adéquate (ou mieux,
qui hérite de l'adaptateur ad hoc) : efficace mais multiplie le nombre de classes
3. créer « à la volée » (juste au moment de l'enregistrer comme écouteur) une
classe qui implante l'interface récepteur adéquate : efficace mais réduit la
lisibilité du code

Exemple de gestion d'événements par la principale classe


de l'IHM
import java.awt.*;
import java.awt.event.*;

public class CliquezBouton extends Frame implements ActionListener {

static final String TITRE = "Cliquez sur le bouton !";


private Label lab;
private int k = 0;
public CliquezBouton() {
super(TITRE); // invoque le constructeur de la classe mère
Button b = new Button("++");
// Désignation de l'application comme écouteur des évènements
// de type « Action » sur le bouton b :
b.addActionListener(this);
add(BorderLayout.SOUTH, b);
lab = new Label(String.valueOf(k));
add(BorderLayout.NORTH, lab);
pack(); // agence les composants de la Frame
setVisible(true); //rend visible la Frame
}

// Méthode correspondant à l'interface « ActionListener » :


// (ici on incrémente le label à chaque appui sur le bouton)
public void actionPerformed(ActionEvent e) {
lab.setText(String.valueOf(++k));
lab.setSize(lab.getMinimumSize());
}

public static void main (String args[ ]) {


CliquezBouton monAppli = new CliquezBouton();
}

190
Graphisme et Interface Homme-Machine (IHM)

Exemple de gestion d'événements par une classe dédiée


import java.awt.*;
import java.awt.event.*;

public class FermezMoi extends Frame {


static final String TITRE = "Fermez-moi !";
private Label lab;

public FermezMoi() {
super(TITRE); // invoque le constructeur de la classe mère
lab = new Label("Fermez la fenêtre pour sortir du programme !");
add(BorderLayout.NORTH, lab);
// Désignation d'une instance de la classe EcouteurFenetre
// pour écouter les évts « Window » sur la Frame :
addWindowListener(new EcouteurFenetre());
// ...
}

public static void main(String args[]) {


FermezMoi monAppli = new FermezMoi();
}
}

// Classe dédiée à l'écoute de l'évènement « Window »


// - elle implante indirectement WindowListener en héritant
// de WindowAdapter
// - elle rédéfinit la seule méthode de l'interface pertinente ici :
// windowClosing() pour spécifier le comportement du programme
// lors de la fermeture de la frame.
class EcouteurFenetre extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0); // force la terminaison du programme
}
}

Exemple de gestion d'événements par création d'un


écouteur « à la volée » (sous la forme d'une classe
anonyme)
import java.awt.*;
import java.awt.event.*;

public class CliquezDedans extends Frame {

static final String TITRE = "Cliquez dedans !";


private String msg = "Cliquez dans la fenêtre !";
private TextArea texte;

public CliquezDedans() {
super(TITRE); // invoque le constructeur de la classe mère
texte = new TextArea(msg);
add(BorderLayout.NORTH, texte);
texte.addMouseListener (
// Création « à la volée » d'un écouteur des clics souris :
// on crée une instance de classe anonyme, héritant de
// MouseAdapter pour éviter d'écrire les méthodes non

191
// pertinentes ici
new MouseAdapter () {
public void mouseClicked (MouseEvent e) {
String s = String.format( "%s\n x=%d ; y=%d",
msg, e.getX(),e.getY() );
texte.setText(s);
}
}
);
// ...
}

public static void main(String args[]) {


CliquezDedans monAppli = new CliquezDedans();
}

F. Dessiner
Les méthodes qui permettent de dessiner utilisent un « contexte graphique »
(instance d'une sous-classe de la classe abstraite Graphics) propre au composant
dans lequel on dessine (Canvas, Panel, Applet en tant que Panel, Frame,...)
Ces méthodes sont généralement invoquées depuis le corps de la méthode
paint(Graphics g)
Principales méthodes disponibles en Java pour dessiner :
 g.drawLine(int x, int y, int x2, int y2) : dessine une ligne entre (x,
y) et (x2, y2)
 g.drawRect(int x, int y, int w, int h) : dessine un contour
rectangulaire de dimension w, h à partir de (x, y)
 g.fillRect (int x, int y, int w, int h): dessine un rectangle plein
 [ autres formes : RoundRect, 3DRect, Arc, Oval, Polygon, etc... ]
 g.drawString(String s, int x, int y) : dessine la chaîne s en (x, y)
 g.drawImage(Image im, int x, int y, this) : dessine l'image im à partir
de (x, y)
 ...

Remarque
 Repère utilisé par ces fonctions : origine en haut à gauche du composant avec
l'axe des abscisses orientée vers la droite et celui des ordonnées vers le bas
 Angles : exprimés en degrés
 Arcs et ovales : définis par leur rectangle englobant

Complément : les classes Graphics et Graphics 2D


La classe Graphics sert à simplifier l'écriture des fragments de code destinés à créer
des dessins en 2D à partir d'opérations élémentaires.
Elle permet :
1. de faire abstraction de l'endroit où on dessine (composant affiché à l'écran,
zone mémoire invisible, ...) et du matériel utilisé (écran, carte graphique, ...) ;
2. d'éviter de spécifier lors de chaque opération élémentaire de dessin l'ensemble
des paramètres à utiliser (couleurs, police, etc.).

192
Graphisme et Interface Homme-Machine (IHM)

Une variable « g » de type Graphics doit donc être perçue comme un paquet de
paramètres implicites, autrement dit un ensemble de valeurs prises en compte lors
de chaque appel d'une méthode de la série drawXXX() ou fillXXX()et qui définissent
l'endroit où on dessine, les couleurs à utiliser, etc.
Lorsque nécessaire on peut modifier tout ou partie de ces paramètres par appel des
méthodes setXXX() de la classe Graphics (voir exemples ci-après). La modification
affectera toutes les opérations de dessins effectuées postérieurement à cet appel.
Si besoin, on peut dupliquer un contexte graphique par appel de : Graphics g2 =
g.create(). On peut ensuite positionner des valeurs différentes dans g et g2 (par
exemple pour les choix de couleurs) ce qui permet ensuite de basculer entre plusieurs
« styles » au fil d'un dessin complexe : il suffira d'invoquer selon les besoins
g.drawXXX() ou g2.drawXXX() pour dessiner dans l'un ou l'autre style (mais vers une
même destination).

NOTA-BENE : la classe Graphics2D (standard en Java) étend la classe Graphics ; elle


fournit des fonctionnalités de dessin 2D plus sophistiquées que la classe Graphics,
mais aussi plus délicates à mettre en œuvre, i.e. : espace de rendu indépendant de la
résolution du matériel utilisé, notions de traits et de formes (classes Stroke et
Shape), opérations géométriques de type: translations / rotations / zoom /
intersections / ...), etc.

G. Couleurs
Couleur courante
Les dessins sur un Graphics g se font avec la « couleur courante » :
- pour consulter : Color g.getColor()
- pour changer : void g.setColor(Color c)

Couleurs d'avant-plan et d'arrière-plan


Les couleurs d'avant-plan et d'arrière-plan d'un composant x sont modifiables via
les méthodes de la classe mère Component :
- pour consulter : c = x.getForeground() et c = x.getBackground()
- pour modifier : x.setForeground(c) et x.setBackground(c)

La classe Color
Constructeur : Color(int r, int v, int b)
avec 0 <= r,v,b <= 255
Couleurs usuelles constantes de classe : Color.BLACK, Color.RED,
Color.BLUE, ...

Remarque
 Beaucoup d'autres constructeurs et méthodes sont disponibles dans la classe
Color (voir documentation en-ligne).
 Si besoin de davantage de précision dans les nuances de couleurs, le package
java.awt.color permet la manipulation de couleurs conformément aux
spécifications de l'ICC32 (norme ISO 15076-1).

32 - International Color Consortium ; site web : http://www.color.org.

193
H. Polices de caractères
Fonte courante
Chaque Graphics et Component a une « fonte courante » consultable/modifiable par
les méthodes :
 Font getFont()
 setFont(Font)

Fontes disponibles
Polices disponibles sur toutes plates-formes : Serif, SansSerif, Monospaced, Dialog et
DialogInput

Liste complète des polices disponibles (spécifique à la machine utilisée) par appel à :
String[] Toolkit.getDefaultToolkit().getFontList()

La classe Font
Constructeur : Font(String nom, int style, int taille)
où nom est du type Helvetica, style est une des constantes Font.BOLD,
Font.ITALIC, Font.PLAIN (ou une combinaison par |), et taille est la dimension en «
points »
Tests de disponibilité effective : boolean canDisplay(char), int
canDisplayUpTo(String), ...

Remarque
 Beaucoup d'autres constructeurs et méthodes sont disponibles dans la classe
Font (voir documentation en-ligne).
 Si besoin de davantage de puissance dans la manipulation des polices de
caractères (métrique, ...) package java.awt.font

I. Images
Classe Image
Chargement par la méthode getImage(url_base,name) de Applet, ou bien, hors des
applets, par la méthode getImage(name) de la classe Toolkit (on obtient un Toolkit
par getToolkit(), ou bien par Toolkit.getDefaultToolkit())
Affichage dans un Graphics : boolean drawImage(Image i, int x, int y,
ImageObserver o)
Quelques méthodes de la classe Image :
 int getHeight(ImageObserver)
 int getWidth(ImageObserver)
 Image getScaledInstance(int l, int h, int method)
 Graphics getGraphics() pour pouvoir dessiner dessus

Remarque
 Formats d'images supportés en standard : BMP, GIF, JPEG, PNG et WBMP
 A savoir :
- getImage() rend toujours la main immédiatement (le chargement effectif

194
Graphisme et Interface Homme-Machine (IHM)

se fait dans un thread qu'elle lance)


- ImageObserver : interface de gestion de chargement d'image. En pratique,
mettre comme valeur du paramètre correspondant le composant sur lequel
on affiche l'image
- drawImage() retourne false ssi les pixels de l'image changent (par
exemple parce que l'image n'est pas encore entièrement chargée)
- drawImage() dessine la partie de l'image qui est déjà chargée

Complément : dessiner dans un objet Image non visible


(double-buffering)
Dans certains cas (e.g. pour produire des animations fluides) on peut avoir besoin de
préparer un dessin plus ou moins complexe dans une instance de la classe Image non
visible à l'écran afin de pouvoir afficher le dessin très rapidement une fois l'image
prête. Pour faire cela :
1. créer une image par :
Image img = createImage(l, h); // méthode de Component
2. récupérer un Graphics associé :
Graphics gi = img.getGraphics();
3. dessiner sur gi
4. quand on le souhaite, afficher l'image dans le composant voulu par appel de
drawImage() sur le Graphics associé au composant (et non à l'image) :
g.drawImage(img) ;

Conseil : sauvegarder une image sur fichier (class


ImageIO)
La classe ImageIO facilite la sauvegarde d'une image sur fichier dans l'un des formats
disponibles en standard sous Java.

Exemple :

BufferedImage monImage = ...


// ...
try {
File f = new File("monImage.png");
ImageIO.write(monImage, "png", f);
} catch (IOException e) {
// ...
}

J. Dimensions de l'écran et des composants


Pour connaître les dimensions de l'écran en pixels (par exemple pour adapter celles
des fenêtres) :
Toolkit.getDefaultToolkit().getScreenSize(): renvoie une instance de la
classe Dimension (avec des attributs publics width et height)

Pour connaître les dimensions d'un composant (en fait, de son rectangle englobant) :
Dimension getSize()
int getWidth() et int getHeight()

195
Pour modifier les dimensions d'un composant :
setSize(Dimension d)
setMinimumSize(Dimension d)
setMaximumSize(Dimension d)
setPreferedSize(Dimension d)

Attention
 Sauf cas très particuliers, ne pas invoquer setSize() sur les composants dont
la taille est gérée par un gestionnaire de présentation (LayoutManager).
 L'effet des méthodes setSize(), setMinimumSize(), ... n'est absolument pas
garanti : en pratique, il s'agit d'une requête émise par le programmeur et qui
ne sera satisfaite que dans la mesure du possible par le gestionnaire de
géométrie et le système d'exploitation.

K. Applet vs application
Une applet étant un code téléchargé sur le réseau puis exécuté au sein d'un
navigateur, Java impose un certain nombre de restrictions de sécurité ( accès aux
fichiers, connexions réseau, lancement d'autres programmes, etc...) => certaines
applications ne peuvent pas être des applets

Une applet nécessite de créer un fichier HTML (balise <APPLET>) en plus du fichier
.java

Principales différences entre applets et applications :

Applet Application

Fichiers Prog.html +Prog.java Prog.java

Compilation en mode javac Prog.java javac Prog.java


texte

Exécution en mode appletviewer Prog.html ou java Prog


texte via le navigateur

Méthodes init(), paint(), start(), ... main(), paint(),...

Fenêtre principale celle de l'applet Frame ou Jframe à créer

Restrictions Nombreuses : accès Celles du langage


fichiers, sécurité, etc... uniquement

L. Ecrire une applet


Principe
Ecrire une applet c'est :
1. Créer un fichier MonApplet.html (ou éditer une page HTML existante)
2. Créer un fichier MonApplet.java contenant une classe MonApplet qui dérive
de la classe Applet (penser à importer le package java.applet)
3. Dans la classe MonApplet, redéfinir tout ou partie des méthodes suivantes :

196
Graphisme et Interface Homme-Machine (IHM)

4. Ajouter si besoin attributs et autres méthodes nécessaires

NOTA-BENE : pas de main (une applet n'est pas un programme Java ordinaire)

En pratique : écriture du fichier .html


Dans le fichier MonApplet.html insérer une balise (tag) :
< APPLET code="MonApplet.class" width=w height=h >
......
</APPLET>
où w et h sont 2 nombres entiers définissant la largeur et la hauteur, en pixels, de la
zone réservée à l'applet dans la page HTML.

NOTA-BENE : <APPLET> et </APPLET> on peut insérer d'autres éléments, en


particulier :
 <PARAM> name = mon_param value = ma_valeur
 du texte qui apparaitra en lieu et place de l'applet si le navigateur ne peut pas
la charger.
Exemple :

<HTML>
<HEAD>
<TITLE> Exemple </TITLE>
</HEAD>
<BODY>
<APPLET code=MonApplet.class width=800 height =300>
<br>
Le navigateur n'a pas pu charger une applet !
</APPLET>
</BODY>
</HTML>

En pratique : écriture du fichier .java


Détail des méthodes à redéfinir (ou pas) dans la classe Applet :
 init() : lancée automatiquement, une seule fois, au démarrage
initialisation de l'applet : on crée ici les composants dont on aura besoin, on
initialise objets et variables utiles
 start() : lancée automatiquement au rechargement
comme init() mais on n'indiquera que les variables à réinitialiser en cas de
re-démarrage de l'applet
 update() : invocation manuelle ou automatique
lancée automatiquement par le navigateur (par exemple lorsqu'on remet
l'applet au premier plan). Par défaut : efface puis appelle paint()
 paint(Graphics g) : lancée automatiquement pour (re-)dessiner
prend en paramètre le contexte graphique de l'applet. On y fera typiquement
appel aux méthodes g.draw(), g.fill(), g.setColor(), etc. Par défaut : ne
fait rien !
 destroy() : lancée automatiquement avant destruction de l'applet
permet, par exemple, de terminer des threads lancée dans init() ou
start(). Par défaut : ne fait rien !
 stop() : lancée automatiquement quand l'applet devient invisible
redémarrage avec start()

197
NOTA-BENE : lors du chargement de l'applet, le navigateur (ou appletviewer) :
1. rapatrie le fichier .class ;
2. charge la classe dans la JVM ;
3. crée une instance de cette classe ;
4. lui applique init(), puis start() ;
5. lui applique update() quand nécessaire.

Autres méthodes disponibles dans la classe Applet :


 repaint() : lancée par le programme dès qu'il le faut, on peut faire appel à
cette méthode pour forcer le programme à redessiner l'applet à un moment
donné (changement de couleur, dessin d'un nouveau composant, etc.)
 getImage(URL base, String name) : renvoie un objet de type Image à partir
d'un fichier image
 getAudioClip(URL base, String name) : renvoie un objet de type AudioClip
à partir d'un fichier son
 getDocumentBase() : renvoie un objet de type URL (récupération de l'URL du
fichier html contenant l'applet)
 getCodeBase() : renvoie un objet de type URL (récupération de l'URL du
répertoire de l'applet)
 getparameter() : retourne sous forme de String les paramètres passés dans
la balise <PARAM>
 ... et bien d'autres ...

Complément
En théorie, la méthode start() (resp. stop()) est exécutée à chaque fois que l'applet
est exposée ou réexposée (resp. masquée) ; par exemple lors des navigation avant
arrière, changement d'onglet etc...
En pratique, les navigateurs usuels ne respectent pas forcément cette « règle du jeu
» définie par les auteurs de Java ce qui a pour effet que ces méthodes sont invoquées
moins souvent qu'elles devaient l'être.

Exemple : Applet composée d'un bouton et d'un label


où s'affiche le nombre de clics sur le bouton
import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class ButtonApplet extends Applet


implements ActionListener {

private Label lab;


private int k=0; // un simple compteur de clic

public void init() {


Button b = new Button("Cliquer là");
lab = new Label("0");
b.addActionListener(this);
add(b);
add(lab);
}

198
Graphisme et Interface Homme-Machine (IHM)

// Méthode correspondant à l'interface ActionListener :


// on incrémente le compteur de clic à chaque appel
public void actionPerformed (ActionEvent e) {
lab.setText(String.ValueOf (++k)) ;
lab.setSize(lab.getMinimumSize ()) ;
}
}

Exemple : Affichage d'une image avec un son joué


durant l'affichage
import java.applet. * ;
import java.awt.*;
import java.net.*; // pour la classe URL

public class ImageSonApplet extends Applet {

private Image img;


private AudioClip son;

public void init () { // télécharge l'image et le son


URL base = getDocumentBase () ;
img = getImage (base, "im.gif") ;
son = getAudioClip (base, "s.au") ;
}
public void start () {
son.loop (); // joue le son
}
public void stop () {
son.stop () ; // stoppe le son
}
public void paint (Graphics g) {
g.drawImage (img, 0, 0, this) ; // affiche l'image
}

Remarque : la méthode getAudioClip() et l'interface


AudioClip
 La méthode getAudioClip() retourne immédiatement (même si le fichier
demandé est inaccessible) ; le chargement effectif des données a lieu ensuite
lorsque le son est joué pour la première fois.
 Formats de fichiers audios/musicaux lisibles en standard en Java : AIFF, AU,
WAV, MIDI Type 0, MIDI Type 1, et Rich Music Format (RMF)
 Quelque soit le format du son, l'interface AudioClip garantit l'existence des
trois méthodes suivantes : play(), stop() et loop()
 Si plusieurs audioclips sont joués par play()ou loop(), ils sont « mixés »
automatiquement et le son résultant est joué.

199
Exemple : Une applet animée simple (sans thread) :
affiche un disque dont le rayon varie au fil du temps
import java.applet.*;
import java.awt.*;

public class AnimApplet extends Applet {

private int x=50, y=50, r=5, dr=1;


private final int MAX_DIM=40;

public void paint (Graphics g) {


g.fillOval (x, y, 2*r, 2*r);
iteration ();
repaint (); // demande de redessiner
}

public void iteration () {


if ( r>MAX_DIM || r<1 ) {
dr *= -1; //changement sans variation
}
r += dr; //modification du rayon
}

Exemple : La même chose mais animée via un thread


import java.applet.*;
import java.awt.*;

public class AnimApplet2 extends Applet implements Runnable {

private int x=50, y=50, r=5, dr=1, dt=100 ;


private final int MAX_DIM=40;
private Thread anim;
private boolean suspendAnim = false;

public void init() {


anim = new Thread(this);
}

public void start () {


if ( ! anim.isAlive () ) {
anim.start () ;
} else {
suspendAnim = flase ;
}
}

public void paint (Graphics g) {


g.fillOval (x, y, 2*r, 2*r) ;
}

public void run () { // corps du thread d'animation


while (true) {
if (! suspendAnim) {
if (r>MAX_DIM || r<1) {

200
Graphisme et Interface Homme-Machine (IHM)

dr* = -1;
}
r += dr ;
}
try { Thread.sleep (dt); }
catch (InterruptedException e) {}
repaint () ;
}
}

public void stop () {


suspendAnim = true ;
}

L'instruction implements Runnable spécifie que la classe contient une méthode


run(), et peut donc servir à créer un Thread (cf. Programmation multi-threadée
p 207).

M. Ecrire une application graphique


Principe
Ecrire une application graphique indépendante c'est :
1. Créer une fenêtre principale (au minimum)
2. Y ajouter les conteneurs et composants souhaités
3. Programmer l'aspect réactif de l'IHM (« écouter » les événements utiles et y
réagir)
4. Dessiner ce qui doit l'être (et redessiner chaque fois qu'il le faut)

En pratique
1. Créer une fenêtre principale :
- créer une classe dérivant par exemple du conteneur Frame (ou Jframe en
Swing)
- y définir une méthode main qui instanciera cette classe (création d'un objet
de la cette classe principale = création de la fenêtre principale de l'IHM)

2. Conteneurs et composants :
- déclarer les autres composants graphiques comme attributs de cette classe
- dans le constructeur, créer les composants graphiques et les ajouter au(x)
conteneurs (en particulier le conteneur Frame correspondant à l'application
elle-même)
- si besoin, modifier les layoutManager par défaut pour obtenir la
présentation voulue

3. Programmer l'aspect réactif de l'IHM :


- déclarer les « écouteurs » sur les composants susceptibles de générer des
événements
- écrire les méthodes de gestion des événements soit dans la classe
principale soit dans des classes spécifiques

4. Dessiner ce qui doit l'être :


- redéfinir la méthode paint(Graphics g) dans les classes où c'est utile

201
(éléments à y dessiner par l'une des méthodes de la série g.drawXXX())
- invoquer la méthode repaint() pour rafraichir les dessins lorsque nécessaire

Exemple : Une application graphique avec juste un


bouton
import java.awt.*;
import java.awt.event.*;

// La classe hérite du composant AWT Frame (fenêtre indépendante)


public class TestBouton extends Frame {

//attribut de ma fenêtre : un bouton


Button b;

// constructeur de ma classe :
public TestBouton(String titre) {
super(titre); // invoque le constructeur de la classe mère
b = new Button ("Cliquer ici !"); // crée le bouton
b.addActionListener (new EcouteurBouton()); //écouter
add(BorderLayout.NORTH, b); // ajoute le bouton b à la Frame
pack(); // agence les composants de la Frame
setVisible(true); //rend visible la Frame
}

// Méthode main : on y crée juste une instance de la classe


public static void main (String args[ ]) {
TestBouton monAppli = new TestBouton( "Essai" );
}

Reste encore à programmer la classe EcouteurBouton qui va permettre de réagir aux


clics sur le bouton :

class EcouteurBouton implements ActionListener {


public void actionPerformed ( ActionEvent e ) {
System.out.println("Clic bouton détecté !");
}
}

Remarque
On aurait pu ne pas créer cette classe et coder l'écoute du bouton dans la classe
TestBouton. Pour cela, il aurait fallu que TestBouton implante l'interface
ActionListener et qu'on écrive la méthode ActionPerformed ci-dessus dans la
classe TestBouton. L'écoute serait déclarée comme ceci :
b.addActionListener(this)

202
Graphisme et Interface Homme-Machine (IHM)

N. Swing
Introduction
Swing = package standard Java (import javax.swing) = complément et/ou alternative
à AWT :
 permet la réalisation d'IHMs plus sophistiquées qu'avec AWT seul
 modèle d'événements commun avec AWT (mais avec des types d'événements
additionnels)

Avantages par rapport à AWT :


 davantage de composants (et composants plus riches)
 nombreux mécanismes additionnels (double-buffering, paramétrage, ...)
 portabilité supérieure (IHM davantage similaire entre les machines/OSs par
raport à AWT)

Inconvénients par rapport à AWT :


 performance et fiabilité moindre qu'avec AWT (car les composants Swing sont
intégralement « dessinés » au lieu de faire intervenir les composants de la
plate-forme d'exécution)
 complexité très supérieure (threads, séparation modèle/présentation, ...)
 intégration moins parfaite au plan graphique avec les autres applications non
écrites en Java

Les applets Swing


Classe JApplet indispensable pour utiliser des composants Swing dans une applet
Sous-classe de la classe Applet de AWT, fonctionne donc de la même façon , sauf :

1. existence d'une « contentPane » (comme dans tous les conteneurs « top-level


» de Swing) ce qui implique :
- tout composant (ou sous-Panel) c doit être ajouté à la contentPane par
getContentPane().add(c);
- le « layoutManager » est celui de la contentPane (BorderLayout par défaut)
et se modifie donc par getContentPane().setLayout(...);

2. possibilité de positionner une barre de menu par setJMenuBar(...);

Les fenêtres Swing


Classe JFrame indispensable pour utiliser des composants Swing dans une fenêtre
Sous-classe de la classe Frame de AWT, fonctionne donc de la même façon , sauf :

1. existence d'une « contentPane » donc :


- tout composant (ou sous-Panel) c doit être ajouté à la contentPane par
getContentPane().add(c);
- le « layoutManager » est celui de la contentPane (BorderLayout par défaut)
et se modifie donc par getContentPane().setLayout(...);

2. possibilité de définir un comportement par défaut quand on ferme la fenêtre


(exécuté après les windowClosing(...) des WindowListener enregistrés) par
setDefaultCloseOperation(...);

203
Composants Swing ayant leur équivalent en AWT
La plupart des composants graphiques usuels d'AWT ont leur équivalent Swing, qui a
le même nom avec un J devant :
 JComponent : ancêtre de tous les composants Swing (sauf JApplet, JDialog,
JFrame)
 JButton : bouton usuel
 JCheckBox : cases à cocher « indépendantes »
 JLabel : texte affiché par le programme
 JList : liste « scrollable » de choix
 JTextField, JTextArea : pour entrer du texte
 JPanel : conteneur de base pour grouper des composants
 JDialog : fenêtre secondaire (« esclave »)
 JMenu, JMenuBar, JMenuItem, JPopupMenu : pour les menus
 JScrollBar : barre de défilement
 JScrollPane : pour donner une vue « scrollable » d'un seul composant
 JWindow : fenêtre sans barre de titre ni bordure
Ces équivalents Swing ont généralement plus de fonctionnalités que leurs homologues
AWT

Attention : classes JCheckBox et JRadioButton


 Dans le nom de la classe JCheckBox, il y a une majuscule à Box, contrairement
à l'équivalent AWT qui est Checkbox !
 Pour des cases à cocher mutuellement exclusives, on doit utiliser la sous-
classe JRadioButton (voir ci-dessous).

Autres composants spécifiques à Swing


Composants simples :
 JRadioButton : sorte de JCheckBox, mais avec un autre look et permettant
des choix mutuellement exclusifs via ButtonGroup
 JComboBox : liste déroulante (sorte de Choice de AWT mais avec plus de
fonctionnalités)
 JPasswordField : sorte de JTextField masquant les caractères tapés (par
exemple pour saisie de mot de passe)
 JTextPane : zone de texte éditable avec police de caractères et style
 JSlider : curseur pour choisir graphiquement une valeur numérique
 JToolTip : bulle d'aide
 JProgressBar : barre d'avancement de tâche
 JTable : tableau (éditable) de données
 JTree : représentation de données arborescentes (façon Windows Explorer)
 JToolbar : barre d'outils
 JColorChooser : utilitaire pour choix de couleur

Conteneurs :
 JOptionPane : boites de dialogue créables et affichables par un simple appel
de fonction :

204
Graphisme et Interface Homme-Machine (IHM)

JOptionPane.showMessageDialog(...);
message + 1 bouton OK
int r=JOptionPane.showConfirmDialog(...);
message + boutons style Oui / Non / Annuler
int r=JOptionPane.showOptionDialog(...);
message + choix de boutons
String s=JOptionPane.showInputDialog(...);
message + zone saisie texte + boutons OK / Annuler
 JSplitPane : pour afficher deux composants côte à côte (ou l'un au-dessus de
l'autre), et avec ligne de séparation déplaçable par l'utilisateur
 JTabbedPane : regroupement de plusieurs composants accessibles via des
onglets
 JFileChooser : fenêtre de sélection de fichier sorte de FileDialog de AWT
mais en mieux)
 JInternalFrame : pour disposer de sous-fenêtres dans une fenêtre (sortes de
« bureaux virtuels »)

Autres classes et mécanismes apportés par Swing


 Nouveaux gestionnaires de présentation (layoutManagers) : BoxLayout,
GroupLayout, OverlayLayout, SpringLayout, ViewportLayout
 Gestion fine du « focus » (destination des frappes au clavier), bulles d'aide,
icônes, ...
 Immense souplesse concernant les possibilités de modifier l'aspect et/ou la
manière de fonctionner de ses composants prédéfinis (à la fois au niveau de
chaque composant, mais aussi au niveau global de l'IHM)
 Mise en œuvre du « design pattern MVC » (séparation stricte entre modèle
abstrait des données et présentation à l'écran), possibilité de paramétrer la
présentation des contenus dans les composants selon le type des données, ...

O. Pour aller plus loin...


Attention
Il existe :
 beaucoup d'autres classes (et méthodes) disponibles dans les packages AWT et
Swing ;
 plusieurs autres paquetages Java pour aller plus loin dans la réalisation d'IHMs,
en particulier : Java2D, JavaFX (plate-forme développée par Oracle pour la
création d'IHM « riches » pour le web, destiné à succéder à Swing
progressivement à partir de 2014), ...

Conseil
Penser à consulter la documentation en-ligne des classes Java, rechercher
des exemples, .... Parmi les nombreux tutoriaux disponibles en-ligne, celui
d'Oracle33 comporte par exemple deux sentiers très complets intitulés « Creating a
GUI With JFC/Swing » et « Creating a JavaFX GUI ».

33 - http://docs.oracle.com/javase/tutorial/

205
206
Processus légers
XIX -

(threads)
XIX

Programmation multi-threadée 207


Thread 208
Classe Thread 208
Création de threads 208
Suspension / arrêt de thread 209
Exemple de thread 209
Synchronisation des données 210
Synchronisation des exécutions 210
Blocages 211
Priorités des threads 211
Groupement de threads 212
Penser à utiliser la documentation 212

A. Programmation multi-threadée
 Un « thread » ou « processus léger » est une séquence d'instructions
exécutées séquentiellement

 Un meme programme peut facilement lancer plusieurs threads au sein d'un


même processus « lourd »
exécution « en parallele »
avec partage des memes données

 Intérets : interactivité, réactivité (essentiellement pour les interfaces homme-


machine), et plus léger que multi-process Unix

 Inconvénients : problemes de synchronisation, de gestion des ressources


partagées, risque de « deadlock », caractere non déterministe

 Applications : IHMs (animation notamment), programmation réseau

207
Remarque
Un programme « normal » sans appel explicite à des instructions qui créent des
threads :
s'exécute dans un seul thread qui va « dérouler » les instructions écrites par le
programmeur en commençant par la première ligne de la fonction main()
mais d'autres threads peuvent avoir été lancés par Java pour optimiser de manière
transparente pour le programmeur certaines tâches dans la machine virtuelle

B. Thread
Un thread Java est un fil d'exécution interne au programme, représenté par un objet
(instance de la classe Thread) qui possede :
 une instruction courante
 un état (actif, inactif, en attente, ...)
 un nom (facultatif)

Attention
Pour qu'un thread s'exécute, il faut
1. le créer ;
2. ensuite, le démarrer

C. Classe Thread
 Démarrage par invocation de la méthode start() pré-programmée dans la
classe Thread
 start() fait appel à la méthode run()
 Arret quand on sort de run() par fin normale ou exception

 Mise en sommeil du thread courant :


méthode statique Thread.sleep(long milliseconds)

 Changement de thread courant (pour laisser la main aux autres threads) :


méthode statique Thread.yield()

D. Création de threads
Deux bonnes manieres pour créer un thread :
 soit creer une classe derivee de Thread, et redéfinir sa méthode run()
 ou bien, creer une classe implantant l'interface Runnable, donc ayant une
méthode run(), puis créer un Thread avec ce Runnable en parametre du
constructeur

voir exemples ci-après

208
Processus légers (threads)

E. Suspension / arrêt de thread


Pour pouvoir suspendre/arreter un thread, faire en sorte qu'il teste périodiquement un
(ou des) drapeau(x) lui indiquant s'il doit etre suspendu/redémarré/arreté.

Exemple :
Class Test implements Runnable {
private Thread t;
private boolean suspendThread=false, stopThread=false;
public void run() {
while ( !stopThread ) {
if ( !suspendThread ) {
// ... (tâche de fond du thread)
}
}
}
public static void main(String[] args) {
t = new Thread(this);
t.start();
// ...
suspendThread = true; //suspension
// ...
suspendThread = false; //redemarrage
// ...
stopThread = true; //arret definitif
}
}

F. Exemple de thread

class Compteur extends Thread {


private int compteur=0;
private boolean pause=false, stop=false;

public void run() { // lancé lorsque le thread démarre


while ( !stop ) {
if ( ! pause ) {
compteur++;
}
try {
sleep(50);
}
catch (InterruptedException e) {}
}
}
public int valeur() { return compteur; }
public void suspendre() { pause = true; }
public void redemarrer() { pause = false; }
public void tuer() { stop = true; }
}

209
G. Synchronisation des données
 Gestion des conflits de modification de données par verrou (« lock ») sur les
méthodes déclarées avec le mot-clé synchronized
durant toute l'exécution par un thread d'une méthode synchronisée, aucun
autre thread ne peut appeler simultanément une autre méthode synchronisée
du même objet
 Possibilité de faire un « bloc synchronisé » exigeant un lock sur un objet
donné :
synchronized (obj) {
//...
}

 Possibilité de déclarer volatile les attributs modifiées de manière non-


synchronisé (dans plusieurs threads)
force le compilateur à rechercher valeur courante à chaque accès

Exemple
Exemple de bloc synchronisé :
synchronized (System.out) {
// ICI plusieurs invocations de println()
// devant impérativement s'afficher
// à la suite.
}

L'utilisation de synchronized permet d'obtenir un accès exclusif à la ressource


System.out (durant l'exécution du bloc). Elle garantit ainsi que d'autres threads ne
vont pas pertuber la séquence de println(). Si un autre thread essaie d'utiliser
System.out pendant que le bloc est en cours d'exécution, cet autre thread sera
(temporairement) bloqué jusqu'à la fin de traitement du bloc.

H. Synchronisation des exécutions


 Attente de condition remplie : appel de la méthode wait() de l'objet sur lequel
le thread travaille, exemple :
class FileAttente {
Element tete, queue;
public synchronized Element suivant() {
try {
while (tete==null) {
wait();
// wait() libère le verrou et met en sommeil ;
// réveil depuis un autre thread par notify
// sur cette instance (voir ci-dessous)
// ou à l'expiration de la temporisation si on
// avait invoqué : wait(timeout)
}
}
catch(InterruptedException e) { return null; }
return tete;
}

210
Processus légers (threads)

 Déblocage de threads en attente sur l'objet courant : méthodes notify() et


notifyAll() de l'objet, exemple :

public synchronized arrivee(Element e){


// ajout du nouvel élément dans la file
// ...
notifyAll();
}

 Attente de fin d'un autre thread (rendez-vous) : appel de la méthode join()


de ce thread

Calcul c; // Calcul doit implanter Runnable


Thread calc = new Thread(c);
calc.start();
//...
try {
calc.join(); // attente de la fin du thread calc
}
catch (InterruptedException e) {
// ...
}

Remarque
 Pour invoquer wait(), il faut avoir un lock sur l'objet la méthode doit être
synchronisée
 La méthode notifyAll() réveille tous les threads en attente sur l'objet,
notify() en réveille au plus un (mais on ne sait pas lequel !)
 On peut faire t.join(timeout) pour bloquer au maximum timeout
millisecondes

I. Blocages
La programmation avec threads nécessite de faire très attention à ce qu'aucun
blocage mutuel (ou « deadlock ») ne puisse se produire.

Cas typiques de blocage :


 t1 attend la fin de t2 et réciproquement ,
 t1 attend la fin de t2 alors qu'il a un « lock » sur un objet sur lequel t2 attend
de pouvoir mettre un « lock » ;
 t1 suspend t2 pendant qu'il a un « lock » sur o, puis essaie de prendre un
« lock » sur le même o.

J. Priorités des threads


Plus sa priorité grande, plus le thread dispose d'une part importante du temps
d'exécution

Priorité par défaut : Thread.NORM_PRIORITY

Méthodes à connaître :
 getPriority()
 setPriority(int p) avec p entre Thread.MIN_PRIORITY et
Thread.MAX_PRIORITY

211
 sleep(long milliseconds) : met en sommeil le thread courant
 yield() : interrompt le thread courant pour permettre à un autre de prendre
la main

Complément : Threads et processeurs multi-cœurs


La manière dont sont gérées les threads sur le processeur dépend à la fois du type
d'ordinateur, de la version de java utilisée et de l'implantation de la JVM utilisée.
Le modèle le plus courant (celui implanté par la plupart des JVM correspondant à des
versions récentes de Java) consiste à utiliser autant que possible les threads du
système d'exploitation (« native threads ») plutôt que de gérer les threads au niveau
de la JVM (« green threads »).
Lorsque le modèle suivi est « native threads », chaque thread crée depuis Java est en
fait un thread géré par le système d'exploitation. Dans ce cas, c'est le système
d'exploitation qui attribue, par défaut, chaque thread à un cœur du processeur.
Lorsque le modèle suivi est « green threads », tous les threads crées depuis Java
s'exécutent en fait au sein d'un même thread du système d'exploitation, et donc sur
un même cœur du processeur. L'avantage de ce modèle est de pouvoir fonctionner
sur tout système d'exploitation, y compris lorsque la gestion des threads par le
système d'exploitation n'est pas satisfaisante pour faire fonctionner efficacement
n'importe quel programme Java multi-threadé. L'inconvénient est qu'il ne tire pas
profit des architectures multi-cœurs et se révèle (dans la majorité des cas) moins
performant qu'une gestion au niveau du système d'exploitation lorsqu'elle est
possible.
Au delà du fonctionnement « par défaut » consistant à laisser le système
d'exploitation attribuer chaque thread Java à un cœur, il est possible dans un
programme Java de contrôler la distribution des threads sur les différents cœurs et
d'optimiser ainsi les performances en présence d'un processeur multi-cœurs.
Dans la classe Runtime, la méthode availableProcessors() permet de connaître le
nombre de cœurs disponibles, ce qui est primordial dans la mesure où la performance
optimale atteignable sur une architecture multi-cœurs s'obtient en évitant à la fois les
sous-utilisations de certains cœurs et la multiplication des threads affectés à un
même cœur.
Les autres classes à utiliser pour optimiser un programme pour un processeur multi-
cœurs sont disponibles dans le package java.util.concurrent (voir en particulier la
classe ForkJoinPool).

K. Groupement de threads
La Classe ThreadGroup permet de regrouper des threads que l'on veut pouvoir traiter
de la même façon (par exemple les suspendre tous ensemble, modifier la priorité de
tous en même temps, …)

L. Penser à utiliser la documentation

Conseil
Il existe beaucoup d'autres classes (et méthodes) disponibles en java pour développer
des programmes multi-threadés efficaces et fiables.

Penser au tutoriel d'Oracle34 dont le sentier « Essential Java Classes » comporte un


sous-sentier intitulé « Concurrency ». L'un des avantages des tutoriaux d'Oracle est

34 - http://docs.oracle.com/javase/tutorial/

212
Processus légers (threads)

qu'ils sont systématiquement mis à jour avec chaque nouvelle version du langage ─
or ce point est particulièrement important concernant les aspects concurrents du
langage qui ont tendance à évoluer plus fréquemment que le reste (introduction de
nouveaux modèles conceptuels pour la synchronisation, le positionnement des
threads sur les cœurs, etc.)

213
Programmation
XX -

réseau
XX
Paquetage java.net 215
Accès aux protocoles Internet 215
Exemple d'utilisation de la classe URL 216
Connexion réseau bas niveau 216
Exemple de Client 217
Exemple de serveur 217
Penser à utiliser la documentation 218

A. Paquetage java.net
Le package java.net permet :
 la manipulation des URL
 l'accès aux protocoles standards de l'Internet (http, ftp, mail, ...)
 la communication inter-processus, la création d'architectures de type « clients-
serveur »

B. Accès aux protocoles Internet


Classe URL (protocoles http, ftp, ...) :
constructeurs : URL(String nom), URL(URL base, String nom), ...
ouverture de flux en lecture : InputStream openStream()
manipulation plus fine, infos sur le contenu via URLConnection openConnection(),
puis méthodes de URLConnection :
 connect(),
 getContentType(), getContentLength(), ...
 getInputStream(), getOutputStream()

Manipulation adresse internet :


classe InetAddress (instances obtenues par InetAddress.getLocalHost() ou
InetAddress.getByName(String host))

Remarque : La classe URL permet :


 d'envoyer un e-mail en ouvrant un URL de type « mailto:destinataires », et en
écrivant dedans avec un PrintWriter
 d'envoyer des données à un formulaire HTML
 de se conecter à un site web et den extraire du contenu
 ....

215
C. Exemple d'utilisation de la classe URL
import java.net.*;
import java.io.*;

class VisuHTML {
public static void main(String[] args) {
try {
URL url = new URL(args[0]);
URLConnection c = url.openConnection();
c.connect();
String type = c.getContentType();
if ( type.startsWith("text") ) {
InputStream in = c.getInputStream();
InputStreamReader isr = new InputStreamReader( in );
BufferedReader br = new BufferedReader( isr );
// NOTA-BENE : readLine() possible sur un BufferedReader
String ligne;
while ( (ligne=br.readLine() ) != null) {
System.out.println(ligne);
}
br.close();
}
else {
System.out.println("Fichier de type " + c.getContentType());
}
}
catch(Exception e) { System.out.println(e); }
}
}

D. Connexion réseau bas niveau


Communication entre deux programmes : via une connexion passant par un « port
» (logique) d'une machine « hôte »

Une « socket » = une « prise » (au sens de prise électrique) = l'extrémité d'une
connexion

Pour coder la partie « client » : classe Socket


 constructeur Socket(String host,int port)
 ouverture flux I/O : getInputStream(), getOutputStream()
 fermeture connexion : close()

Pour coder la partie « serveur » : classe ServerSocket


 constructeur : ServerSocket(int port)
 méthode pour attendre connexion de clients : Socket accept()
 fermeture serveur : close()

Manipulation directe de paquets : classes DatagramPacket et DatagramSocket

216
Programmation réseau

E. Exemple de Client
import java.net.*; import java.io.*;

class ClientMiroir {
public static void main(String[] arg) {
try {
Scanner sc = new Scanner(System.in);
// ouverture socket (port=9999, host=arg[0]) :
Socket client = new Socket(arg[0], 9999);
// ouverture de deux flux sur socket :
OutputStream out = client.getOutputStream();// flux écriture
InputStream in = client.getInputStream(); // flux lecture
while (true) {
String s = sc.nextLine(); // lecture d'une ligne au clavier
out.write(s.getBytes()); // envoi des bytes au serveur
out.write('\n');
out.flush();
// lecture sur socket :
byte [] buf = new byte[1000];
in.read(buf);
s = new String(buf);
System.out.println(s); // affichage à l'écran
}
}
catch (IOException e) { System.out.println(e); }
}
}

F. Exemple de serveur
import java.util.*; import java.net.*; import java.io.*;

class ServeurMiroir {
public static void main(String[] arg) {
try {
// mise en route du serveur sur port 9999 :
ServerSocket serveur = new ServerSocket(9999);
Socket client = serveur.accept(); // attente connexion client
InputStream is = client.getInputStream(); // flux lecture
OutputStream out = client.getOutputStream();// flux ecriture
// fonctionnement du serveur :
StringBuffer buf = new StringBuffer();
do {
int c = is.read(); // lecture caractere par caractere
if (c == -1) { break; } // fin de flux
if (c != '\n') { buf.append( (char) c ); } // cas général
else { // traitement des fins de ligne sur flux lecture
buf.reverse();
out.write(buf.toString().getBytes());
out.flush();
buf = new StringBuffer();
}
} while (true);
} catch (IOException e) { System.err.println(e); }
}
}

217
G. Penser à utiliser la documentation
Conseil
Il existe beaucoup d'autres classes (et méthodes) disponibles en java pour mettre en
place des architectures distribuées, échanger des données, etc.
Penser au tutoriel d'Oracle35 sur le sujet pour approfondir ces aspects du langage (le
tutoriel d'Oracle est organisé sous forme de sentiers dont un sentier intitulé « Custom
Networking » qui permet de découvrir plus en détail les principaux éléments de java
liés à la programmation réseau.)

35 - http://docs.oracle.com/javase/tutorial/

218
Annexe : ressources
XXI -

complémentaires sur
Java XXI
Ce support de cours ne saurait remplacer un ouvrage de référence sur le langage
Java, et encore moins l'ensemble des documentations, cours et bases d'exemples
disponibles via la page du cours sur le site web de l'Ecole.
Concernant spécifiquement le langage Java, il serait vain de vouloir tout apprendre
par avance : une fois les bases du langage maîtrisés et les différents paradigmes bien
assimilés, il convient de se dire qu'étant donné la maturité du langage, tout problème
qu'on est susceptible de rencontrer avec telle ou telle classe a, très probablement, été
déjà surmonté, et largement documenté – il suffit donc de savoir trouver rapidement
les éléments de solutions nécessaires en utilisant au mieux :
1. la documentation de référence ;
2. les bases d'exemples ;
3. les tutoriaux.

Apprendre à exploiter aux mieux ces ressources est donc primordial pour
programmer efficacement.
Aussi, il importe en premier lieu de savoir quelles ressources sont disponibles, leurs
différences, et quand/comment les utiliser : c'est l'objet de cette annexe.

Documentation de référence
 Diagramme cliquable en forme de table des matières (« Java Platform
Standard Edition Documentation ») 36 : donne accès à l'ensemble de la
documentation relative à l'édition de Java utilisée 37 et en particulier aux
documentations :
- des outils tels que javac, jar, javadoc, javah, ...
- des technologies de déploiement telles que Java Web Start
- des packages standards (regroupées par thèmes : Input/Output, Math,
Sound, ...)
- de la machine virtuelle

NOTA-BENE : chaque clic sur un thème, une technologie, ... ouvre une
page qui rassemble à la fois les tutoriaux et les manuels (APIs 38)
correspondants.

Conseil
 Dans la mesure du possible (espace disque suffisant), il est recommandé
d'installer une copie physique de toute la documentation de référence
Java sur son disque dur afin de pouvoir y accéder sans latence, et a fortiori en
l'absence de connexion internet.

36 - Toute la documentation de référence est disponible sur le site d'Oracle à la fois en mode téléchargement
(on récupère alors un fichier compressé à installer sur son disque dur) et en mode consultation :
http://docs.oracle.com/javase
37 - J2SE dans le cadre de ce cours.
38 - API = Application Programming Interface (en français : Interface de programmation)

219
 Il faut maîtriser au moins deux modes de navigation dans la
documentation de référence :
a. si on sait dans quelle classe, ou package, se trouve ce qu'on cherche il
faut partir de la page qui rassemble les manuels de toutes les APIs
standards (celle avec la liste des packages en haut à gauche et la listes des
classes et interfaces en dessous) ; il convient donc d'avoir à tout instant
cette page sous la main dans son navigateur (à ajouter à sa liste de
favoris) ;
b. sinon il faut partir de la page avec le diagramme cliquable (à ajouter aussi
à sa liste de favoris) et explorer de manière descendante les thématiques
proposées jusqu'à atteindre le tutoriel et/ou l'API recherché.

Bases d'exemples, fragments de code, etc.


 Base d'exemples très riche et bien organisée du site Java2s (en anglais) :
http://www.java2s.com/Tutorial/Java/CatalogJava.htm
NOTA-BENE :
- La base d'exemples de Java2s comporte des centaines de fragments de
code couvrant quasiment tous les aspects de Java SE (Standard Edition), et
au delà : Java EE, JAVA ME, SWT, Spring, exemples de patterns, ...
- De nombreux autres sites proposent des collections d'exemples, en général
bien moins complètes et/ou moins bien structurées que celle de Java2s.
 Moteurs de recherche de projets informatiques et/ou fragments de code :
nombreux outils disponibles dont JExamples39 (recherche de fragments de
codes Java) et Ohloh Code40 (indexe les codes de la plupart des logiciels libres,
multi-langages).

Cours, tutoriaux, ...


Il existe littéralement des milliers de cours sur Java dans toutes les langues et pour
tout type de publics dont :
 la série de tutoriaux en anglais d'Oracle (idéal pour approfondir un sujet :
chaque tutoriel couvre un aspect du langage comme Swing, Java2D, JavaFX,
RMI, ... plus les technologies connexes telles que WebStart, ...) :
http://docs.oracle.com/javase/tutorial
 le tutoriel en français d'openclassrooms (ex. site du zéro) : « Apprenez à
programmer en Java » (d'autres tutoriaux sont disponibles sur le même site
sur JavaEE, Android, les JARs, les sockets, ...) : http://fr.openclassrooms.com

A noter pour les débutants complets : « Programmation Java pour les enfants, les
parents et les grands-parents »41 (en principe totalement inutile après ce cours mais à
conseiller, comme suggéré dans le titre, pour les enfants, cousins, neveux, grands-
parents, amis, voisins, ... qui voudraient s'initier à l'informatique à travers Java).

Conseil : Quand utiliser telle ou telle ressource ?


Il n'y a pas de règle précise, c'est avant tout une affaire de bon sens, et
d'expérience :
 si on ne connaît pas du tout un aspect de Java dont on va devoir faire un usage
intensif (par exemple manipuler des sons, accéder à une base de données, ou
faire du graphisme en 3D) commencer par lire un tutoriel sur le sujet ;
 si on connaît un package mais qu'on a besoin de quelques détails sur une

39 - http://jexamples.com
40 - http://code.ohloh.net/
41 - http://java.developpez.com/livres/javaEnfants

220
Annexe : ressources complémentaires sur Java

méthode consulter en premier le manuel de référence (API correspondant au


package) ;
 si on cherche à résoudre une difficulté ponctuelle (par exemple créer une
image transparente ou formater une date dans un style précis) rechercher un
exemple.
Aussi, il ne faut pas hésiter à essayer rapidement toutes ces ressources à tour de
rôle, d'où l'intérêt de les avoir enregistrées par avance dans ses favoris.

Sélection d'autres sites utiles pour aller plus loin en Java


 Java Developer Network d'Oracle (site de référence sur Java) :
http://www.oracle.com/technetwork/java/index.html
 Java2s (déjà mentionné pour sa base d'exemples) : http://www.java2s.com
 JavaWord : http://www.javaworld.com
 Stack Overflow (500.000+ questions/réponses sur Java) :
http://stackoverflow.com/questions/tagged/java
 Developpez.com (en français) : http://java.developpez.com

Ces sites comportent de nombreuses ressources : FAQ, forums, articles scientifques


sur la conception du langage, annonces/discussions sur les prochaines versions, accès
aux packages non-standards, outils connexes, ...

Remarque
Le site http://www.java.com (géré par Oracle) est destiné aux utilisateurs de
programmes Java : il inclut un outil pour vérifier la bonne installation de la
technologie Java sur sa machine, des conseils sur l'installation du JRE, ...

221
Annexe : ressources
XXII -

complémentaires sur
l'algorithmique XXII
Contrairement aux techniques de programmation – et a fortiori aux langages
informatiques – qui évoluent à un rythme relativement rapide, les connaissances en
algorithmique n'évoluent que lentement et s'appuient sur un socle désormais très
large et de nature pérenne, à l'image de l'algèbre élémentaire ou de la physique
classique.
Il est donc logique que les meilleures ressources pour approfondir ses connaissances
dans ce domaine soient des livres et pas des sites webs.
Parmi les meilleures ouvrages pour aller plus loin à l'issue de ce cours :
 Algorithm Design par John Kleinberg & Eva Tardos, Pearson Education :
ouvrage excellent car très complet et relativement facile à lire.
 The Art of Computer Programming, volumes I-IVa (également connu sous
son acronyme TAOCP) par Donald Knuth, Addison Wesley : ouvrage de
référence, de nature quasi-encyclopédique bien qu'écrit pas un seul auteur, pas
vraiment facile à lire mais d'une rigueur absolue.

223
Index

: : (opérateur)... p.144 affectation........ p.34, 47 auto-flush......... p.101


! (opérateur)..... p.33 AJAX................ p.19 availableProcessors() p.211
!= (opérateur)... p.33 Algol (langage). . p.15 awt (package)... p.182
? : (opérateur) p.35 algorithme........ p.65 AWTEvent (classe) p.186
// .................... p.31 algorithmique, algorithmie Basic (langage). p.15
/* ... */............ p.31 p.69 BigDecimal (classe) p.163
/** ... */.......... p.175 allOf().............. p.158 BigInteger (classe) p.163
. (opérateur)..... p.80 Android............ p.22, 219 binaire.............. p.28
^ (opérateur).... p.33, 34 animation......... p.194, 196 bloc.................. p.30, 36
~ (opérateur).... p.34 annotations....... p.177 blocage mutuel (notion)
-- (opérateur). . . p.35 appel (de méthode) p.59 p.211
@Deprecated.. . . p.178 Appendable (interface) BlockingQueue (interface)
@Documented... p.178 p.166 p.156
@FunctionalInterface p.144, applet, appliquette p.196, BMP (format d'image)
178 196 p.194
@Override........ p.131, 178 applet, appliquette (notion) boolean............ p.33
@Retention....... p.178 p.181 boolean (mot clé) p.27,
@SafeVarargs. . . p.178 appletviewer (commande) 162
@SupressWarnings p.178 p.196 BorderLayout (classe)
@Target........... p.178 arbre (type)...... p.117 p.184
& (opérateur).... p.33, 34 arbre bicolore.... p.158 boucles............. p.37, 39
&& (opérateur). . p.33 arbre binaire..... p.118 branche............ p.118
% (opérateur)... p.32 arbre général.... p.118 break (mot clé). p.38, 41
++ (opérateur). p.35 arbres binaires de recherche brevet.............. p.65
+=, -=, *=, ... (opérateurs) p.120 buble sort......... p.72
p.34 arc................... p.118 buffer............... p.117
<, >, <=, >= (opérateurs) arguments........ p.60 bufférisation...... p.101
p.33 ArithmeticException p.32 bulle (tri).......... p.72
<<, >>, >>> (opérateurs) ARM................. p.15 Button (classe). . p.196
p.34 ArrayBlockingQueue (classe) byte (mot clé). . . p.28
= (opérateur).... p.34 ....................... p.157 bytecode.......... p.19
== (opérateur). p.33 arraycopy()....... p.48, 161 byteValue()....... p.163
-> (opérateur). . p.144 ArrayList (classe) p.154 C (langage)....... p.15, 19,
| (opérateur)..... p.33, 34 Arrays (classe). . p.151, 153 20, 63
|| (opérateur). . . p.33 arrondi............. p.160 C# (langage). . . . p.15
abs()................ p.160 ASCII............... p.30 C++ (langage). . p.15, 19,
abstract (mot clé) p.132 assembleur (langage) 20, 63
accept()............ p.216 p.15 calculabilité....... p.66
accesseur......... p.88, 111 assert (mot clé). p.97 calculable (problème ou
actionPerformed() p.186 assertion (notion) p.97 fonction)........... p.66
adapteur (notion) p.186 attribut............. p.81, 130, calendrier......... p.167
addActionListener() p.186 165 CAML, ML (langages) p.15
addAll()............ p.156 attribut statique. p.85 canDisplay()...... p.194
addExact()........ p.160 audio (formats de fichiers) canDisplayUpTo() p.194
addMouseListener() p.186 p.196 capacité............ p.53
addWindowListener() p.186 AudioClip (interface) p.196 caractères......... p.27, 162,

225
163 Comparable (interface) Deprecated (annotation)
case (mot clé).. . p.38, 55 p.153 p.178
casting............. p.35 Comparator (interface) dérivée (classe). p.130
catch (mot clé). . p.91, 93, 94 p.153 dessiner........... p.192
ceil()................ p.160 compareTo()..... p.53 destroy().......... p.162, 196
chaînage........... p.112, 120 compareToIgnoreCase() destructeur....... p.84
chaînes de caractères p.53 Dimension (classe) p.195,
p.53, 168 compatibilité ascendante 195
chaînes modifiables p.53 p.20 directive........... p.177
chaînes non modifiables compilation....... p.45, 124 disjoint().......... p.151
p.53 complexité........ p.67, 77 do (mot clé)...... p.39
char (mot clé). . . p.27 Component (classe) p.182 documentation automatique
Character (classe) p.27, composant graphique (notion) p.21, 31, 175
162, 163 ....................... p.182 Documented (annotation)
charAt()............ p.53 concaténation.... p.53 p.178
checked (exceptions) p.94 concurrent (package) double (mot clé) p.28, 162
checker framework p.179 p.211 double-buffering p.194
chemin............. p.118 const (mot clé). . p.29 drawImage()..... p.192, 194
Class (classe).... p.164 constantes........ p.29, 30, 56 drawLine()........ p.192
class (mot clé)... p.80 constructeur...... p.81, 131 drawRect()........ p.192
classe (notion). . p.79 constructeur par recopie drawString()..... p.192
classe abstraite. p.133 p.81 droit d'auteur.... p.65
classe anonyme. p.186 Constructor (classe) p.164 durée............... p.167
classe effective. . p.132 Container (classe) p.182 dynastique (numérotation)
classe fille (ou classe dérivée) contains()......... p.Erreur : p.118
....................... p.130 source de la référence non Eclipse.............. p.21, 134
classe mère (ou super-classe) trouvée écouteur d'événements
....................... p.130 containsAll()...... p.156 (notion)............ p.186
classe non-dérivable p.133 containsKey().... p.157 éditions (de Java) p.22
classes anonymes p.128 containsValue(). p.157 effective (classe) p.132
classes enveloppes p.162 conteneur (notion) p.184 efficacité........... p.67
classes internes (ou nichées) contentPane...... p.203 elements()........ p.158
....................... p.128 contexte graphique p.192 ElementType..... p.178
classes locales... p.128 continue (mot clé) p.41 ellipse.............. p.62
CLASSPATH....... p.123 contrôlées (exceptions) else (mot clé).... p.37
clear().............. p.Erreur : p.94 encapsulation.... p.123, 130,
source de la référence non conventions de nommage 130
trouvée p.30 en place (tris). . . p.69
client-serveur.... p.216 conversion (opérateur de) ensemble.......... p.156
Clojure (langage) p.15, p.35, 160 en-tête............. p.57
22 corps................ p.57 entiers (nombres) p.28,
clone()............. p.136, 142 createImage()... p.194 32, 162
Cloneable (interface) p.136, Currency (classe) p.172 entrées-sorties. . p.42
142 Dalvik............... p.22 entrySet()......... p.157
close().............. p.101 deadlock (notion) p.211 Enum (classe). . . p.164
Closeable (interface) p.142 décidabilité....... p.66 enum (mot clé). p.40, 55,
cœurs............... p.211 décidable (problème ou 89, 164
Collection (interface) p.Erreur fonction)........... p.66 EnumMap (classe) p.158
: source de la référence non déclaration (de variable) EnumSet (classe) p.158
trouvée p.30, 30 enveloppes (classes) p.162
collection (notion) p.149 déclaration (de variables) equals()............ p.134
Collections (classe) p.151 p.48 Error (classe).... p.94
Color (classe).... p.193 deepEquals()..... p.48 espace de nommage p.123
color (package). p.193 deepToString(). . p.48 événement (notion) p.186
commentaires. . . p.31, 175 default (mot clé) p.38, 146 événementielle (style de
compact (notion) p.125 DelayQueue (classe) p.157 programmation) p.186

226
Index

Exception (classe) p.93 Formatter (classe) p.42, goto (mot clé). . . p.41
exceptions........ p.91, 95 172 Graphics (classe) p.192
exceptions contrôlées (ou forName()......... p.137, 164 Graphics2D (classe) p.192
non)................. p.94 Fortran (langage) p.15 GRD (parcours). p.119
exec().............. p.162 freeMemory().... p.162 green threads (notion)
exécution.......... p.45 frequency()....... p.151 p.211
exit()............... p.161 fuite de mémoire (notion) GridLayout (classe) p.184
expression rationnelle p.48 Groovy (langage) p.22
(notion)............ p.168 function (package) p.144 GWT................. p.22
expression régulière (notion) FunctionalInterface hashCode()....... p.134, 171
....................... p.168 (annotation)...... p.144, 178 HashMap (classe) p.158
extends (mot clé) p.129, Garbage collector (GC) HashSet (classe) p.134, 156
141 p.48, 84, 161 HashTable (classe) p.158
Externalizable (interface) gc()................. p.161 Haskell (langage) p.15
p.143 GDR (parcours). p.119 headMap()........ p.157
fdlibm.............. p.161 généalogique (numérotation) héritage............ p.129, 141
feuille............... p.118 ....................... p.118 heure............... p.161
fichiers............. p.100, 101, generics (types génériques heuristique........ p.67
103 paramétrés)...... p.150 hexadécimal...... p.28
Field (classe)..... p.165 générique (programmation) hôte................. p.216
FIFO................. p.116 p.136 ICC.................. p.193
File (classe)...... p.108 gestionnaire de présentation IEEE-754.......... p.28
file (type)......... p.116, 156 (notion)............ p.184 if (mot clé)........ p.37
file d'attente...... p.117 getAnnotations() p.164, 165, IllegalArgumentException
FileInputStream (classe) 166 p.137
p.106 getAudioClip(). . . p.196 Image (classe). . p.194
FileOutputStream (classe) getBackground() p.193 image (formats supportés)
p.105 getBytes()........ p.217 p.194
FileReader (classe) p.103 getChars()........ p.53 ImageIO (classe) p.194
fill()................. p.151 getClass()......... p.134, 164 ImageObserver (interface)
fille (classe)...... p.130 getColor()......... p.193 p.194
fillRect()........... p.192 getContentPane() p.203 impérative (style de
final (mot clé). . . p.29, 56, getDeclaredFields() p.164 programmation) p.186
133, 133 getDeclaredMethods() implantation (d'une interface)
finalize()........... p.134 p.164 ....................... p.141
finally (mot clé). p.91, 93 getFontList()..... p.194 implements (mot clé)
firstKey().......... p.157 getForeground() p.193 p.141
float (mot clé). . . p.28, 162 getGraphics().... p.194 import (mot clé) p.124
floatValue()....... p.163 getHeight()....... p.195 indexOf().......... p.154
floor().............. p.160 getID()............. p.186 InetAddress (classe) p.215
flottants (nombres) p.28, getImage()....... p.194 inférer.............. p.Erreur :
32, 161, 162 getInputStream() p.216 source de la référence non
FlowLayout (classe) p.184 getInterfaces(). . p.164 trouvée
flush().............. p.101 getLayout()....... p.184 infinity.............. p.28
Flushable (interface) p.142 getModifiers().... p.165 infixé................ p.119, 120
focus................ p.203 getOutputStream() p.216 init()................ p.196
fonction............ p.57 getParameterType() p.166 insertion (tri). . . . p.71
Font (classe)..... p.194 getProperty().... p.161 instance............ p.79
font (package)... p.194 getReturnType() p.166 instanceof (mot clé) p.83,
for (mot clé)..... p.40 getRuntime(). . . . p.162 130
forêt................. p.118 getScaledInstance() p.194 instant.............. p.167
ForkJoinPool (classe) p.211 getScreenSize(). p.195 int (mot clé)...... p.28, 162
format()........... p.42 getSource()....... p.186 interface (mot clé) p.139
formats de fichiers audio getType()......... p.165 interface de marquage
p.196 getWidth()........ p.195 p.142
Formattable (interface) GIF (format d'image) p.194 Interfaces fonctionnelles
p.42 Gosling, James. . p.18 p.144

227
interfaces internes (ou JFrame (classe). p.203 long (mot clé). . . p.28, 162
nichées)........... p.128 JOptionPane (classe) p.203 loop()............... p.196
internationalisation (notion) JPEG (format d'image) main().............. p.25, 45, 60
p.172 p.194 Map (interface).. p.157
interne (classe ou interface) JRadioButton (classe) marker interface p.142
p.128 p.203 marqueur......... p.142
introspection (notion) JRE (Java Runtime marshalling....... p.105
p.137, 177 Environment).... p.21 masquage......... p.130
intValue()......... p.163 JRuby (langage) p.22 masquage (notion) p.131
invocation (de méthode) JTextPane (classe) p.203 Math (classe).... p.160
p.59 JVM.................. p.19 math (package). p.160, 163
invoke()........... p.166 Jython (langage) p.22 MathContext (classe) p.163
isInfinite()........ p.163 keys().............. p.158 MAX_VALUE...... p.163
isLetter(), isDigit(), keySet()........... p.157 max()............... p.151, 160
isWhiteSpace(), etc. p.163 Knuth, Donald. . . p.65, 223 membre (de classe) p.80
isNaN()............. p.163 Label (classe).... p.196 memory leak (notion)
ISO 4217.......... p.172 label (mot clé)... p.41 p.48
isProbablePrime() p.163 lambda expression p.18, mère (classe).... p.130
Iterable (interface) p.40 144 métaclasse........ p.164
itérateur (notion) p.154 lang (package). . p.159 métadonnée...... p.177
Iterator (interface) p.154 langage binaire.. p.15 Method (classe). p.166
JApplet (classe). p.203 langages de programmation méthode........... p.79, 80,
JAR.................. p.219 p.15 81, 130, 166
java2D (package) p.205 langages de programmation méthode abstraite p.132
Java2D (package) p.219 logique............. p.15 méthode de classe p.87
java2s.com (site web) langages fonctionnels méthode non-redéfinissable
p.42, 168, 219 p.15 p.133
java3D (package) p.205 langages impératifs p.15 Méthodes par défaut p.146
javac (commande) p.196 langages orientés objets méthode statique p.87
Java card.......... p.22 p.15 MIN_VALUE....... p.163
Java Developer Network (site langages rationnels (notion) min()............... p.151, 160
web)................ p.219 p.168 ML, CAML (langages) p.15
javadoc............ p.21, 31, lastKey().......... p.157 MMIX............... p.65
178 LayoutManager (interface) modInverse().... p.163
javadoc (commande) p.175 p.184 modulo............. p.32
Java EE, J2EE (Java length()............ p.53 monnaie........... p.172
Enterprise Edition) p.22, length (pour les tableaux) Moore (loi de).... p.67
219 p.48 mot-clé (notion) p.25
JavaFX............. p.181, 205, licences............ p.21 motif (notion).... p.168
219 LIFO................. p.113 MouseAdapter (classe)
javah............... p.63 linéarisation...... p.105 p.186
Java ME, J2ME (Java Micro LinkedBlockingQueue (classe) multi-cœurs...... p.211
Edition)............ p.22 ....................... p.157 musicaux (formats de
Java Native Interface (JNI) LinkedList (classe) p.151, fichiers)............ p.196
p.63 152, 154 MVC................. p.203
JavaScript (langage) p.19, lisibilité............. p.30 Nahshorn.......... p.19
22 Lisp (langage). . . p.15 namespace....... p.123
Java SE, J2SE (Java Standard List (interface)... p.152, 154 Nan (NotANumber) p.28,
Edition)............ p.22 liste (type)........ p.110 32
Jazelle.............. p.15 listener (notion). p.186 native (mot clé). p.63
JCheckBox (classe) p.203 ListIterator (interface) native thread (notion)
JComponent (classe) p.203 p.151, 155 p.211
JDialog (classe). p.203 Locale (classe). . p.172 NEGATIVE_INFINITY p.163
JDK (Java Development Kit) localisation (notion) p.172 NetBeans.......... p.21, 134
p.21 lock (notion)..... p.210 new (mot clé).... p.35, 47,
JFileChooser (classe) p.203 loi de Moore...... p.67 53, 82

228
Index

newInstance()... p.137, 164 paquetage........ p.123, 130 Python (langage) p.15


nextDown()....... p.160 paramètre (de fonction) Queue (interface) p.156
nextGaussian(). . p.170 p.57, 59, 60, 62 quick sort......... p.74
nextUp()........... p.160 parseDouble(). . . p.163 racine............... p.118
nichée (classe ou interface) parseInt()......... p.163 racine (classe)... p.134
p.128 partitionner....... p.74 ramasse-miettes (notion)
niveau.............. p.118 Pascal (langage) p.15 p.48
noeud............... p.118 Pattern (classe). p.168 random().......... p.160
nombres entiers p.28, 32, peek().............. p.155 Random (classe) p.170
162 PHP (langage). . . p.15 RandomAccessFile (classe)
nombres flottants p.28, pile (type)......... p.113, 155 p.107
32, 161, 162 pipes................ p.100 rapide (tri)........ p.74
nommage (conventions) pivot................ p.74 readDouble()..... p.106
p.30 PNB (format d'image) readExternal()... p.143
null (mot clé).... p.47, 171 p.194 readInt().......... p.106
Number............ p.163 police............... p.194 readObject()..... p.106, 143
Oak.................. p.18 polymorphisme.. p.132 récursif (parcours) p.119
Object (classe). . p.134 pop.................. p.114 récursivité......... p.62, 115
ObjectInputStream (classe) pop()............... p.155 redéfinition....... p.131
p.106 port................. p.216 Refactor (menu d'Eclipse)
Objective C (langage) portée (des variables) p.134
p.15 p.30, 36, 59 références......... p.47, 56
ObjectOutputStream (classe) POSITIVE_INFINITY p.163 référence sur méthode /
....................... p.105 postfixé............ p.119, 120 fonction............ p.144
Objects (classe). p.171 préfixé.............. p.119, 120 reflection, introspection
objet (notion).... p.79 primitifs (types). p.Erreur : (notion)............ p.137
observateur...... p.111 source de la référence non regex (package) p.168
octal................ p.28 trouvée, 26 regionMatches() p.53
openJDK........... p.21 print() et println() p.42, repaint()........... p.196
opérateur de conversion 101 replace()........... p.53
p.35 printf()............. p.42 réseau (programmation)
opérateurs........ p.31, 32, 35 PrintWriter (classe) p.101 p.215
opérateurs arithmétiques priorité des opérateurs reset().............. p.105
p.32 p.35 ResourceBundle (classe)
opérateurs bit-à-bit p.34 PriorityBlockingQueue p.172
opérateurs booléens p.33 (classe)............ p.157 retainAll()......... p.156
opérateurs d'affectation PriorityQueue (classe) Retention (annotation)
p.34, 47 p.157 p.178
opérateurs d'incrémentation private (mot clé) p.123, 127, RetentionPolicy.. p.178
p.35 130, 130 return (mot clé). p.41, 58
opérateurs de comparaison Process (classe). p.162 RGD (parcours). p.119
p.33 processus léger. p.207 rint()................ p.160
opérateurs de décrémentation profondeur........ p.118 RMI.................. p.219
....................... p.35 programmation round()............ p.160
opérateur ternaire p.35 événementielle. . p.186 Runnable (interface) p.208
Oracle.............. p.18 programmation impérative Runtime (classe) p.162
overloading....... p.62 p.186 RuntimeException (classe)
Override (annotation) programme principal p.25, p.94
p.131, 178 45, 60 SafeVarargs (annotation)
pack().............. p.201 Prolog (langage) p.15 p.178
package (mot clé) p.123, protected (mot clé) p.123, Scala (langage). p.15, 22
130 127, 130 Scanner (classe) p.42, 103,
package (visibilité) p.127 prototype.......... p.57 168, 172
packages standards (listes public (mot clé). p.123, 127, scope............... p.30
des)................. p.125 130 SecureRandom (classe)
paint().............. p.192 push................ p.114 p.170
paint(Graphics g) p.196 push().............. p.155 SecurityManager (classe)

229
p.161 subSet()........... p.156 TreeSet (classe) p.156
seek().............. p.107 substring()........ p.53 tri « en place ». . p.69
sélection (tri).... p.70 subtractExact().. p.160 tri bulle............ p.72
sérialisation, désérialisation Sun.................. p.18 trim()............... p.53
p.105 super (mot clé).. p.131, 131 tri par insertion. p.71
Serializable (interface) super-classe...... p.130 tri par sélection. p.70
p.101, 105, 142, 143 SupressWarnings tri rapide.......... p.74
ServerSocket (classe) (annotation)...... p.178 try (mot clé)..... p.91, 93
p.216 surchage.......... p.62 type (notion de) p.Erreur :
Set (interface)... p.156 swing (package) p.203 source de la référence non
setBackground() p.193 switch (mot clé). p.38, 55 trouvée
setColor()......... p.193 SWT................. p.181, 182, type abstrait..... p.139
setFont().......... p.194 219 type booléen..... p.27, 162
setForeground() p.193 synchronized (mot clé) type caractère... p.27, 162,
setJMenuBar()... p.203 p.210 163
setLayout()....... p.184 System (classe). p.42, 161 type énuméré.... p.40, 55,
setMaximumSize() p.195 tableaux........... p.48, 134 89, 158, 164
setMinimumSize() p.195 table d'association (type) types entiers..... p.28, 162
setPreferedSize() p.195 p.157 types flottants... p.28, 162
setPriority()...... p.211 tags................. p.175 types primitifs. . . p.Erreur :
setSeed()......... p.170 tailMap()........... p.157 source de la référence non
setSize()........... p.195 TAOCP.............. p.65, 223 trouvée, 26
setVisible()....... p.201 Target (annotation) p.178 unchecked (exceptions)
Shape (classe). . p.192 temps.............. p.167 p.94
short (mot clé). . p.28, 162 ternaire (opérateur) p.35 Unicode............ p.27
shuffle()........... p.151 tests................ p.33, 35, UnsupportedOperationExcepti
signature.......... p.57 37, 38 on.................... p.Erreur :
signum().......... p.160 this()................ p.81 source de la référence non
sleep()............. p.208, 211 this (mot clé).... p.84 trouvée
Smalltalk (langage) p.15, Thread (classe). p.208 update()........... p.196
15 ThreadGroup (classe) URL (classe)...... p.215
Socket (classe). . p.216 p.212 URLConnection (classe)
SortedMap (interface) ThreadLocalRandom (classe) p.215
p.157 ....................... p.170 util (package).... p.167
SortedSet (interface) p.156 threads (notion) p.207 validate().......... p.184
Source (menu d'Eclipse) throw (mot clé). p.95 valueOf().......... p.53
p.134 Throwable (classe) p.94 variable............ p.Erreur :
sous-classe....... p.130 throws (mot clé) p.96 source de la référence non
sous-type......... p.134 ThumbEE.......... p.15 trouvée, 30, 36, 59
spécialisation (notion) time (package). . p.167 Vector (classe). . p.154
p.131 toArray().......... p.Erreur : verrou (notion).. p.210
split()............... p.53, 53 source de la référence non versions du langage p.18
Stack (classe). . . p.155 trouvée VHDL (langage). p.15
start().............. p.196 toDegrees()...... p.160 visibilité............ p.88, 127
static (mot clé). . p.85, 87 toIntExact()...... p.160 void (mot clé). . . p.58
stop()............... p.196 toLowercase(), volatile (mot clé) p.210
strict floating point p.161 toUpperCase(), etc. p.53, waitFor().......... p.162
strictfp............. p.161 163 WBMP (format d'image)
StrictMath (classe) p.161 Toolkit (classe). . p.195 p.194
String (classe)... p.53 toRadians()....... p.160 while (mot clé). . p.39
StringBuffer (classe) p.53 toString()......... p.134, 163, windowClosing() p.186
StringBuilder (classe) 171 wrapper............ p.162
p.53 totalMemory().. . p.162 writeDouble().... p.105
Stroke (classe). . p.192 transformateur. . p.111 writeExternal(). . p.143
structure de données p.109 transient (mot clé) p.143 writeInt().......... p.105
subMap().......... p.157 TreeMap (classe) p.158 writeObject()..... p.105, 143

230
Index

XML (langage)... p.15 Xtend (langage). p.22 yield().............. p.208, 211

231

You might also like