PartI Java Cours PDF
PartI Java Cours PDF
PartI Java Cours PDF
Orientée Objet au
langage JAVA
Dr Joseph NDONG
1
Que donne ce cours ?
3
Plan du Cours (1/2)
Module 8 : L’héritage
Module 9 : Gestion des exceptions
Module 10 : Threads
Module 11: Les Swing GUI
Module 12 : Entrées Sorties
Module 13: Collections et algorithmes
Module 14 : Applets
Module 15 : JDBC
5
Module 1
Introduction à Java
6
Naissance du langage Java
7
Les générations des langages de programmation
Langage machine
Spécifique aux UAL
Langage assembleur
Langage algorithmique
C, pascal,cobol, …
8
Java : un langage objet
9
Programme interprété et compilé
Compilateur de X en Y
(plus proche du langage
Interpréteur de X Compilateur de X Machine)
en langage machine
Programme en
Programme en langage Langage de Y
machine
Interpréteur de Y
10
La Machine Virtuelle java ( JVM)
Le pseudo-code est
Compilation en java-compiler( javac) universel c’est à dire
PSEUDO-CODE
(byte-code) Interprétation par la
indépendant du
Machine virtuelle Java pour compilateur et de
les l’ordinateur où a lieu
Systèmes d’exploitation cette compilation.
processeurs coté
utilisateurs PC Macintosh UNIX
11
La Programmation Orientée Objet (P.O.O)
Procédures
Constitué Structures
Programmation structurée de données
( indépendantes
des procédures)
Champs
Programmation objet Constitué objets (données)
Méthodes
(traitements des données)
12
Concept de classe
13
La P.O.O :l’ encapsulation
Impossible
d’agir
Principe d’encapsulation directement
des données sur les
respect du données
14
JRE (Java Runtime Environnment)
15
Java 2 en trois éditions différentes
-Applications
J2SE( Java2 Standard Édition)
-Applet
16
L’ API
L'A.P.I. (Application Programming Interface) est un ensemble de classes et
interfaces prédéfinies utilisables par le programmeur .Elles sont présentées
dans des packages (java.lang, java.math, java.util, etc..
PROGRAMME
classe : type de
classes définies données
Un programme utilise pour ce + fonctions pour
au maximum programme les manipuler
les fonctionnalités
présentes dans l'A.P.I. API
17
Application standalone et Application WEB
FIN DU CHAPITRE 19
Module 2
Techniques de base du langage
20
Premier programma Java: HelloWorld
package hello.java.essai;
// un premier programme // Ceci est un commentaire finissant en fin de ligne
/* la version JAVA du classique
/* ceci est un commentaires pouvant encadrer
Hello World un nombre quelconques de caractères
*/ sur un nombre quelconque de lignes */
public class HelloWorld {
public static void main (String [ ] args) {
System.out.println ("Hello World !");
}
}
Hello World !
21
Notes importantes
22
Mises à jour JDK 5
out.println (…)
23
Structure du programme (1/2)
package hello.java.essai ;
import static java.lang.System.out;
24
Structure du programme (2/2)
Le mot clé static précise que la méthode main n’est pas liée à une instance (objet)
particulière de la classe.
Le paramètre String[ ] args est un tableau de chaînes de caractères qui permet de
récupérer des arguments transmis au programme au moment de son lancement.
Ce paramètre est OBLIGATOIRE en Java.
Le mot clé public dans public class sert à définir les droits d’accès des autres Classes
(en fait de leurs méthodes) à la classe . [ A voir].
Le mot clé public dans public static void main est obligatoire pour que votre programme
s’exécute. Il s’agit d’une convention qui permet à la machine virtuelle d’accéder
à la méthode main .
25
Paquetage de la classe
Pour utiliser des classes de l’ API, il faut préciser leur package. On pourra utiliser
l’instruction import nom_package.nom_de_la_classe .
26
Contenu du programme
28
Exécution du programme (2/2)
Si elle se passe bien( sans erreurs) on obtient un fichier d’extension .class . Ici, il s’agit
de HelloWorld.class .
java HelloWorld
aucune extension ne doit figurer
Commande java pour exécuter le byte code
ATTENTION: en pratique, on tiendra toujours compte des variables d’environnement
PATH et CLASSPATH (cf. diapos suivantes). 29
Exemple pratique de compilation et
d’exécution d’une classe (1/2)
(ici dans le paquet essai, il y a une seule classe : LectureClavier)
31
compilation simultanée de plusieurs fichiers
javac -d D:\allndong\mescompils
-classpath D:\allndong\alldev.jar
C:\ndong\src\essai\HelloWorld.java
C:\ndong\src\essai\Compte.java
Compilation de tous les fichiers d'un répertoire (on compile toutes les classes du
package essai):
javac -d D:\allndong\mescompils
-classpath D:\allndong\alldev.jar
C:\ndong\src\essai\*.java
32
La variable d’environnement classpath
A cette option peut correspondre une ou plusieurs valeurs, chacune d'elle pouvant être :
- l'adresse (relative ou absolue) d'un fichier jar.
- l'adresse (relative ou absolue) d'un répertoire de base de classes
Remarque : les classes de l‘ A.P.I. ne sont pas concernées par cette option
Si plusieurs valeurs sont associées à une option classpath, elles doivent être séparées par
des ; (sous Windows) ou des : (sous linux).
La valeur par défaut de cette option est le répertoire courant (désigné par un ".")
Exemple :
cd C:\ndong\classes
jar cf D:\allndong\mescompils\mesprogs.jar .
javac -d D:\allndong\mesclasses
-classpath D:\allndong\mescompils\mesprogs.jar
C:\ndong\src\essai\UtiliseLectureClavier.java
On peut exécuter une classe à partir d’un fichier jar, il suffit simplement d’éditer
le fichier MANIFEST.MF contenu dans le répertoire META-INF de l’archive.
Avec n’import quel éditeur de texte, ouvrez le fichier Manifest (il ne contient que
deux lignes) et éditer le de la façon suivante:
conserver la ligne (c’est la première):
Manifest-Version: 1.0
et remplacer la deuxième ligne c à d:
Created-By: 1.4.1_05 (Sun Microsystems Inc.)
par:
Main-Class: nom_complet_de_la_classe_principale.
Par exemple, pour la classe LectureClavier, le fichier manifest sera:
Manifest-Version: 1.0
Main-Class: essai.LectureClavier .
// pour exécuter le programme à partir du jar
C:\> java –jar D:\allndong\mescompils\mesprogs.jar
35
Les commandes de base du langage
Java fournit un ensemble de commandes de base très utiles pour diverses opérations
que vous pouvez réaliser en ligne de commande. Voici quelques commandes:
36
Catégories d’instructions
package info.fst.jnd.pro;
37
Règles d’écriture en Java (1/3)
Exemple :
ligne Clavier valeur_5 _total _56 $total 2nombre
38
Règles d’écriture en Java (2/3)
39
Règles d’écriture en Java (3/3)
Voici quelques conventions de codage en java
}
Indenter votre programme pour plus de lisibilité
} 40
Documentation en ligne et utilisation de classes
La documentation en ligne peut être générée à partir des fichiers sources par
l'utilitaire javadoc.
Cette documentation est organisée et générée de la même manière pour toutes
les classes que ce soit les classes de l'API ou les classes que nous définissons
nous même.
Lors du développement d’applications, il NE faut PAS négliger la documentation
de vos classes (bien documenter les fonctionnalités).
42
A propos des commentaires
package hello.java.essai;
/**
* @param autor Joseph /* ceci est un commentaire de documentation
* @since 1.0 automatique javadoc */
*/
// un premier programme // Ceci est un commentaire sur une seule ligne
/* la version JAVA du classique /* ceci est un commentaire pouvant encadrer
Hello World un nombre quelconques de caractères
*/ sur un nombre quelconque de lignes */
public class HelloWorld {
public static void main(String [ ] args) {
out.println("Hello World !");
}
}
44
Les commentaires JAVADOC
La description des attributs, des constructeurs et des méthodes publics est donnée
- brièvement en début de document
- en détail dans la suite du document.
46
La commande javadoc
GENERATION DE LA DOCUMENTATION
javadoc -d <répertoire où doivent être mis les fichiers générés>
-sourcepath <répertoire(s) de base des fichiers sources>
<nom du paquetage>
- sourcepath
le(s) répertoire(s) de base des sources
(s'il y en a plusieurs, séparer par des ; (Windows) ou : (linux))
47
La commande javadoc: exemple
Pour générer la documentation des classes des paquetages essai (dans C:\ndong)
et exemple.test (dans D:\allndong)
javadoc -d D:\allndong\javaprog\doc
-sourcepath C:\ndong\src;D:\allndong\src
essai exemple.test
48
Environnement de développement: les IDEs
Cependant, pour être plus à l’aise et réaliser des programmes sophistiqués, vous devez utiliser
un environnement de développement intégré ou IDE (Integrated Development Environment).
Un IDE est intelligent et présente plusieurs avantages parmi lesquels:
- la possibilité de créer complètement la hiérarchie du projet;
- la disponibilité d’un audit de code qui offre les fonctionnalités du JDK;
- la facilité d’utiliser les commandes de base de Java (javac, java, javadoc, jar,…);
- l’intégration à chaud d’un projet dans un autre projet à l’aide de fichiers jars;
- l’ajout de librairies tierces dans un projet ;
- etc
49
IDEs populaires
Le lecteur peux aussi tester l’environnement NetBeans qui est également excellent.
50
Tutoriel sur Eclipse
Eclipse est proposé en plusieurs versions selon le type de programmation que vous
souhaitez réaliser. La page http://www.eclipse.org/downloads/ donne les différentes
versions.
Pour apprendre les fondamentaux de base de Java, la version nommée
Eclipse IDE for Java Developers suffit. Ceux qui souhaitent apprendre les notions
avancées en JEE ont besoin de la version nommée Eclipse IDE for Java EE Developers.
C’est ce dernier que j’utilise pour préparer les étudiants au cours de JEE.
51
Installation de Eclipse
L’installation d’un IDE pour Java nécessite au préalable l’installation du JDK standard.
Il faut choisir une version du JDK compatible avec la version de l’IDE choisie.
Ici, j’ai choisi la version Eclipse JEE JUNO version 1.5.2 qui est compatible avec le JDK1.5
et supérieur.
A cet instant vous pouvez créer un raccourci de l’exécutable d’Eclipse dans votre bureau.
Lancer ce raccourci pour commencer à travailler avec Eclipse.
52
Utilisation de Eclipse
Pour bien travailler de façon générale avec un IDE, il faut commencer par créer
un espace de travail (workspace). Il s ’agit d’un répertoire où vos futurs projets Java
résideront.
Vous pouvez laisser Eclipse vous demander de choisir votre workspace chaque fois que
vous le démarrer. Cette option est intéressant si vous disposez de plusieurs workspaces.
Dans le cas où vous avez un seul workspace, il faut mieux le configurer une seule fois.
Il suffit de faire un clic droit sur le raccourci de votre bureau + clic sur propriétés.
53
Modifier le niveau du JRE pour
Eclipse
-vmargs
-Dosgi.requiredJavaVersion=1.7
54
-data D:\mesprojets
Au niveau de Cible, placez un espace et mettez votre workspace. Par exemple, si mon
workspace est le répertoire D:\mesprojets, alors on a comme cible:
Une fois votre espace de travail mis en place, vous pouvez commencer à y développer
des projets. Programmer en Java doit toujours faire l’objet d’un fichier projet. Il s’agit
d’un répertoire se trouvant dans votre workspace et devant contenir vos classe Java.
Je montre dans ce qui suit, à l’aide de captures d’écran les différentes phases allant
de la création d’un nouveau projet jusqu’à la phase d’exécution du programme.
56
Fenêtre d’acceuil de Eclipse
Explorateur de contenu de
Explorateur de classes (code source Java)
projets
diapo suivante
58
premierprojet
59
Pour ajouter une nouvelle classe dans ce projet,
faire un clic droit sur le nom du projet + new classe.
cours.java
HelloWorld
1) Saisir le package ou Browse pour le choisir
2) Saisir le Nom de la nouvelle classe
60
Vous obtenez la structure de projet ci-dessous pour votre projet.
61
Pour exécuter on peut le faire de plusieurs manières:
1) cliquer sur le bouton en forme de flèche entourée en vert
sur la barre des tâches ou
2) Clic droit sur le nom de la classe + Run As + Java Application
3) Clic droit sur le code source+ Run As + Java Application
Le résultat ou les erreurs s’affichent alors sur la console.
62
FIN DU MODULE
Module 3 Les Types Primitifs
63
Les différentes familles de types primitifs
Java dispose d’un certain nombre de types de base dits primitifs, permettant de
manipuler des entiers, des flottants, des caractères et des booléens.
Ce sont les seuls types du langage qui ne sont pas des classes.
Les types primitifs(au nombre de 8) se répartissent en quatre grandes catégories
selon la nature des informations qu’ils permettent de manipuler:
- nombres entiers,
- nombres flottants,
- caractères
- booléens
64
Le type entier
Ils servent à représenter les nombres entiers relatifs, ils sont au nombre de 4.
Les types élémentaires ont une taille identique quelque soit la plate−forme
d'exécution.
65
Le type flottant (réel)
Ils permettent de représenter , de manière approchée, une partie des nombres réels.
Java prévoit deux types de flottants correspondant chacun à des emplacements
mémoire de tailles différentes: float et double.
double : 64 bits
float : 32 bits
Exemple :
66
Le type caractère
CHAR ( 2 octets)
char : caractère isolé
-codage unicode sur 16 bits non signé
-expression littéral char entre apostrophes
‘+’, ‘a’ ,’\t’ , ‘\u???’
Une variable de type caractère se déclare:
char c1; char c1,c2 ; // c1 et c2 sont 2 variables caractère
67
Le type booléen
BOOLEAN
-Deux états: true / false
-Exemples:
boolean ok=false;
if (n<p) … //n<p est expression booléenne valant vrai ou faux
boolean ordonne ; // déclaration d’une variable de type booléenne
………………
ordonne =n<p; //ordonne reçoit la valeur de l’expression n < p
68
Initialisation des variables (1/2)
Exemple :
valeur
nom = opérateur d’affectation
type ( associatif de droite à gauche)
Remarque :
Une variable manipulée dans une méthode (variable locale) ou un bloc devra toujours
être initialisée avant toute utilisation.
Une variable GLOBALE (déclarée comme champ dans une classe) est toujours
initialisée par défaut à une valeur « nulle » dépendant de son type.
La déclaration d’une variable réserve de la mémoire pour stocker sa valeur . 69
Initialisation des variables (2/2)
70
Utilisation des variables
package home.user.java.essai ;
import static java.lang.System.out;
public class UtilVariable
{ String chaine ; // variable de type (class ) String, valeur par défaut null
double solde ; // valeur par défaut 0.0 assignée à solde
public static void main(String [ ] args)
{
out.println(" valeur de solde =" +solde); new pour
} créer un objet
public void affiche( )
{ chaine = new String(" bonjour" ); // objet de type String initialisée
long nombre ;
out.println(" valeur de nombre= "+nombre); // erreur de compilation
// car nombre non initialisée
}}
71
variables finales
(le mot clé final)
Java permet de déclarer que la valeur d’une variable ne doit pas être
modifiée pendant l’exécution du programme.
package home.user.java.essai ; Une fois convenablement
public class VariableFinale initialisée une variable finale
{ final long NOMBRE ; ne peut pas voir sa valeur évoluée .
final double MAX = 100 ; // variable finale = constante
public static void main(String [ ] args)
{
out.println(" utilisation de variable constante" );
}
public void affiche( )
{ NOMBRE = 1000 ; // initialisation différée de la variable NOMBRE
out.println(" valeur de MAX= "+MAX);
}
} 72
Les Opérateurs
(arithmétiques binaires)
RETENEZ BIEN
package home.user.java.essai ;
public class Op_Arith_Binaire
{ public static void main(String [ ] args)
+ - * / sont des
opérateurs arithmétiques
{ int a =1, b = 2 ; binaires qui portent sur deux
int addit = a + b , opérandes de même type et
soustr = a – b ,
renvoient un résultat du même
type que le type des opérandes ..
div = a / b,
addit = 3
multi = a*b; soustr = -1
System.out.println(" addit =" +addit ); div = 0
System.out.println(" soustr =" +soustr ); multi = 2
System.out.println(" div =" +div );
System.out.println(" multi =" +multi );
}}
73
Les Opérateurs
(unaire et modulo)
package home.user.java.essai ;
public class Op_Unaire_et_Modulo Opérateur modulo:
{ public static void main(String [ ] args) fournit le reste de la
{ int a =100, b = 50 ; division de deux
opérandes.
int _modulo = 100 % 50 ;
System.out.println(" le reste de la division de " +a+" par" +b+" est" +_modulo );
float x = + 10.2f ;
-
double d= 50.2 ;
System.out.println (" x et d sont des opérateurs unaires portant sur un seul opérande" );
}
} le reste de la division de 100 par 50 est 0
x et d sont des opérateurs unaires portant sur un seul opérande
74
Les Opérateurs
(priorité)
75
Exception sur la manipulation
des opérateurs (1/2)
package home.user.java.essai ;
/* test sur la division par zero de nombres entiers */
public class Test {
public static void main (String args[])
{
int valeur=10;
double résultat = valeur / 0;
out.println("index = " + résultat);
}
}
Exception in thread « main »
java.lang.ArithmeticException:/
by zéro at Test.main ( Test.java:9
76
Exception sur la manipulation
des opérateurs (2/2)
Pour les entiers, la division par zéro (par / ou %) conduit à une erreur
d’exécution. Plus précisément, il y a déclenchement de ce que l’on nomme une
exception de type ArithmeticException.
Nous verrons plus tard comment traiter convenablement les exceptions.
Si nous ne le faisons pas, nous aboutissons à l’arrêt de l’exécution du
programme, avec un message de ce type:
Exception in thread « main » java.lang.ArithmeticException:/ by zéro at
Test.main ( Test.java:9)
REMARQUE :
Pour les flottants, aucune opération ne conduit à un arrêt de
l’exécution (pas même une division par zéro ) ; seulement
on a une valeur non exploitable.
77
Conversions implicites (1/5)
78
Conversions implicites (2/5)
double d= p + a;
79
Conversions implicites (3/5)
Une conversion telle que int en float est appelée ajustement de type .
Elle ne peut se faire que suivant une hiérarchie qui permet de ne pas
dénaturer la valeur initiale, à savoir :
int -> long ->float ->double
NB : une conversion de double en float ( par exemple) n’est pas légale .
pour l’exemple précèdent on ne peut pas faire :
int k = p + a ; // erreur de compilation
80
Conversions implicites (4/5)
Promotions numériques
les opérateurs numériques ne sont pas définis pour les types byte, char
et short.
Toute opération qui utilise l’un de ces types nécessite une conversion
préalable dans le type int
Cette conversion porte le nom de promotion numérique .
81
Conversions implicites (5/5)
82
Les opérateurs relationnels(1/2)
Exemple :
public class Oper_Relat {
public static void main(String args [])
{ int n = 10 ;
short s =10 ;
float x = 100;
double d= 200;
out.println("Affichage 1 :"+(n = = s) );
out.println("Affichage 2 :"+(d <= x) );
}
} Affichage 1 : true
Affichage 2 : false
84
Les opérateurs logiques(1/3)
Opérateur Signification
Le résultat est
! négation
toujours un
& et
booléen.
^ ou exclusif
| ou inclusif
&& et(avec cout-circuit)
|| Ou inclusif(avec court-circuit
85
Les opérateurs logiques (2/3)
86
Les opérateurs logiques (3/3)
Exemple :
if ( x<10 ) && ( y++ > 4) { //on évalue x<10 , le résultat
// est faux donc on n’ évalue pas
// y++ > 4
}
// instructions après le test
x= y-10; 87
Opérateurs
d’incrémentation et de décrémentation (1/2)
incrémentation
int i = 10 ; En fait en écrivant :
post incrémentation
int n= i++ ;
i++ ; // cette expression vaut 10 on a :
//mais i vaut 11 n= i ;
int j = 10 ; i = i+1 ;
Et en écrivant :
++j ; // cette expression vaut 11 int p= ++j ;
//et j vaut aussi 11 on a:
j = j+ 1 ;
pré incrémentation
p =j ;
88
Remarque
Il faut bien constater que le comportement des opérateurs de post ou de pré incrémentation
ou décrémentation dépend de leur utilisation dans une instruction ou dans une expression.
Une instruction est indivisible tandis qu’une expression est un ensemble d’instructions.
Dans l’exemple précédent la post et la pré incrémentation sont équivalentes et donnent
le même résultat dans une instruction (i++ et ++i). Tandis dans une expression, la post et
la pré incrémentation/décrémentation sont totalement différentes.
89
Opérateurs
d’incrémentation et de décrémentation (2/2)
90
Opérateurs
d’affectation élargie
91
Transtypage: opérateur de cast
Opérateur Signification
Opérateurs bit à bit
& Et (bit à bit) Opérande 1 0 0 1 1
| Ou inclusif(bit à bit) Opérande 2 0 1 0 1
^ Ou exclusif(bit à bit) & 0 0 0 1
<< Décalage à gauche
>> Décalage arithmétique à droite | 0 1 1 1
93
Opérateurs
de manipulation de bits (2/3)
Résultat : 1100110111111101110100111011100
94
Opérateurs
de manipulation de bits (3/3)
résultat 0000111001101111111011101001110
95
Opérateur
Conditionnel
?:
if(ciel == bleu)
temps ="beau"
else temps =ciel==bleu ?"beau" : " mauvais"
temps=" mauvais"
96
Priorité des opérateurs (1/2)
(ordre de priorité décroissante)
les parenthèses ()
les opérateurs d'incrémentation ++ -- --
97
Priorité des opérateurs (2/2)
(ordre de priorité décroissante)
l'opérateur OU logique ||
les opérateurs d'assignement = += -=
FIN DU MODULE 98
Module 4 Les structures de contrôle
99
Types de structures
CHOIX :
if ….. else Branchement inconditionnel
switch
break
for , continue
BOUCLES : while
do … while
100
Choix :
if …else
switch
101
Syntaxes :
if …else
switch
if (condition)
Condition booléenne ( true / false )
instruction_1
Expressions quelconques
[ else
instruction_2 ] Les crochets renferment des instructions
facultatives.
switch (expression)
Expression de type byte, char,
{ case constante_1 : [suite_d’instruction_1 ] short ou int .
case constante_2 : [suite_d’instruction_2 ]
………………….. Expression constante d’ un type
case constante_n : [suite_d’instruction_n ] compatible par affectation avec
[ default : suite_d’instructions ] le type de expression
}
102
L’instruction
do while
package home.user.java.essai ;
import java.util.Scanner ; // importation de classe de l’ API
public class Exemple_Do_While{
public static void main (String args [ ])
{ Scanner clavier = new Scanner (System.in) ;
do
{ System.out.println ("saisir un entier strictement positif " ) ;
n = clavier.nextInt ( ) ; // saisir à partir du clavier
if ( n < 0) System.out.println ("la saisie est invalidée: recommencez" ) ;
}
while ( (n < 0) || (n = = 0) );
}}
do instruction
Expression quelconque
Condition booléenne
while (condition) ; 103
L’instruction
while
package joseph.cours.java ;
public class Exemple_While{
public static void main(String args [ ])
{ while ( n < = 0)
{ System.out.println ("saisir un entier strictement positif " ) ;
n = clavier.nextInt( ) ; // saisir à partir du clavier
if ( n < 0) System.out.println ("la saisie est invalidée: recommencez" ) ;
}
}
}
while (condition) ;
Condition booléenne
Expression quelconque
instruction 104
L’instruction
for
package joseph.cours.java ;
public class Exemple_For{
public static void main (String args [ ])
{ int tab [ ] = new int [ 100] ; // tableau d’entiers de taille 100
for( int i = 0 ; i < 100 ; i ++ )
{
tab [ i ] = i + 1;
}
}
}
instruction
105
Branchement inconditionnel
break / continue
En cas de boucles
package home.user.java.essai; imbriquées,
public class Essai_Break_Imbr { l’instruction break
public static void main (String args [ ]) fait sortir uniquement
{ int tab [ ] = new int [ 10] ; // tableau d’entiers de taille 100 de la boucle la plus
for( int i = 0 ; i < 10 ; i ++ ) interne.
{
for ( int j =i;j <10;j++)
{ if ( j == 3 || j == 4 || j == 5 ) break ;
tab [ j ] = j+1;
} // le break branche ici
}
for ( int i = 0 ; i < 10 ; i ++ )
System.out.println (" éléments du tableau:" +" "+tab [ i] );
}
} éléments du tableau: 1 2 3 0 0 0 7 8 9 10
107
break avec étiquette
package joseph.cours.java;
public class Essai_Break_Etiq {
public static void main (String args [ ])
{ int tab [ ] = new int [ 10] ; // tableau d’entiers de taille 100
repeat: for( int i = 0 ; i < 10 ; i ++ )
{
for ( int j =i;j <10;j++)
{ if ( j == 3 || j == 4 || j == 5 ) break repeat;
tab [ j ] = j+1; Étiquette : pour sortir
} de deux boucles imbriquées
} // cette fois le break branche ici
for ( int i = 0 ; i < 10 ; i ++ )
System.out.println (" éléments du tableau:" +" "+tab [ i] );
}
} éléments du tableau: 1 2 3 0 0 0 0 0 0 0
108
Continue ordinaire
package joseph.cours.java ;
public class Exemple_Continue_Ord{
public static void main (String args [ ])
{ int tab [ ] = new int [ 10] ; // tableau d’entiers de taille 10
for( int i = 0 ; i < 10 ; i ++ ) // ici
{ if ( i = = 5 ) continue ;// on poursuit la boucle for
tab [ i ] = i + 1;
}
for ( int i = 0 ; i < 10 ; i ++ )
System.out.println (" éléments du tableau:" +" "+tab [ i] );
}
} éléments du tableau: 1 2 3 4 5 0 6 7 8 9 10
109
Continue avec étiquette
package home.user.java.essai;
public class Essai_Continue_Etiq {
public static void main(String args [ ])
{ int tab [ ] = new int [ 10] ; // tableau d’entiers de taille 10
again: for( int i = 0 ; i < 10 ; i ++ ) // cette fois le continue branche ici
{
for ( int j =i;j <10;j++)
{ if ( j == 3 || j == 4 || j == 5 ) continue;
tab [ j ] = j+1;
} ATTENTION: on ne mentionne pas
} for( int i = 0 ; i < 10 ; i ++ ) le nom de l’ étiquette avec continue.
System.out.println(" éléments du tableau:" +" "+tab [ i] );
}
} éléments du tableau: 1 2 3 0 0 0 7 8 9 10
111
Exercice d’application
Ensuite le
programme affiche le factoriel de chaque entier après chaque saisie réussie.
Un objet peut être défini comme étant une entité concrète ou abstraite du
monde réel. Les objets contiennent des attributs et des méthodes.
Chaque objet sera caractérisé par son jeu de données( on parlera d’
attributs ou aussi de champs). Les fonctions qui agissent sur les
données de l’objet sont aussi appelées méthodes.
données
CHAMPS propriétés
caractéristiques
attributs
OBJET (Identification, caractérisation)
METHODES
CHAMPS - abscisse
- ordonnée
Point
METHODES - affiche
- translater
Objet point du plan cartésien
- coincide
CHAMPS - prenom
- nom
- numero
Compte - solde
METHODES - deposer
- retirer
Objet compte en banque 115
Objet = identité + état + comportement (1/2)
116
En considérant des objets points du plan cartésien:
Point a = new Point (2,3);
Point b=new Point (4,5);
2 a.afficher ( );
3
Identité =Référence
(adresse mémoire)
a
4
Identité =Référence b.afficher ( );
(adresse mémoire) 5
b 117
Le concept de classe
Point p2
Point p4
Point p1
Point p5
Point p3
« Une classe est une usine de création d’objets de même nature. » 118
Définition d’une classe
119
Remarques
Une méthode peut être déclarée private : dans ce cas elle n’est visible qu’à
l’intérieur de la classe où elle est définie. Pour pouvoir l’utiliser dans un
autre programme, il faut nécessairement passer par une méthode publique
de sa classe ayant l’appelée.
120
Créer un objet = instancier une classe
1 x
référence
2 y objet
a
Point
121
Utilisation d’une classe
Lorsqu’une classe est définie, il ne reste qu’à l’utiliser, en instanciant des objets
et en appelant les méthodes décrivant les fonctionnalités. Mais attention, l’accès
DIRECT aux champs encapsulés est impossible en dehors de leur classe.
package test.point;
public class TestPoint
{ public static void main( String args [ ] )
{ Point a = new Point (1,2) ;
int abs=a.x; // tentative d’acces au CHAMP x déjà bien encapsulé dans sa classe
int ord=a.y; // tentative d’acces au CHAMP y déjà bien encapsulé dans sa classe
}
} // fin de la classe TestPoint
Lorsque vous définissez une classe, vous devez aussi y définir toutes les méthodes utiles.
En particulier, songez à définir les ACCESSEURS ou MUTATEURS. Il s’agit de méthodes
(que l’on nomme aussi getter et setter) servant à accéder et à modifier individuellement
chaque champ de l’objet surtout lorsque ceux-ci sont encapsulés.
122
ACCESSEURS: getter et setter
124
Autres fonctionnalités
A part les accesseurs, les autres fonctionnalités de la classe doivent y être
insérées sous forme de méthodes d’instances ou méthodes de classe.
Voici par exemple, une méthode pour déplacer un point et une méthode pour affiche
à la fois les coordonnées d’un point.
class Point
{
// code manquant
126
Le constructeur par défaut: pseudo-constructeur
En Java, vous n’êtes pas obligé de créer effectivement un constructeur explicite lors
de la définition d’une classe. Dans ce cas, Java vous fournit un constructeur par
défaut appelé pseudo-constructeur.
Il s’agit d’un constructeur sans paramètre ne réalisant aucun traitant. Il sert à créer
des objets avec une initialisation par défaut des champs aux valeurs « nulles » .
Si on a :
class Point
{
}
Ecrire une classe principale TestOperation où vous vous basez sur la classe précédente
pour addition deux entiers donnés.
128
Quelques règles sur les constructeurs
Une classe peut disposer de plusieurs constructeurs: ils se différencieront par le nombre
et le type de leurs arguments.
Une classe peut disposer d’un constructeur sans arguments qui est bien différent du
pseudo-constructeur.
129
Construction d’un objet
booléen false
char caractère de code nul
entier(byte, short, int, long) 0
flottant( float, double) 0.f ou 0.0
objet null
131
Autoréférence : this ( 1/3)
Le mot clé this joue deux rôles : 1) le rôle d’OBJET COURANT et 2) l’appel
d’un constructeur dans un autre constructeur de la même classe.
Regardons le premier rôle.
L’objet sollicité par la JVM en instant donné est appelé objet courant et il est désigné par this.
Lors de la définition de classe, ce this est souvent présent dans le programme de manière
implicite devant le nom des champs et dans les méthodes d’instances.
132
Autoréférence : this ( 2/3)
L’utilisation de this est très pratique dans l’écriture des méthodes et surtout des
constructeurs.
133
Autoréférence : this ( 3/3)
public void affiche( )
{ out.println("Point de coordonnées" + this.x + " et " + this.y);
}
L’objet sur lequel la méthode s’applique en un instant donné est appelé l’objet courant.
Il est désigné par la référence this.
134
Autoréférence : this : remarque
Le mot clé this peut être utilisé pour simplifier l’écriture du constructeur.
En clair, on peut utiliser les noms des champs identiques aux noms des arguments.
136
Contrat et implémentation
137
Affectation d’objets
Point a ; 12
10
a = new Point (12,10 ) ;
a
11
Point b = new Point ( 11, 14 ); 14
b
affectation d’objet 12
a=b; a 10
Sera candidat au 11
ramasse-miettes b
14
s’il n’est plus référencé
Désormais a et b désignent le même objet.
138
Référence nulle: le mot clé
null
class Point
{
private int x ; // champ x d’un objet Point
private int y ; // champ y d’un objet Point
public Point( int abs, int ord ) // un constructeur à deux arguments
{ x = abs ;
y = ord ; Les variables locales doivent
} toujours être initialisées avant toute
public Point coincide (Point p ) utilisation.
{ Point t = null ; // t est locale donc il est nécessaire de l’initialiser
if ((p.x = = this.x) && ( p.y = = this.y )) t = this;
else t = null;
return t ;
}
} //fin de la classe Point
139
Comparaison d’objets (1/2):
= = versus equals
public class Point
{ private int x ; // champ x d’un objet Point
private int y ; // champ y d’un objet Point
public Point ( int abs, int ord ) // un constructeur à deux arguments
{ x = abs ;
y = ord ;
}
public static void main(String args [ ] )
{
Point a = new Point ( 1,1 );
Point b = new Point ( 1,1 );
System.out.println ("avec = = : " + a == b);
System.out.println ("avec equals :" + a.equals ( b ));
}
} //fin de la classe Point Résultat avec = = : false
avec equals : false
140
Comparaison d’objets (2/2)
Champs de classe
Les champs de classe ou champs statiques existent en un seul exemplaire pour
toutes les instances de la classe. On les déclare avec le mot clé static .
a.k et b.k peuvent être remplacés par ChampStatic.k . Mais si k est privé, on ne
peut faire ceci.
142
Exemple d’utilisation de champs de classe
Une méthode d’une classe ayant un rôle indépendant de toute instance de la classe doit
être déclarée avec le mot clé static et elle ne pourra être appliquée à aucun objet de cette
classe, contrairement aux méthodes d’instances.
L’appel de la méthode ne nécessitera que le nom que de la classe.
Une méthode statique ne peut pas agir sur des champs usuels,
ATTENTION : c’est-à-dire non statiques.
144
Exemple d’utilisation de méthodes de classe
145
Bloc d’initialisation statique
Remarque :
l’initialisation d’un champ statique se limite uniquement à :
- l’initialisation par défaut,
- l’initialisation explicite éventuelle.
Les blocs statiques sont souvent utilisés pour initialiser des variables complexes dont l’
initialisation ne peut être faite par une simple instruction.
Les instructions n’ont accès qu’aux champs statiques de la classe.
Les instructions d’un bloc statique sont exécutées de façon automatique et une seule fois
lorsque la classe est chargée.
146
Exemple d’utilisation de bloc statique
148
Exemple de surdéfinition de méthode
150
Surdéfinition de constructeurs
156
Objet membre
Une classe est dite interne lorsque que sa définition est située à l’intérieur de la
définition d’une autre classe. Les classes internes (inner classes) peuvent être
situées à différent niveau d'une classe normale.
Il existe quatre types de classes imbriquées :
- les classes internes simples, définies au niveau des classes,
- les classes internes statiques, représentant une classe de sommet intérieure,
- les classes locales, définies au niveau des méthodes,
- les classes internes anonymes, définies au niveau d'une instance.
158
Classes internes simples(1/5)
package essai01;
public class ClasseParente {
private int x = 10, static int y = 20;
public int addition ( ) { return (x + y); }
public class ClasseInterne //DEBUT CLASSE INTERNE
{ static int p = 20; //erreur de compilation,
static final int k = 12; //constante statique
public int multiplier ( )
{ return x*y + addition ( ); }
} //FIN CLASSE INTERNE
public static void main (String [ ] args) {
ClasseParente ob_out = new ClasseParente ( );
//ClasseInterne ob_in0 = new ClasseInterne ( ); IMPOSSIBLE
ClasseInterne ob_in = ob_out.new ClasseInterne ( );
System.out.println (ob_in.multiplier ( ));
// System.out.println (ob_out.multiplier ( ));//ERREUR
// System.out.println (ob_in.addition ( )); IMPOSSIBLE
}} 159
Classes internes simples(2/5)
Une classe interne peut être déclarée avec n’importe quel modificateur d’accès ((
(public, protected, par défaut ou private) et les modificateurs abstract, final, static.
Elles sont membres à part entière de la classe qui les englobe et peuvent accéder à tous les
membres de cette dernière.
Les classes internes ne peuvent pas être déclarées à l'intérieur d'initialiseurs
statiques (blocs statiques).
Les classes internes ne doivent pas déclarer de membres statiques, sauf s'ils
comportent le modificateur final, dans le cas contraire, une erreur de compilation se
produit. Toutefois, les membres statiques de la classe externe peuvent être hérités
sans problème par la classe interne.
Les classes imbriquées sont capables d'accéder à toutes les variables et méthodes de
la classe parente, y compris celles déclarées avec un modificateur private.
160
Classes internes simples (3/5)
On retient:
La notation particulière:
ClasseInterne ob_in = ob_out.new ClasseInterne();
161
Classes internes simples (4/5)
Il est possible d'utiliser une méthode de la classe parente pour créer directement
une instance de la classe interne. Toutefois, lors de l'appel de la méthode, il sera
nécessaire de créer une instance de la classe d'inclusion.
package essai0;
public class ClasseParente02 {
private int x = 10, int y = 20;
public int addition ( )
{ ClasseInterne02 obj_in = new ClasseInterne02( );
return (x + y)+ obj_in .multiplier ( );
}
public class ClasseInterne02
{ public int multiplier ( )
{ return x*y ;
}
}
} 162
Classes internes simples (5/5)
Elles sont membres à part entière de la classe qui les englobent et peuvent
accéder uniquement aux membres statiques de cette dernière.
public class Parente04 { Les classes internes
private static int x = 1, y = 2; statiques peuvent
private int z = 3; accéder à l'ensemble
public int addition ( ){ return x + y + z;} des membres statiques
public static int multiplier( ){ return x*y;} de leur classe parente,
public static class Interne04{ à l'instar des méthodes
de classe.
private static int k = 1;
private int p = 2;
public void diviser ( )
{ System.out.println (new Parente04( ).addition ( )/p+x+y);}
}
public static void imprimer(){
System.out.println ( multiplier ( ) / x+y+k );} }
public static void main(String [ ] args) {
Parente04.Interne04( ).imprimer ( );
new Parente04.Interne04( ).diviser ( )} } 164
Classes locales
Une classe locale est définie à l'intérieur d'une méthode ou un bloc, et agît
librement et essentiellement au sein de cette dernière.
Elles peuvent être static ou non.
Il n'est possible de déclarer des classes locales, dont la portée est limitée au bloc,
qu'avec les modificateurs final ou abstract. Les modificateurs suivants : public,
protected, private et static, sont interdits.
Les données membres d'une classe externe peuvent être accédés par la classe locale.
165
Classes locales
Les classes anonymes obéissent aux mêmes restrictions que les classes locales et de plus,
ne peuvent ni être abstraites (abstract) ni être statiques (static).
Par contre, elles portent toujours implicitement le modificateur final.
En fait, aucun modificateur n'est permis dans une déclaration de classe anonyme
167
Gros plan sur les packages
En Java, il y a quatre types de droits d’accès aux méthodes et aux champs d’un objet
d’une classe. Autrement dit, la portée de la visibilité des méthodes et champs
est assurée par les mots clés: private, protected, vide (droit de paquetage), et public.
169
Paquetage et visibilité des champs
(encapsulation des membres)
class c1{
class c4 extends c1{
public int a;
…. a c
int b;
}
protected int c;
private int d; }
package B
package A
170
Exemple d’accès aux membres
class c1{
class c4 extends c1{
public void f( );
…. f( ) h( )
void g( );
}
protected void h( );
private void k( ); }
package B
package A
Introduction
Les tableaux sont des structures de données regroupant plusieurs valeurs de même type.
Ou encore on parle de tableaux pour désigner un ensemble d’éléments de même type désignés
par un nom unique, chaque élément étant repéré par un indice précisant sa position au sein
de l’ensemble .
Les tableaux constituent des collections d'informations homogènes, c'est-à-dire, de
valeurs primitives ou d'objets de même type.
Les éléments d'un tableau peuvent être :
• des primitives (scalaires) (float, int, char, etc.),
• des références d'objets (String, Object),
• des références de tableaux.
La taille d'un tableau est fixée d'une façon permanente suite à la déclaration du tableau et
à l'allocation de ressources systèmes pour ce dernier.
173
Introduction
La taille d'un tableau est donc fixée lors de sa création et ne peut plus être
changée pendant toute la durée de sa vie.
Une solution est de créer un tableau d'une taille donnée, et, lorsque celui-ci est
saturé, en créer un nouveau et déplacer toutes les références de l'ancien. Tableau
dans le nouveau. C'est précisément ce que fait la classe ArrayList ou la classe
Vector, qui seront étudiées plus loin dans ce cours.
174
Introduction
Indépendamment du type de tableau qu'on utilise, un identifiant de tableau est en fait une
référence sur un vrai objet créé dans le segment. C'est l'objet qui stocke les références
sur les autres objets, et il peut être créé soit implicitement grâce à la syntaxe
d'initialisation de tableau, soit explicitement avec une expression new. Une partie de
l'objet tableau (en fait, la seule méthode ou champ auquel on peut accéder) est le membre
en lecture seule length qui indique combien d'éléments peuvent être stockés dans
l'objet. La syntaxe « [ ] » est le seul autre accès disponible pour les objets tableaux.
175
Déclaration et création de tableaux
Déclaration.
Exemples:
ATTENTION
La taille d'un tableau n'est spécifiée qu'à partir du moment de son utilisation
dans le programme. Ainsi, la mémoire ne sera allouée que lorsque cela sera nécessaire.
Exemples:
t = new int [10]; // la variable t fait référence à un tableau de 10
// valeurs entières bien initialisées.
178
La déclaration peut se combiner à la définition du tableau produisant une
instruction plus compacte.
Dimension obligatoire
String [ ] tabcar = new String [ 14];
Dans la création d’un tableau, il faut obligatoirement
mentionner la taille du tableau.
Par défaut, les valeurs de chaque élément d'un tableau sont égales à :
- 0 pour des entiers (int, short, ...),
- 0.0 pour des nombres à virgule flottante (double, float),
- u0000 pour des caractères (char),
- false pour des booléens (boolean),
- null pour des objets (Object, String).
179
Remarque
Voici un exemple:
180
Remarques importantes
Les tableaux peuvent être initialisés par l'intermédiaire d'une liste de valeurs
séparées par une virgule et compris entre des accolades .
type [ ] identificateur = { valeur1, ..., valeurN };
type identificateur [ ] = { valeur1, ..., valeurN };
Exemples:
int [ ] notes = {10, 9, 12, 14, 16, 15, 17, 20, 19, 18};
int notes [ ] = {10, 9, 12, 14, 16, 15, 17, 20, 19, 18};
L’utilisation d’un initialiseur n’est utilisable que dans une déclaration.
int [ ] notes;
notes = {10, 9, 12, 14, 16, 15, 17, 20, 19, 18}; //interdit
182
Utilisation d’un tableau
L'accès individuel aux éléments d'un tableau est réalisé en utilisant ses indices, soit les
numéros de chacun de ses éléments, en sachant que le premier commence à l'indice 0.
Exemples:
String s[ ] = new String [10];
s[2] = new String ("Bonjour");//place la chaîne "Bonjour" dans le
// 3eme élément du tableau
double d [ ] = new double [6];
d[ 5]++; // incrémente de 1 le dernier élément du tableau
183
Utilisation d’un tableau
184
Utilisation d’un tableau
185
Utilisation d’un tableau
Remarque importante
188
Exemple de tableau en argument et en retour
500 6 71 80 1
190
Tableau dynamique
Il est possible d’augmenter la taille d’un tableau une fois que celui-ci est plein et
qu’on souhaite y ajouter des éléments.
On utilise pour cela un tableau tampon et la méthode statique arraycopy de la classe
System. Voici un exemple:
On verra au chapitre sur les Collections qu’on aura plus besoin de recourir à cette
méthode qu’il faut d’ailleurs utilisée avec précaution et modestie.
191
Algorithmes de Tri
L’intérêt d’un algorithme de tri est de trier les éléments d’un tableau selon un
critère d’ordre donné.
Un exemple de critère est:
- par ordre croissant (pour les nombres),
- par ordre lexicographique (pour les chaînes).
Pour trier les valeurs d'un tableau, il va être nécessaire de permuter les valeurs
contenues dans les différentes cases du tableau. Pour cela, une fonction de
permutation, qui sera appelée "echanger", doit être écrite. Cette fonction prend
en argument un tableau et deux entiers i et j. Elle récupère la valeur contenue dans
la iième case du tableau, affecte à cette case la valeur contenue dans la jième case,
puis affecte à la jième case l'ancienne valeur de la iième case.
192
Exemple d’échange d’éléments d’un tableau
193
Code de la méthode echanger
194
Algorithme de tri bulle
L'algorithme du tri bulle - ou bubble sort - consiste à regarder les différentes valeurs
adjacentes d'un tableau, et à les permuter si le premier des deux éléments est
supérieur au second. L'algorithme se déroule ainsi : les deux premiers éléments
du tableau sont comparés, si le premier élément est supérieur au second, une
permutation est effectuée. Ensuite, sont comparés et éventuellement permutés les
valeurs 2 et 3, 3et 4 jusque (n-1) et n. Une fois cette étape achevée, il est certain
que le dernier élément du tableau est le plus grand. L'algorithme reprend donc pour
classer les (n-1) éléments qui précédent. L'algorithme se termine quand il n'y a plus
de permutations possibles. Pour classer les n valeurs du tableau, il faut, au pire,
effectuer l'algorithme n fois.
195
Exemple de tri bulle
Évolution du tableau au fil de l'algorithme (en vert, les éléments qui sont
comparés, et éventuellement permutés, pour passer à la ligne suivante).
Premier parcours 5 3 1 2 6 4
3 5 1 2 6 4
3 1 5 2 6 4
3 1 2 5 6 4
3 1 2 5 6 4
Deuxième parcours 3 1 2 5 4 6
1 3 2 5 4 6
1 2 3 5 4 6
1 2 3 5 4 6
Tableau trié 1 2 3 4 5 6
Présentation
Le tri par sélection est l'un des tris les plus instinctifs. Le principe est que
pour classer n valeurs, il faut rechercher la plus grande valeur et la placer
en fin de liste, puis la plus grande valeur dans les valeurs restantes et la
placer en avant dernière position et ainsi de suite...
Considérons un tableau à n éléments. Pour effectuer le tri par sélection,
il faut rechercher dans ce tableau la position du plus grand élément. Le plus
grand élément est alors échangé avec le dernier élément du tableau. Ensuite,
on réitère l'algorithme sur le tableau constitué par les (n-p) premiers éléments
où p est le nombre de fois où l'algorithme a été itéré. L'algorithme se termine
quand p = (n-1), c'est à dire quand il n'y a plus qu'une valeur à sélectionner ;
celle ci est alors la plus petite valeur du tableau.
198
Algorithme de tri par sélection
Exemple
Étapes de l'évolution du tableau au fil de l'algorithme. En vert, les valeurs déjà traitées.
5 3 1 2 6 4
5 3 1 2 4 6
4 3 1 2 5 6
2 3 1 4 5 6
2 1 3 4 5 6
1 2 3 4 5 6
199
Code source Tri par sélection
(algorithmique)
tri_selection ( tableau T)
debut
entier longueur, maxi, i
longueur<- taille(T)
tantque (longueur>0) faire
//recherche de la position du plus grand élément dans le tableau non encore trié
maxi<-0;
pour i = 1 à (longueur-1) faire
si T(i) > T(maxi) alors
maxi <-i
fin si
fin pour
//echange du plus grand élément avec le dernier
echanger( T,maxi,longueur-1)
//traitement du reste du tableau
longueur<-longueur-1
fin tantque
fin 200
Code source Tri par sélection
(Java)
while (longueur>0)
{
//on recupere la position du plus grand élément du tableau non encore trié
int maxi = 0;
for ( int i = 1;i< = longueur;i++)
{
if (tableau[i]>tableau[maxi]) maxi = i;
}
echanger (tableau,maxi,longueur); //on met le plus grand élément à la fin
longueur--; //et on traite le reste du tableau !!!
}
}
201
Exemple de programme de tri par sélection
Introduction
Les tableaux vus jusqu’ici sont des tableaux à une dimension : conceptuellement
tous les éléments se trouvent dans une seule ligne (ou colonne).
Les tableaux à plusieurs dimensions sont utiles dans la modélisation des données,
mais ce sont les tableaux à deux dimensions qui sont de loin les
plus utilises en informatique. Nous concentrons notre étude à leur cas.
Un tableau `a deux dimensions, ou matrice, représente un rectangle compose de lignes
et de colonnes. Chaque élément stocké dans le tableau est adressé par sa position,
donnée par sa ligne et sa colonne.
En Java, si tab est un tableau `a deux dimensions, l’élément de ligne i et colonne j est
désigne par tab[ i ][ j ].
203
Tableau à deux dimensions
Déclaration
Pour déclarer un tableau à deux dimensions, on peut utiliser l’une de ces trois
déclarations qui sont équivalentes :
int t [ ] [ ] ; // tableau d’entiers à deux dimensions
int [ ] t [ ] ; //idem
int [ ] [ ]t ; //idem
Elles déclarent que t est une référence à un tableau, dans lequel chaque élément
est lui-même une référence à un tableau d’entiers . Pour l’instant, aucun tableau
de cette sorte n’existe encore .
204
Tableau à deux dimensions
Considérons l’instruction :
int [ ] [ ] t = {new int [3], new int [2] } ;
L’initialiseur de t comporte deux éléments dont l’évaluation crée un tableau de 3 entiers
et un tableau de 2 entiers . On aboutit à cette situation (les éléments des tableaux sont,
comme d’habitude, initialisés à une valeur nulle, ici 0) :
0 t[0][0]
0 t[0][1]
t[0] 0 t[0][2]
t[1]
0 t[1][0]
0 t[1][1]
t 205
Tableau à deux dimensions
206
Tableau à deux dimensions
Second exemple :
On peut aboutir à une situation très proche de la précédente en procédant ainsi :
int [ ][ ] ;
t = new int [2][ 3] ; // creation d’un tableau de deux tableaux d’entiers
int [ ] t1 = new int [3] ; // t1 = reference à un tableau de 3 entiers
int [ ] t2 = new int [2] ; // t2 = reference à un tableau de 2 entiers
t[0] = t1 ; t[1] = t2 ; // on range ces deux references dans t
La situation peut être illustrée ainsi :
t1 0
0
0
t
t2 0
0 207
Tableau à deux dimensions
Dans le premier exemple, nous avons utilisé un initialiseur pour les deux références
à introduire dans le tableau t ;autrement dit, nous avons procédons comme pour un
tableau à un indice . Mais, les initialiseurs peuvent tout à fait s’imbriquer, comme
dans cet exemple :
int t[ ] [ ] = { {1, 2, 3}, {11, 12}} ;
ce qui correspond à ce schéma :
t
208
Tableaux réguliers
Rien n’empêche que dans un tableau toutes les lignes aient la même taille.
Par exemple si l’on souhaite disposer d’une matrice de NLIG lignes et de NCOL
colonnes, on peut procéder comme suit:
int tab [ ] [ ] =new int [NLIG][ ];
Et faire:
for (int i = 0; i<NLIG;i++) tab[i] = new int [NCOL];
Mais on peut écrire plus simplement:
int tab [ ] [ ] =new int [NLIG][NCOL];
Maintenant il sera possible de parcourir ce tableau sans recourir à la variable
length, comme ceci:
for (int i = 0; i<NLIG;i++)
for (int j = 0; j<NCOL;j++)
tab[ i ][ j ] = i+j;
210
Exercice d’application
211
Module 7 La classe java.lang.String
212
Fonctionnalités
chaine1
ATTENTION L’objet n’a pas été modifié, c’est simplement la référence qui change.
213
Les méthodes de la classe String (1/4)
c vaut { ‘j’,’a’,’v’,’a’}
ch.indexOf ( a); // l’indice de la 1ère occurrence trouvée
renvoie la valeur 1
ch.indexOf ( a,2); // l’indice de la 1ère occurrence trouvée à partir de 2
219
renvoie la valeur 3
La méthode toUpperCase ( )
221
L’opérateur +
L’opérateur + est utilisé lorsque ses deux opérandes sont de type String. Mais, il
est possible de mélanger des expressions de type chaine et de type primitif.
Dans ce cas, il y a conversion (formatage) de la valeur de type primitif en chaîne.
int p = 100;
System.out.println (" la valeur de p est: " +p);// la valeur en binaire de p est
// representee en chaine
En définitive, lorsque l’opérateur + possède un opérande de type String, l’autre
est automatiquement converti en String.
Lorsque l’opérateur + possède deux opérandes, l’un de type String, l’autre peut être de
n’import quel type primitif, mais aussi de type objet. Dans ce dernier cas, il y a
conversion de la valeur de l’objet en chaine et ceci est réalisé grâce à la méthode
toString de la classe de l’objet qu’il faut souvent redéfinir.
222
L’opérateur +=
223
= = et equals
String ch = "note";
String s = "note";
System.out.print (ch = = s) ; // affiche la valeur true
// = = teste les références des chaînes
Une chaine n’étant pas modifiable, une seule chaine est créée et
référencée par ch et s. On parle ici d’une fusion des chaînes identiques.
String ch = " bonjour ";
String s = " bon ";
s + = " jour " ;
System.out.print (ch = = s) ; // affiche la valeur false
Vu l’utilisation non optimisée de = =, pour comparer deux chaînes il faut
utiliser la méthode equals qui compare le contenu de deux chaînes.
Cette méthode est celle de la classe Object mais redéfinie dans la classe String.
224
= = et equals
String ch = "note";
String s = "note";
System.out.print (ch.equals (s)) ; // affiche la valeur true
// equivalent à ch.equals("note " );
String ch = " bonjour ";
String s = " bon ";
s + = " jour " ;
System.out.print (ch.equals( s)) ; // affiche la valeur true
String ch = "NoTe";
String s = "note";
System.out.print (ch.equalsIgnoreCase (s)) ; // affiche la valeur true
225
Conversions chaînes et types primitifs
226
Conversions chaînes et types primitifs
Byte.parseByte
Short.parseShort
Integer.parseInt
Long.parseLong
Double.parseDouble
Float.parseFloat
227
chaînes et tableaux
mot = { ‘b’,’o’,’n’,’j’,’o’,’u’,’r’};
228
La classe StringBuffer
Cette classe n’ a aucun lien direct avec la classe String, elle se trouve
d’ailleurs dans le paquetage java.util . Elle apporte un rôle dans la
manipulation des chaînes en facilitant la division de chaînes en sous-
chaînes selon un nombre de « délimiteurs ».
Cette méthode divise une chaîne en différents éléments
appelés tokens.
FIN DU MODULE
Exercice 1:
Reprendre le code la diapositive précédente sur StringTokenizer
en proposant un programme complet où les tokens extraits sont
stockés dans un tableau de chaînes.
Exercice 2:
232
Module 8 L’Héritage en Java
package allndong.compte;
public class CompteBancaire {
double solde ; On se propose de spécialiser la gestion
CompteBancaire (double solde ) des comptes. On crée alors une classe
{ this.solde = solde; CompteChèque et une autre classe
} CompteEpargne qui dérivent de la classe
void deposer ( double montant) CompteBancaire.
{ solde +=montant;
}
void retirer (double montant)
{ if (solde >=montant ;
solde -=montant ;
}
public void imprimeHistorique ( ){
out.println (" Votre solde="+solde);
}}
234
Le concept d’héritage
GENERALISATION
CompteBancaire
champs
solde
méthodes
dérivation deposer ( )
retirer ()
PERSONNALISATION
PERSONNALISATION CompteEpargne
CompteCheque taux
interets
decouvertAutorise
calculInterets( )
changeDecouvert (double dec )
crediterInterets( )
retirer ( )
changerTaux( )
235
Le concept d’héritage
package allndong.compte;
public class CompteCheque extends CompteBancaire {
En Java, on utilise la
double decouvertAutorise;
CompteCheque (double solde, double decouvertAutorise) mention extends pour
signaler au compilateur
{ super (solde); //appelle le constructeur de la
que la classe
// super classe pour initialiser CompteCheque dérive
// le champ solde hérité. de la classe
this.decouvertAutorise = decouvertAutorise; CompteBancaire.
}
void retirer (double montant) // methode redefinie
{ if (solde + decouvertAutorise >=montant ; Ici, on rajoute un nouveau
solde -=montant ; champ decouvertAutorise.
} Et la méthode retirer est
void changeDecouvert (double dec) //nouvelle méthode redéfinie. On a aussi une
{ this.decouvert Autorise= dec; nouvelle fonctionnalité.
}
} 236
Le concept d’héritage
double taux;
CompteEpargne (double solde, double taux)
{ super (solde);
this. taux = taux;
}
// pas de methode retirer
//………
}
237
Accès aux membres {champs et méthodes}
de la classe de base.
Avec l’instruction :
CompteEpargne ce = new CompteEpargne ( 20000, 0.05) ;
On peut bien faire:
ce.retirer (10000) ;
malgré que la méthode retirer n’est pas définie dans la
classe CompteEpargne.
Un objet d’une classe dérivée accède aux membres publics (public, droit
de paquetage, protected) de sa classe de base, exactement comme s’ils étaient
dans la classe dérivée elle-même .
Une méthode d’une classe dérivée n’a pas accès aux membres
privés de sa classe de base .
238
Construction des objets dérivés
240
Quelques remarques
comme nom de méthode . Comme celui effectué par super, cet appel doit
correspondre à la première instruction du constructeur .
Dans ces conditions, on voit bien qu’il n’est pas possible d’exploiter les deux
possibilités en même temps . Autrement dit, dans un constructeur d’une classe
dérivée il n’est pas possible d’appeler en même temps un constructeur de la
même classe et un constructeur d’une classe de base.
L’appel par super ne concerne que le constructeur de la classe de base de niveau
immédiatement supérieur (vu qu’1 classe peut dériver d’une classe qui aussi dérive d’1autre.
241
Redéfinition de membres (1/4)
Avec :
CompteBancaire cb; CompteCheque cc;
l’appel : cb.retirer ( 20000);
appelle la méthode retirer de CompteBancaire.
l’appel : cc.retirer ( 20000);
appelle la méthode retirer de CompteCheque.
On se base tout simplement sur le type de l’objet pour déterminer la classe
de la méthode appelée.
Pour bien voir l’intérêt de la redéfinition des méthodes, examinons la méthode
imprimeHistorique de la classe CompteBancaire qui permet d’afficher le solde pour un
compte et la méthode imprimeHistoriqueCheque de la classe CompteCheque qui affiche
non seulement le solde (qui est un membre hérité) mais aussi le decouvertAutorise.
Dans cette dernière, il y a une information qui est déjà prise en compte dans la
méthode imprimeHistorique. La situation précédente peut être améliorée de
cette façon:
243
Redéfinition de membres (3/4)
A* f est redéfinie
ici.
f est redéfinie C*
B
ici.
D* E F
En cas de redéfinition, Java impose seulement l’identité des signatures mais aussi
du type de la valeur de retour
class A class A
{ public void f ( int n){……} { private void f ( int n){……}
} }
class B extends A class B extends A
{// impossible de mettre private {// augmente les droits d acces: possible
private void f ( int n) {….} public void f ( int n) {….}
} }
249
Règles sur :
la Redéfinition et la Surdéfinition
1 Une méthode de classe (static) ne peut pas être redéfinie dans une classe dérivée.
Cette restriction va de soi puisque c’est le type de l’objet appelant une méthode
qui permet de choisir entre la méthode de la classe de base et celle de la classe
dérivé.
2 Les possibilités de redéfinition d’une méthode prendront tout leur intérêt
lorsqu’elles seront associées au polymorphisme que nous allons étudié .
Bien que cela soit d’un usage peu courant, une classe dérivée peut définir un champ
portant le même nom qu’un champ d’une classe de base ou d’une classe
ascendante . Ce phénomène est appelé duplication de champs.
251
Duplication de champs
class A
{ public int resultat;
class B extends A
{ /* le champ resultat est duplique */
// instructions
public int resultat ;
}
float calcul( int n)
{ return resultat + super.resultat +n;
}
}
Surclassement
La réutilisation de code est un aspect important de l’héritage, mais ce n’est peut
être pas le plus important.
Un autre aspect fondamental est la relation qui relie une classe à sa super classe.
Une classe B qui hérite d’une classe A peut être vue comme un sous-type (sous -
ensemble) du type défini par la classe A.
CompteBancaire
Un CompteCheque est un CompteBancaire
Tout objet instance de la classe B peut être aussi vu comme une instance de la
classe A.
« à une référence déclarée de type A il est possible d’affecter une valeur qui est
une référence vers un objet de type B (surclassement ou upcasting) »
cb.deposer (500);
CompteCheque cc.deposer ( 250);
decouvertAutorise cb.changeDecouvert ( 10);
changeDecouvert ( )
retirer ( ) cc.changeDecouvert( 10);
255
Sousclassement (downcasting)
((CompteCheque)cb).changeDecouvert( 10);
256
Liaison dynamique
} 257
Liaison dynamique
CompteBancaire
CompteBancaire cb = new
void retirer (double montant)
CompteCheque (50000,100);
{ if (solde >=montant ;
solde -=montant ;
? }
cb.retirer ( 50)
CompteCheque
void retirer (double montant)
{if (solde + decouvertAutorise >=montant ;
solde -=montant ;
} 258
Liaison dynamique
VRAIMENT A RETENIR
259
Liaison dynamique
CompteBancaire cb = new
CompteCheque (500,100);
type réel 260
Liaison dynamique
Vérifications statiques
262
Le Polymorphisme (1/4)
263
Le Polymorphisme (2/4)
ClasseA
methodeX( )
ClasseB ClasseC
methodeX( )
objA.methodeX( );
+ médiaire d’une
classe de base
Lien dynamique : le comportement
est différent selon la classe commune.
effective de l’objet
264
Le Polymorphisme (3/4)
Etudiant
EtudiantSportif EtudiantEtranger
265
Le Polymorphisme (4/4)
267
La super classe Object
268
Référence de type Object
a = Point@fc17aedf
NB: le plus souvent, vous aurez à redéfinir cette méthode.
Nous verrons cette méthode dans le module sur la classe String.
270
equals (3/1)
274
Classes abstraites
276
Généralités
}
Alors on peut instancier un objet de type Rectangle et placer sa
référence dans une variable de type Forme (polymorphisme):
277
Exemple
package allndong;
- Une classe abstraite est une classe ayant au moins une méthode abstraite.
- Une méthode abstraite ne possède pas de définition.
- Une classe abstraite ne peut pas être instanciée (new).
- Une classe dérivée d'une classe abstraite ne redéfinissant pas toutes les méthodes
abstraites est elle-même abstraite.
- Une méthode abstraite ne doit pas être déclarée final, puisque sa vocation
est d’être redéfinie. De même une classe abstraite ne doit pas être final.
- Une méthode abstraite ne doit jamais pas déclarée private.
- Une méthode abstraite ne doit jamais pas être déclarée static.
279
Quelques remarques importantes (2/2)
abstract class A
{
void g ( int ) //nom d argument muet obligatoire sinon erreur de compilation
}
Une classe dérivée d’une classe abstraite n’est pas obligée de redéfinir toutes
les méthodes abstraites de sa classe de base(elle peut même n’en redéfinir
aucune). Dans ce cas, elle reste simplement abstraite.
Une classe dérivée d’une classe non abstraite peut être déclarée abstraite et/ou
contenir des méthodes abstraites.
280
Interfaces
Une interface correspond à une classe où TOUTES les méthodes sont abstraites.
Une classe peut implémenter ( implements) une ou plusieurs interfaces
tout en héritant (extends) d'une classe.
Une interface peut hériter (extends) de plusieur (s) interface(s).
281
Généralités
package allndong; Les modificateurs
private et protected sont
interface Operation interdits.
{ /*constantes*/ Toute variable déclarée ne
public double nombre =100 ; peut être qu’une constante
final float x = 1000; (donc ayant une valeur).
/* que des methodes abstraites*/
public double addition( );
public float division( float a, float b ); //private et protected interdit
abstract double multiplication ( ); //abstract non obligatoire
}//fin de Operation
Dans la définition d’une interface seuls les droits d’accès public et doit de
paquetage (vide) sont autorisés.
282
Utilisation d’une interface
283
Exemple de mise en oeuvre
package allndong;
abstract class Forme{ public abstract double perimetre( ) ; }// fin de Forme
interface Dessinable { public void dessiner ( ); }
class Circle extends Forme implements Dessinable {private double r;
public double perimetre ( ) { return 2 * Math.PI * r ; }
public void dessiner ( ){ //instructions de dessin d un cercle}
}//fin de Circle
class Rectangle extends Forme implements Dessinable{ private double long, larg;
public double perimetre( ) { return 2 * (long + larg); }
public void dessiner ( ){ //instructions de dessin d un rectangle}
}//fin de Rectangle
/* dans le main d une classe de test */
Dessinable [ ] dessins = {new Circle (2), new Rectangle(2,3), new Circle(5)};
for ( int i=0; i< dessins.length; i++)
dessins[i].dessiner ( );
284
Diverses situations avec les interfaces
Le fait de pouvoir
implémenter plusieurs
On dispose de deux interfaces : interfaces peut résoudre le problème
de la dérivation multiple
interface I1 {…} connue dans les autres
langages objets comme
interface I2 {…} (C++)
Il existe des classes nommées Boolean, Byte, Character, Short, Integer, Long, Float
et Double , destinées à manipuler des valeurs de type primitif en les encapsulant
dans une classe . Cela permet de disposer de méthodes et de compenser le fait que
les types primitifs ne soient pas des classes .
Toutes ces classes disposent d’un constructeur recevant un argument d’un type
primitif :
Integer objInt = new Integer (5) ; // objInt contient la référence à un
// objet de type Integer encapsulant la valeur 5
Elles disposent toutes d’une méthode de la forme xxxValue ( xxx représentant le nom
du type primitif) qui permet de retrouver la valeur dans le type primitif correspondant :
286
Exemple
Integer objet_n = new Integer (12) ;
Double objet_x = new Double (5.25) ;
interface Calculatrice{
/*calcule et renvoie la racine carrée de nombre*/
public double racineCarre(double nombre);
/*affiche le resultat renvoye par la methode racineCarre*/
public void afficheRacine();
/*calcule et renvoie val à la puissance degre*/
public double puissance(int val, int degre);
/*affiche le resultat renvoye par la methode puissance*/
public void affichePuissance();
}
288
Répondez aux questions suivantes
1) Pourquoi une nouvelle méthode d’une classe dérivée ne peut être accédée par
une référence surclassée.
2) On donne classe A { } et class Z extends A { }. Ecrire l’instruction de surclassement
entre ces deux classes.
3) Dire le rôle de la liaison dynamique en Java,
4) Dire la différence entre classe abstraire et interface,
5) A quoi correspond l’héritage multiple en Java ?
6) Pourquoi ne peut-on pas redéfinir une méthode de classe ?
7) Une classe final peut-elle être dérivable ?
8) Quel peut être le rôle du polymorphisme en Java ?
9) En quoi consiste la dérivation implicite en Java ?
10) Quels sont les rôles du mot clé super en Java ?
289
Module 9 Les Exceptions en Java
Lorsqu’un programme traite des données, il peut arriver deux types de situations
gênantes :
– on peut lui demander d’enlever un élément d’une liste vide. Il est possible de traiter
ce problème tout de suite, en disant que le résultat, dans ce cas, est une liste vide ;
– on peut aussi demander la valeur du premier élément d’une liste vide. Dans ce cas,
on ne peut pas répondre. La seule chose possible est de dire qu’il y a une erreur à
cet endroit, et charge à d’autres d’essayer de réparer cette erreur.
Dans le premier type de situations, il est possible de modifier le code en séparant les
cas (içi, liste vide ou liste non vide),pour éliminer le problème.
Le deuxième cas est plus gênant, car on ne peut pas le traiter au niveau actuel. Il faut
arrêter de faire ce qui était en cours, et signaler l’erreur. On appelle cela une
Exception.
290
Introduction
Une Exception est un problème qu’il n’est pas possible de traiter immédiatement.
292
Vue générale sur les exceptions(2/2)
293
L’instruction throw
295
Améliorations
Une bonne gestion des exceptions doit toujours permettre à l’utilisateur, s’il
le désire de pouvoir continuer l’exécution du programme après détection d’une
anomalie. Dans l’exemple précédent de la classe Except01 , la méthode division
déclenche bien une exception q’elle ne traite pas et la méthode appelante (ie la
méthode main aussi ne la traite pas non plus. C’est pourquoi le programme ne
se poursuit pas pour exécuter l’instruction System.out.println ("Merci !" ).
L’intérêt de l’exemple précédent est simplement d’avoir des informations plus
parlantes sur la nature de l’exception.
bloc try…..catch
297
Exemple avec gestionnaire d’exception
Là aussi à l’exécution, l’exception causée par la division par zéro est lancée dans
la méthode division et traitée par le bloc catch (DivisionParZero e )
dans la méthode appelante. Mais, comme précédemment l’instruction :
System.out.println( « Merci ! ») ne sera pas exécutée. Ceci parce que tout
simplement dès qu’on sort du bloc try pour entrer dans le bloc catch, on ne
peut plus revenir dans le try.
Si on veut continuer l’exécution des instructions après l’exception, il faut utiliser
l’instruction finally après catch. Cette instruction veut dire qu’il y ait exception
ou pas les instruction se trouvant dans ce bloc seront exécutées. On écrit:
finally {
System.out.println( « Merci ! »)
}
299
Comment gérer plusieurs exceptions
Dans l’exemple précèdent, on ne gérait qu’un seul type d’exception (la division
par zéro). Maintenant, nous allons voir comment prendre en compte plusieurs
exceptions dans le programme.
On rajoute, par exemple, une exception provoquée par une taille négative d’un
tableau d’entiers.
On verra en même temps comment transmettre de l’information au gestionnaire
d’exception.
En fait il faut exploiter les méthodes de la classe Exception.
300
Exemple avec plusieurs gestionnaire d’exception
Dans cet exemple, le choix du bon gestionnaire est toujours réalisé en examinant le type
de l’objet transmis au bloc catch (se rappeler que lancer une exception c’est produire
un objet de type classe d’exception.
Si, en parcourant un bloc try une exception est rencontrée mais n’est traitée par aucun
bloc catch, alors c’est la classe standard de l’exception ( faisant partie de l’API) qui est
invoquée par le compilateur pour la traiter.
En réalité, lorsque vous créez des classes d’exception, vous ne faites que personnaliser
une classe d’exception de l’API dans le but d’avoir des informations plus parlantes
quant à la nature de l’exception.
Aussi, on n’est pas sensé, à priori, connaître les classes de bases de l’API pour la
gestion des exceptions (exemple savoir qu’il y a une classe ArithmeticException qui
gère les erreurs dues à des calculs algébriques impossibles ou erronées). Mais, il faut
savoir qu’il y a une super classe Exception qui englobe la gestion de toutes formes
d’exception (et il est toujours possible de dériver de cette classe pour gérer une
exception quelconque).
302
Les exceptions standards (API)
ServerNotActiveException
Exception de serveur non actif pour une opération à distance.
SQLException :
Exception SQL : Structure Query Language (BatchUpdateException, SQLWarning).
NoSuchMethodException
Exception de méthodes introuvables.
ClassNotFoundException
Exception de classe chargée avec un nom erroné.
BadLocationException
Exception de mauvaise localisations d'une ressource.
303
Exemple avec exceptions de l’API
305
Exemple de déclenchement et traitement simultanés
Les threads peuvent être créés comme instance d’une classe dérivée de la
classe Thread. Elles sont lancées par la méthode start ( ) (pour allouer
les ressources système nécessaires), qui demande à
l’ Ordonnanceur de threads de lancer la méthode run ( ) du thread.
La méthode run ( ) doit être nécessairement implantée dans le programme.
Le schéma ci-après illustre les temps d’exécution et de latence des threads:
Thread 1
Thread 2
Thread 3
Thread 4
308
Types de threads
Les threads utilisateurs se terminent lorsque les instructions dans le corps de leur
méthode run ( ) sont toutes exécutées.
Un thread démon continue indéfiniment si aucune précaution n’a été prise pour
l’arrêter.
Nous commencerons par étudier les threads dits utilisateurs pour terminer sur
un bref aperçu portant sur les threads démons.
309
Cycles de vie d’un Thread (1/2)
État nouveau C’est l’état initial après l’instanciation du thread. Le thread est
opérationnel mais n’est pas encore actif. Un thread prend toujours cet
état après son instanciation.
État exécutable Un thread est dans cet état à partir du moment où il a été lancé par la
méthode start ( ) et le reste tant qu’il n’est pas sorti de la méthode
run ( ) . Le système donnera du temps d’exécution à votre thread dès
qu’il le pourra.
Il s’agit de thread qui n’exécute aucun traitement et ne consomme
État en attente aucune ressource CPU. Il existe plusieurs manières de mettre un
thread en attente:
- appeler la méthode Thread.sleep ( long temps_en_millisecondes)
- appeler la méthode wait ( )
- appeler une ressource bloquante (flux, accès base de données, 310
…)
- accéder à une instance sur laquelle un verrou a été posé
Cycles de vie d’un Thread (2/2)
État mort Il s’agit d’un thread qui est sorti de sa méthode run ( ) soit de façon
naturelle, soit de manière subite (exception non interceptée).
311
Constructeurs de Thread
312
Méthodes de la classe Thread
314
Premier Thread avec java.lang.Thread
(programme simple qui simule l’exécution de deux threads)
public class FirstThread extends Thread {
L’usage de la méthode statique sleep (long millis) nous permet de voir que les deux
threads s’exécutent en apparente simultaneité.
Cette méthode peut lever une exception de type InterruptedException qu’il faut donc
intercepter et capturer.
La méthode start ( ) ne peut être appelée q’une seule fois pour un thread donné, sinon
une exception de type IllegalThreadStateException est levée.
Il est possible d’appeler la méthode run ( ) pour chaque thread mais cela entraîne l’
exécution complète du thread 1 puis celle complète du thread 2. l’appel de sleep
entraînerait alors l’exécution d’autres threads autres que ceux –ci, donc ralentissement
de l’exécution de notre programme. 316
Deuxième Thread avec java.lang.Runnable
(le premier exemple réalisé ici avec l’interface Runnable)
Avec cet deuxième exemple, pour lancer l’exécution d’un thread, nous sommes
dans l’obligation d’instancier un objet de la classe implémentant Runnable:
SecondThread objetRun = new SecondThread ("thread 1");. 1
Mais cet objet n’est pas de type Thread, c’est pourquoi on ne peut pas lui appliquer
directement la méthode start ( ), il faut absolument l’enroller dans un autre objet
de type Thread pour pouvoir lancer son exécution via l’appel de start ( ).
Si un thread est bloqué, il ne peut pas déterminer s’il est interrompu. C’est à ce moment
que la classe InterruptedException intervient. Lorsque la méthode interrupt est appelée
sur un thread bloqué, l’appel bloquant (comme sleep ou wait) est terminé par une
InterruptedException.
Pour savoir si un thread est couramment actif c’est-à-dire qu’il est soit exécutable, soit
bloqué, utilisez la méthode boolean isAlive ( ). Elle renvoie true si le thread est
exécutable ou bloqué et false si le thread est nouveau et pas encore exécutable ou si le
thread est mort.
Vous ne pouvez pas déterminer si un thread actif est exécutable ou bloqué ou si un thread
exécutable est réellement en cours d’exécution. Vous ne pouvez pas non plus faire la
différence entre un thread qui n’est pas encore exécutable et un thread qui est déjà mort.
321
java.lang.ThreadGroup
Par défaut un thread appartient (est créé) au groupe (de threads) courant càd
celui qui l’a créé.
Il faut savoir que le premier thread que l’on rencontre est la méthode main.
Par défaut donc, un thread est créé dans ce groupe.
Mais il est possible de créer des groupes de threads autre que le groupe courant, et à
chacun, associé un certain nombre de threads.
Dans ce cas, il sera plus facile d’interrompre un ensemble de threads, en
interrompant simplement le groupe.
Pour cela, on crée une instance de la classe ThreadGroup avec l’un des constructeurs:
Un thread démon est un thread qui n’a aucun autre but que de servir d’autres threads.
L’exécution de tels threads peut se poursuivre même après l’arrêt de l’application
qui les a lancés. On dit qu’ils s’exécutent en tâche de fond.
Une application dans laquelle les seuls threads actifs sont des démons est
automatiquement fermée.
Un thread doit toujours être créé comme thread standard, puis il peut être
transformé en thread démon grâce à un appel de la méthode setDaemon ( true).
Mais cet appel doit se faire avant le lancement du thread sinon une exception
de type IllegalThreadStateException est levée.
Un thread démon dépend du thread parent qui l’a lancé et s’exécute en arrière plan
de ce dernier.
323
Synchronisation de Threads
(utilisation d’un moniteur (ou sémaphore) pour l’accès à une ressource partagée)
Le moniteur est utilisé pour synchroniser l’accès à une ressource partagée (qui
peut être un segment de code donné). Un thread accède à cette ressource par
l’intermédiaire de ce moniteur.
Pendant que le thread exécute la ressource partagée aucun autre thread ne peut y
accéder.
Le thread libère le moniteur dès qu’il a terminé l’exécution du code synchronisé ou bien
s’il a fait appel à la méthode wait ( ) de l’objet.
Il faut faire très attention aux méthode statiques. Synchroniser de telles méthodes revient
à bloquer le moniteur de la classe ce qui peut être source de performances médiocres
dans certains cas, puisque vous bloquez l’accès à toute la classe.
Un thread détient le moniteur s’il exécute une méthode synchronisée, un bloc synchronisé
ou une méthode statique synchronisée d’une classe.
325
Synchronisation pour un bloc
326
Premier exemple Synchronisation de bloc (1/5)
Considérons une classe Compte permettant de gérer les comptes de clients dans une
quelconque banque disposant de plusieurs agences.
Pour une gestion efficace et sécurisée des comptes client, il ne faudrait pas permettre
par exemple que deux (au moins) transactions s’effectuent simultanément sur un même
compte à un instant donné (exemple: le retrait et le dépôt).
Les opérations de retrait et de dépôt sont gérées séparément par deux threads distincts.
Notre travail sera de créer ces deux threads de telle sorte qu’ils ne pourront jamais s’
exécuter simultanément sur un même compte.
327
Premier exemple Synchronisation de bloc (2/5)
(Compte.java)
package thread.compte;
public class Compte {
private double solde;
private double decouvert;
public Compte(double solde, double decouvert){
this.solde = solde;
this.decouvert = decouvert;
}
public void deposer (double montant){
this.solde += montant;
}
public void retirer (double montant){
if (montant + decouvert <= solde)
this.solde -= montant;
}
public double getSolde ( ) {
return solde ;
}} 328
Premier exemple Synchronisation de bloc (3/5)
(ThreadCompteDepot .java)
package thread.compte;
public class ThreadCompteDepot extends Thread {
private Compte c;
private double depot;
public ThreadCompteDepot (String name, Compte c, double depot){
super (name);
this.c =c;
this.depot = depot;
}
public void run ( ){
synchronized (c) { // fondamental: on pose un verrou sur le compte
try {
System.out.print (this.getName ( ) + ":avant le depot: "+c.getSolde( ));
c.deposer (this.depot);
Thread.sleep (1000);
System.out.print (this.getName() + ":apres le depot: "+c.getSolde( )); ;
}
329
catch (InterruptedException e) { System.out.println("retrait avorte"); } } }}
Premier exemple Synchronisation de bloc (4/5)
(ThreadCompteRetrait .java)
package thread.compte;
public class ThreadCompteRetrait extends Thread {
private Compte c;
private double retrait;
public ThreadCompteRetrait (String name, Compte c, double retrait){
super (name);
this.c = c;
this.retrait = retrait;
}
public void run ( ){
synchronized (c) { // fondamental: on pose un verrou sur le compte
try {
System.out.print (this.getName ( ) + ":avant le retrait:"); S.O.P(c.getSolde ( ));
c.retirer (this.retrait);
Thread.sleep (1000);
System.out.print (this.getName() + ":apres le retrait:"); S.O.P(c.getSolde ( ));
}
catch (InterruptedException e) { System.out.println (" depot avorte"); } } }} 330
Premier exemple Synchronisation de bloc (5/5)
(TestThreadsCompte .java)
retrait:avant le retrait votre solde est: 5000.0 Si vous ne synchroniser pas le Compte
depot:avant le depot: votre solde est: 3000.0 dans les deux threads, vous aurez un
retrait: apres le retrait votre solde est: 4500.0 solde erroné .
depot:apres le depot: votre solde est: 4500.0 331
Deuxième Exemple de bloc synchronisé
On considère une classe qui permet d’inverser les éléments d’un tableau d’entiers.
Mais avant que l’inversion ne se fasse, les éléments du tableau doivent être incrémentés
d’une valeur égale à l’indice de l’élément en cours. Et après, l’inversion pourra se faire
après un certain délai.
On disposera d’une méthode affiche qui nous permettra d’envoyer sur la console
les éléments du tableau inversé.
Mais ici, nous avons un problème à gérer:
Avant que la méthode affiche n’accède au tableau pour l’afficher, il faudra que la
méthode qui se charge de l’incrémentation et de l’inversion finisse carrément son
travail, sinon l’affichage sera complètement faux.
Regardons maintenant comment on peut passer d’un mauvais exemple vers un cas où
les données seront correctes.
332
Exemple de bloc NON synchronisé (1/4)
class TabInverse {
int t [ ];
int [ ] inverse (int tableau [ ])
{ t = new int [tableau.length ];
/*cette classe permet de créer un thread qui n’accédera qu’à la methode inverse
Cet objet peut donc manipuler simultanément le tableau qu’un autre thread */
class EssaiSynchroInverse extends Thread{
TabInverse inv;
int tab[ ];
public EssaiSynchroInverse (String name, TabInverse inv, int tab [ ] )
{ super (name);
this.inv = inv;
this.tab = tab;
}
public void run ( )
{System.out .println (this.getName ( ) ) ;
inv.inverse (tab) ;
try {Thread.sleep (1000) ;}
catch (InterruptedException er) { }
System.out .println("FIN de "+this.getName ( ) ) ;
}} 334
Exemple de bloc NON synchronisé (3/4)
/*cette classe permet de créer un thread qui n’accédera qu’à la methode affiche
Cet objet peut donc manipuler simultanément le tableau qu’un autre thread */
class EssaiSynchroAffiche extends Thread{
TabInverse inv;
int tab[ ];
public EssaiSynchroAffiche (String name, TabInverse inv, int tab[] )
{ super (name);
this.inv = inv;
this.tab = tab;
}
public void run ( )
{ System.out .println (this.getName ( ) ) ;
inv.affiche ( ) ;
try {Thread.sleep(1000) ;}
catch (InterruptedException er) { }
System.out .println ("FINITION de "+ this.getName ( ) ) ;
}} 335
Exemple de bloc NON synchronisé (4/4)
Pour corriger ce défaut, il faut poser un verrou sur l’objet tableau partagé et sur inv… 336
Deuxième Exemple de bloc synchronisé
Chaque fois que deux threads s’exécutent en même temps, il faut souvent prendre des
mesures adéquates pour qu’ ils n’accèdent pas simultanément à une même variable.
Le principe d’exclusion mutuelle doit être assuré sur le partage simultané d’objet
(pour assurer la cohérence des données) par l’utilisation de méthodes dites synchronisées.
Ce principe est assuré lorsqu’une méthode est déclarée avec le mot clé synchronized.
Une méthode synchronisée appartient à un objet quelconque, pas forcément à un thread.
Lorsqu’une méthode déclarée synchronized, est en cours d’exécution par un thread, tous
les autres threads qui en auraient besoin doivent attendre la fin de son exécution.
Lorsque synchronized est utilisé comme modifieur de méthode d’instance, une instruction
telle que: synchronized void method ( ) {…….} est équivalente à:
void method ( ) {
synchronized (this) { ….}
} 338
Exemple de Synchronisation de méthodes (1/4)
Regardons d’abord comment les valeurs des deux champs sont érronées et incohérentes si
l’exclusion mutuelle n’est pas bien gérée: l’incohérence s’explique par le fait que le s
trois threads manipulent les deux champs pèle mêle.
Nous verrons alors une version qui dégage une utilisation correcte de la valeur de ces
variables.
339
Exemple de Synchronisation de méthodes (2/4)
class Synchro {
int n, som;
public Synchro (int n,int som) { this.n =n; this.som =som;
}
void addition ( ){ // methode non synchronisée
System.out .print ("n++= "+(n++) +" suivi de ") ;
try { Thread.sleep (222) ;}
catch (InterruptedException t){ }
som += n; System.out .println(" et som="+som) ;
}
void affiche ( ){ // methode non synchronisée
System.out .print("affiche: n= " +(++n)+" et ");
try {Thread.sleep (222) ;}
catch (InterruptedException t){ }
System.out.println ("affiche :som= "+som);
}}
340
Exemple de Synchronisation de méthodes (3/4)
}
}
342
Sortie de l’ exemple
Attention: c’est des méthodes de la super classe Object et non de la classe Thread.
Elles implantent des mécanismes de demande de verrou et d’ avertissement de libération
de ce verrou.
une méthode synchronisée peut appeler la méthode wait( ) de l’objet dont elle possède
le verrou, pour:
- rendre le verrou à l’environnement qui peut alors le donner à une autre méthode
synchronisée,
- mettre en attente le thread correspondant.
Une méthode synchronisée peut appeler la méthode notifyAll ( ) d’un objet afin de
prévenir tous les threads en attente sur cet objet et de leur donner la possibilité de
s’exécuter.
NB: notifyAll( ) permet de débloquer un wait ( ) sur un objet où notify( ) a été lancé.
La méthode notify ( ) prévient un seul thread. Avant de faire un notify ( ) ou notifyAll()
il faut changer la condition de boucle qui mène au wait ( ).
345
Exemple: producteur - consommateur. (1/4)
Un producteur est un thread qui dépose des jetons numérotés dans un chapeau
qui ne peut contenir qu’un seul jeton. Un consommateur prend ce jeton qui doit
être présent dans le chapeau. Donc:
- le producteur doit s’arrêter de déposer des jetons lorsqu’il y en a déjà un et doit
être informé qu’un jeton a été retiré.
- le consommateur ne peut pas prendre de jetons s’il n’y en a pas (arrêt du
consommateur) et doit être informé lorsqu’un jeton a été déposé.
L’objet le plus à même pour avertir le producteur et le consommateur est le
chapeau lui-même.
346
Exemple: producteur - consommateur. (2/4)
(fichier Producteur.java)
(fichier Consommateur.java)
(fichier Chapeau.java)
public class Chapeau {
private int contenu; /*une classe pour tester*/
private boolean permis = false; public class TestProductCons {
public synchronized int get ( ){ public static void main(String [ ] args) {
while (permis == false) Chapeau chap = new Chapeau ( );
{ try {wait ( ); // rendre le verrou } Producteur p = new Producteur(chap,1);
catch (InterruptedException e){ } Consommateur c=
} new Consommateur(chap,1);
permis = false; notifyAll ( ); p.start ( ) ;
return contenu; } c.start ( );
public synchronized void put (int value){ }
while (permis == true) }
{ try { wait ( );}
catch (InterruptedException er) { } }
contenu = value; permis = true;
notifyAll ( );// attribuer le verrou à un autre
// qui peut alors s’exécuter
349
Exemple: producteur – consommateur: sortie
le producteur N° 1 a mis 0
le consommateur N° 1 a pris 0
le producteur N° 1 a mis 1
le consommateur N° 1 a pris 1
le producteur N° 1 a mis 2
le consommateur N° 1 a pris 2
le producteur N° 1 a mis 3
le consommateur N° 1 a pris 3
le producteur N° 1 a mis 4
le consommateur N° 1 a pris 4
350
Exercice: producteur – consommateur
(fichier Consommateur2.java)
le producteur N° 1 a mis 0
le consommateur N° 1 a pris 0
le producteur N° 2 a mis 0
le consommateur N° 1 a pris 0
le producteur N° 3 a mis 0
le consommateur N° 1 a pris 0
Voici un exemple de sortie le producteur N° 3 a mis 1
du programme de test. le consommateur N° 1 a pris 1
le producteur N° 3 a mis 2
le consommateur N° 1 a pris 2
le producteur N° 1 a mis 1
le consommateur N° 2 a pris 1
le producteur N° 1 a mis 2
le consommateur N° 2 a pris 2
le producteur N° 1 a mis 3
le consommateur N° 2 a pris 3
le producteur N° 1 a mis 4
………
354
Priorité des Threads
Jusqu’à présent, nous n’avons manipulé que des threads de même priorité.
En théorie, il est permis d’attribuer une certaine priorité à un thread.
Pour cela, on utilise la méthode setPriority (int threadPriority) où le paramètre
transmis en argument est une valeur entière comprise entre MIN.PRIORITY
(correspondant à la valeur 1) et la valeur MAX.PRIORITY (correspondant à 10).
355
Priorité des Threads: Exemple (1/2)
Ce qu’on aurait si les deux threads étaient de même priorité (celle par défaut).
357
FIN DU MODULE
Module 11 Les Swing GUI
Quelle est la différence entre les composants AWT et les composants Swing ?
358
AWT et Swing
Les composants AWT sont des composants " lourds" c-à-d des contrôles
produits par la machine virtuelle à destination du système d’exploitation.
Si vous créez par exemple un bouton Button tiré du module java.awt sous
Windows NT, la machine virtuelle génère un bouton NT et lui communique
tous les paramètres nécessaires à son initialisation . L’aspect du bouton, comme des
autres composants de ce type, dépend du système d’exploitation utilisé.
Les composants Swing sont des composants " légers " c-à-d directement dessinés
par la machine virtuelle. Le composant aura toujours le même aspect quelque soit la
plateforme utilisée. On trouve dans les Swing plus de fonctionnalités.
Pour les Swing, un conteneur de plus haut niveau se compose d’une " fenêtre visible " ,
la ContentPane, placée au dessus de la fenêtre native . Les composants GUI doivent se
placer dans cette ContentPane.
359
Création d’une fenêtre Swing
import java.awt.*;
import javax.swing .*;
public class Swing01 extends JFrame {
public Swing01 (String titre) {
this.setTitle (titre);
this.setSize (250,200);
// nécessité de récupérer le ContentPane
fen.setVisible (true);
}
} 360
La même fenêtre en AWT
import java.awt.*;
public class AWT01 extends Frame {
361
Remarques
Les classes Color et Container sont présentes dans le module java.awt , c’est
pourquoi il faut toujours importer ce package. Dans la gestion des interfaces
graphiques, il ne s’agit pas simplement de construire des composants, mais il
faut aussi pouvoir interagir avec eux en produisant des évènements.
Il s’agit de la programmation évènementielle qui nécessitent les classes
de gestion d’évènements présentées dans les modules java.awt.event .* et
javax.swing.event .*
En somme, il faut importer au minimum , les quatre bibliothèques suivantes:
java.awt.*
java.awt.event .*
javax.swing .*
javax.swing.event .*
362
Ajout d’un composant léger: un JButton
import java.awt.*;
import javax.swing .*;
public class Swing02 extends JFrame {
bouton.setBackground (Color.green);
contenu.add (bouton);
364
Remarques sur l’ajout du JButton
365
Le gestionnaire de JFrame: BorderLayout
import java.awt.*;
import javax.swing .*;
public class Swing03 extends JFrame {
Pour bien gérer un évènement c-à-d une action sur un composant graphique, il faut:
367
Gestion de l’interface MouseListener
En Java, tout évènement possède ce qu’on appelle une source. Il s’agit de l’objet
ayant donné naissance à cet évènement : bouton, menu, fenêtre…
368
Gestion de l’interface MouseListener
Il existe une catégorie d’évènement souris qu’on peut traiter avec un écouteur de
souris, c’est-à-dire un objet d’une classe implémentant l’interface MouseListener.
Cette interface possède cinq méthodes:
mouseClicked, mouseEntered, mouseReleased, mouseExited et mousePressed.
Pour prendre en compte la gestion du clic, seul l’évènement clic nous intéresse et
ce dernier correspond à la méthode mouseClicked. Mais comme on implémente
une interface, on est obligé de redéfinir toutes les méthodes de cette dernière.
369
Gestion de l’interface MouseListener
Dans l’exemple précèdent, nous avons choisi la fenêtre comme son propre écouteur
d’évènement souris. C’est pourquoi, il est obligatoire de mentionner
implements MouseListener dans l’en tête de la classe. Si vous l’omettez, il y a erreur de
compilation.
La mention this.addMouseListener ( this ) associe un écouteur à la fenêtre principale.
Si vous l’omettez, il n’ y a pas erreur, seulement le clic sera sans effet.
Supposons maintenant, au lieu de considérer que la fenêtre soit son propre écouteur
d’évènement souris, que son écouteur soit un objet quelconque.
Tout ce qu’il faut vraiment savoir ici est que la classe de cet objet doit implémenter
l’interface MouseListener.
Voyons comment traiter l’exemple précèdent :
371
Personnalisation de l’objet écouteur (1/2)
}
}// fin de la classe Swing05
372
Personnalisation de l’objet écouteur (2/2)
373
Les classes Adaptateur (1/4)
Comment faire donc pour n’utiliser que la méthode qui nous intéresse ici ?
Il existe une classe particulière appelée MouseAdapter qui implémente toutes les
méthodes de l’interface MouseListener ceci:
class MouseAdapter implements MouseListener
{ public void mouseReleased ( MouseEvent e) { }
public void mouseExited ( MouseEvent e) { }
public void mousePressed ( MouseEvent e) { }
public void mouseEntered ( MouseEvent e) { }
public void mouseClicked ( MouseEvent e) { } 374
}
Les classes Adaptateur (2/4)
Comme MouseAdapter est une classe et non une interface, on pourra désormais en
dériver simplement ce qui nous permettra d’utiliser que les méthodes que nous
souhaitons exploiter (en les redéfinissant).
375
Les classes Adaptateur (3/4)
}
}// fin de la classe Swing05
376
Les classes Adaptateur (4/4)
377
Gestion de l’écouteur
Avec une classe Anonyme
}
}
378
Mettre fin à l’application (1/2)
379
Mettre fin à l’application (2/2)
import java.awt.*;
import javax.swing .*;
public class Swing03 extends JFrame {
/* pour mettre fin a l’application des qu’on clique sur le bouton de fermeture*/
this.addWindowListener (new WindowAdapter ( )
{ public void windowClosing (WindowEvent e)
{ System.exit ( 0);
}
} );
}
380
}
Action sur un bouton
Un bouton gère une catégorie d’évènement appelée action qu’on l’on traite
avec un écouteur qui est un objet implémentant l’interface ActionListener.
Cette dernière ne possède qu’une seule méthode :
public void actionPerformed (ActionEvent ev).
Comme illustration, nous allons considérer un bouton et deux zones de
texte, l’une contenant un texte et l’autre étant vide;
Le clic sur le bouton entraînera la copie du contenu de la première zone
de texte dans la seconde, et le vidange de celle-là.
On supposera que la fenêtre est l’objet écouteur des clics sur le bouton.
381
Action sur un bouton
}
public static void main(String[] args) {
Swing06 fen = new Swing06("Ma Fenêtre Swing");
fen.setVisible(true);
}
}
383
Action sur un bouton
Le rôle d’un gestionnaire de mise en forme est de permettre une disposition des
composants selon le choix de l’utilisateur. Nous avons déjà vu le gestionnaire
BorderLayout pour la fenêtre principale. Nous allons à présent explorer les
autres types de gestionnaires.
FlowLayout : représente les composants sur une même ligne, les uns à la suite des
autres; s’il n’y a plus d’espace en fin de ligne, il passe à la ligne suivante.
CardLayout : permet de disposer des composants suivant une pile, à la manière d’un
paquet de cartes, un seul composant étant visible à la fois,
BoxLayout : dispose les composants sur une seule ligne ou sur une seule colonne,
GridBagLayout : dispose les composants sur une grille,la taille d’un composant dépend
du nombre de cellules que le composant occupe.
GridLayout : dispose les composants sur une grille, les composants de même colonne
ayant la même taille.
385
Exemples de mise en œuvre de FlowLayout
Mais cette instruction ne suffit pas pour placer les composants au conteneur.
Tout composant à ajouter doit disposer d’un objet GridBagConstraints lequel spécifie
comment faire le placement des différents composants:
/*The GridBagConstraints class provides the means to control the layout of components
within a Container whose LayoutManager is GridBagLayout.*/
/*Specifies the alignment of the component in the event that it is smaller than the space
allotted*/
public int anchor
/*The component's resize policy if additional space available. */
public int fill
/*Number of columns (gridheight), of rows (gridwidth) a component occupies.*/
public int gridheight, public int gridwidth
/*Horizontal (gridx), vertical (gridy) grid position at which to add component. */
public int gridx, public int gridy
/*Specifies the outer padding around the component.*/
public Insets insets
/*Serves as the internal padding within the component in both the right and left direction*/
public int ipadx
/*Serves as the internal padding within the component in both the top and bottom
directions*/
public int ipady 390
GridBagConstraints: variables et méthodes (2/2)
391
Exemple de mise en œuvre de GridBagLayout
1 2
GridBagConstraints gr;
public ExGridBagConstraints( ) {
this.setResizable ( false ) ;
this.setTitle ("Création d'un nouveau client") ;
Dimension screensize = Toolkit.getDefaultToolkit() .getScreenSize() ;
Dimension framesize = this.getSize() ;
if (framesize.width > screensize. width ) framesize. width =screensize.width ;
if (framesize.height > screensize.height ) framesize.height =screensize.height ;
this.setLocation ((screensize.width -framesize.width )/3,
(screensize.height -framesize.height )/3) ;
393
Code Exemple (2/7)
394
Code Exemple (3/7)
395
Code Exemple (4/7)
397
Code Exemple (6/7)
}
}
} // fin de la classe
399
Aucun Gestionnaire de disposition
Si vous voulez rangés en même temps et directement dans un JFrame des composants
suivant une grille avec par exemple GridLayout et d’autres composants selon une ligne
horizontale avec FlowLayout, cela va s’avérer impossible puisque vous ne pouvez pas
appliquer deux gestionnaires simultanément.
L’astuce qu’il faut utiliser est de créer deux panneaux, l’un pour le premier groupe de
composants, le second pour le deuxième groupe.
Les panneaux sont des conteneurs puisqu’ils servent à contenir des composants.
Un panneau est sorte de sous fenêtre sans titre, ni bordure.
Le gestionnaire par défaut de JPanel est FlowLayout.
401
Exemple de JPanel
panHaut
Impossible
d’agrandir
la fenêtre.
Bordure avec intitulé
Bordure
panBas épaisse.
402
Code Exemple de JPanel
403
Code Exemple de JPanel (suite)
406
Exemple de dessin dans un JPanel
Nous allons dans cette partie voir comment créer des contrôles comme
des zones de texte sur plusieurs lignes ( JTextArea ), des cases à cocher
(JCheckBox), des boutons d’options (JRadioButton), des boîtes de listes
(JList) et listes combinées (JComboBox).
409
Exemple d’application
JList JComboBox
JMenu
JMenuItem
JMenu
JMenuItem
JTextArea
JCheckBox
JRadioButton
410
Code Exemple d’application (1/5)
411
Code Exemple d’application (2/5)
414
Code Exemple d’application (5/5)
Les évènements liés aux JCheckBox et aux JRadioButton sont soit, l’action de l’utilisateur
sur le composant soit connaître l’état du composant (sélectionné ou non).les interfaces qu’ils
utilisent sont respectivement ActionListener contenant une seule méthode
void actionPerformed (ActionEvent e) et ItemListener contenant aussi une seule méthode
void itemStateChange (ItemEvent e).
416
Création de boîtes de dialogue
JFrame
clic
JDialog
417
Code de l’interface (1/2)
418
Code de l’interface (2/2)
Dans l’instruction :
dialog = new JDialog( this, "Mon premier dialog", true); on a trois arguments:
this désigne la fenêtre propriétaire (parent) c-à-d celle contenant le JDialog
"Mon premier dialog " désigne le titre de la boîte de dialogue
true la boîte de dialogue est modale c-à-d une fois lancée, l’utilisateur ne peut pas agir
sur d’autres que ceux intégrés dans la boîte de dialogue.
Remarque : il est possible (de la même façon qu’on utilise la classe JFrame) de créer
une classe qui dérive de JDialog et d’y ajouter toutes les fonctionnalités
dont on souhaite disposer.
Il est aussi possible de créer des boîtes de dialogue sans faire usage de la classe JDialog.
C’est ce que nous allons voir dans le paragraphe suivant avec la classe JOptionPane.
420
La classe: javax.swing.JOptionPane
JFrame
JOptionPane
421
Exemple message: JOptionPane.showMessageDialog
message
Fenêtre parent
Type message titre
Il se peut aussi qu’on veuille effectuer un certain traitement si l’on clique sur
l’un des boutons Yes, No ou Cancel. Dans ce cas, récupérer la valeur renvoyée par
la méthode showConfirmDialog sous une valeur de type entière (int ).
La valeur 0 correspond au clic sur Yes, 1 au clic sur No et 2 au clic sur Cancel.
424
Remarques (2/2)
Il peut arriver qu’on veuille personnaliser le nom des boutons Yes, No et Cancel
selon la langue utilisée.
Comment ferais t-on par exemple pour remplacer ces boutons par Oui, Non et
Annuler?
Utilisez, pour ce faire la méthode showOptionDialog (…).
JFrame frame=…..
File image = new File ( "E:\\imagesMEDICALES\\img2.png");
JLabel background=null;
try {
background = new JLabel(new ImageIcon(ImageIO.read(image)));
}
catch (IOException ex) {
Logger.getLogger(Fenetre.class.getName()).log(Level.SEVERE, null, ex);
}
frame.setContentPane(background);
427
Exemple de code
}
} 428
Remarque
La nature des données échangées peut également être diverse: texte, images, son, etc.
Par rapport à la direction du flux, on peut ranger les flux en deux familles:
o les flux d’entrée ( input stream)
o les flux de sortie (output stream)
par rapport à la nature des données manipulées, on peut diviser les flux en deux
grandes catégories:
les flux de caractères
les flux d’octets (ou flux binaires)
Java définit des flux pour lire ou écrire des données mais aussi des classes pour
traiter les données du flux. Ces classes doivent être associées à un flux de lecture
ou d’écriture et sont considérées comme des filtres. 431
Vue générale sur les flux
Remarque:
A partir du JDK 1.4 de nouvelles classes de flux sont introduites dans le paquetage
java.nio . Nous y reviendrons lors de la programmation réseau avec les sockets.
432
Les classes de flux
L’utilisation de ces classes n’est pas chose facile, vu leur nombre élevé et la
difficulté de choisir la classe convenable à un besoin précis.
Pour bien choisir une classe adaptée à un traitement donné, il faut comprendre
la dénomination des différentes classes.
Le nom d’une classe est toujours composé d’un préfixe et d’un suffixe.
433
Les classes de flux: suffixes
434
Les classes de flux
Il existe donc quatre hiérarchies de classes qui encapsulent des flux particuliers.
Ces classes peuvent être séparées en deux séries de deux catégories différentes:
les classes de lecture et d’écriture et les classes de manipulation
de caractères et d’octets.
les sous classes de Reader sont des types de flux en lecture sur les caractères,
les sous classes de Writer sont des types de flux en écriture sur les caractères,
les sous classes de InputStream sont des types de flux en lecture sur les octets,
les sous classe de OutputStream sont des types de flux en écriture sur les octets.
435
Les flux de caractères
Les classes qui gèrent les flux de caractères héritent d’une des deux classes
abstraites Reader et Writer.
Il existe beaucoup de classes dérivées de celles-ci qui permettent de traiter
les flux de caractères.
437
Les flux de caractères
438
La classe Reader
C’est une classe abstraite qui est la classe de base de toutes les classes qui gèrent
des flux texte d’entrée.
quelques méthodes:
void close ( ) // ferme le flux et libère les ressources qui lui étaient associées
int read ( ) // renvoie le caractère lu et -1 si la fin du flux est atteinte
boolean ready( ) // indique si le flux est prêt à être lu
boolean markSupported ( ) // indique si le flux supporte la possibilité de marquer
// des positions
void mark (int ) // permet de marquer une position dans le flux
void reset ( ) // retourne dans le flux à la dernière position marquée
439
La classe java.io.FileReader
Cette classe permet de gérer les fichiers texte d’entrée. Elle dispose des
mêmes fonctionnalités que la classe abstraite Reader.
Mais les méthodes de cette classe sont rudimentaires, c’est pourquoi, il faut
souvent la coupler à un objet de la classe BufferedReader qui possède des
méthodes plus appropriées et complètes à la manipulation de fichiers textes
en lecture.
La classe BufferedReader est doté d’un tampon et d’une méthode
String readLine ( ) pour la lecture d’une ligne.
440
Lecture rudimentaire d’un fichier texte
441
Lecture rudimentaire d’un fichier texte
La lecture des données du flux est rudimentaire, elle se fait caractère par caractère
package lecture;
import java.io.FileNotFoundException; import java.io.FileReader;
import java.io.IOException;
public class LectureTexte {
public static void main(String[] args) {
java.io.FileReader flux=null;
try {
flux = new FileReader ("E:/test.txt");
} catch (FileNotFoundException e) {e.printStackTrace(); }
int k;
try {
k = flux.read();
while (k!=-1){
out.println((char)k); Affichage du caractère lu
k=flux.read();
}} catch (IOException e) {e.printStackTrace(); }
finally {
try {flux.close();} catch (IOException e) {e.printStackTrace ();
}}} 442
Amélioration de la vitesse de Lecture : usage de filtre
package lecture;
import java.io.FileNotFoundException; import java.io.FileReader;
import java.io.IOException;
public class LectureTexte {
public static void main (String[] args) {
FileReader flux=null; BufferedReader filtre=null;
try {
flux = new FileReader ("E:/test.txt"); filtre=new BufferedReader (flux)
} catch (FileNotFoundException e) {e.printStackTrace(); }
String k;
try {
k = filtre.readLine();
while (k!=null){
out.println(k);
k=filtre.readLine();
}} catch (IOException e) {e.printStackTrace(); }
finally {
try {filtre. close( ); flux.close();} catch (IOException e) {e.printStackTrace ();
}}}
444
Remarques
445
La classe java.io.File
La classe File permet la gestion des fichiers et des répertoires (création, suppression,
renommage, copie, etc.….).
Pour la création d’un fichier, on utilisera souvent l’un des deux constructeurs:
File ( File fileName) // on transmet le nom simple du fichier
File ( String pathName) // on transmet le répertoire complet du fichier
449
Exemples
Le fichier memoire.txt est situé dans C:\ et le fichier lettre.txt dans le répertoire
450
absolu C:\joe\fic
Méthodes de la classe File
/*crée un nouveau fichier qui n’existait pas, renvoie true si la création réussie*/
boolean createNewFile ( )
/* essaie de supprimer le fichier, renvoie true si la suppression réussie
renvoie false si le fichier n’existe pas*/
boolean delete ( )
/*crée un répertoire ayant le nom spécifié, renvoie true si la création s’est
déroule correctement. Seul le dernier niveau du répertoire peut être créé*/
boolean mkdir ( )
/* idem que mkdir mais avec possibilité de création d’éventuels
niveaux intermédiaires de répertoires*/
boolean mkdirs ( )
/* renvoie true si le fichier correspondant existe*/
boolean exits ( )
/*renvoie true si l’objet correspond à un nom de fichier (même si le fichier
en tant que tel n’existe pas*/
boolean isFile ( )
451
Méthodes de la classe File
452
Méthodes de la classe File
String [ ] list (FilenameFilter filtre ) // fournit les éléments du répertoire sous forme
//d’un tableau de chaînes
File[ ] listFiles (FilenameFilter filtre) // fournit les éléments du répertoire sous forme
//d’un tableau de fichiers
453
Exercice: lecture***
Contenu du fichier lu
Répertoire du fichier lu
454
Exercice : lecture***
Réaliser une classe qui permet de lire un fichier (.txt) situé sur disque à partir
de l’ interface graphique précédent. On utilisera les classes vues précédemment.
On prévoira:
- une méthode void ouvrirFichierEnLecture ( ) permettant d’ouvrir la boîte de
dialogue du système de fichiers de Windows pour sélectionner le fichier à lire.
Cette méthode appellera lireFichier pour lire le fichier sélectionné.
- une méthode void lireFichier (File nom) qui permet d’écrire le contenu du
fichier lu dans l’interface graphique.
On ne peut lire que les fichiers qui existent et qu’on peut ouvrir en lecture.
Pour les boîtes de sélection de fichier sous Windows, utilisez la classe JFileChooser
ou la classe FileDialog.
455
Exercice lecture***: Corrigé express
if (retval == JFileChooser.APPROVE_OPTION)
{
File fichier = fileChooser.getSelectedFile ( ); // on sélectionne un fichier
String chemin = fichier.getAbsolutePath ( ); // on extrait le chemin absolu
annonce.setText (" "+chemin);
if ( fichier.isFile( ) && fichier.canRead ( ))
lireFichier(fichier); // appelle la méthode de lecture du fichier sélectionné
}
456
Exercice lecture***: Corrigé express
}
catch (IOException e) {annonce.setText("Erreur de lecture du fichier");}
}
} //fin de FileReading
457
Exercice lecture***: Notes
f.dispose();
{
FileWriter fw=new FileWriter(s,true);
PrintWriter pw=new PrintWriter(fw,true);
pw.println("bonjour");
pw.close();
fw.close();
}
}
459
java.io.StreamTokenizer
460
java.io.StreamTokenizer: champs et méthodes
champs
Méthodes
void printArray(){
System.out .println (liste.toString ( ) ) ;
}
} // fin de la classe
Remarque:
465
Filtre sur les noms de fichiers
Toute classe qui définit un filtre sur un fichier doit implémenter l’interface
FilenameFilter et donc redéfinir la seule méthode cette dernière:
/*là on définit les conditions du filtre*/
public boolean accept (File rep, String nom).
466
Exemple de Filtre
C’est une classe abstraite qui est la classe de base de toutes les classes de flux de
caractères en écriture.
Elle définit quelques méthodes rudimentaires:
/*ferme le flux et libère les ressources qui lui étaient associées*/
void close ( )
/*écrire le caractère en paramètre dans le flux*/
void write ( int)
/* écrire le tableau de caractères dans le flux*/
void write (char [ ])
/*écrit le tableau de caractères tab, i = indice du premier caractère à écrire
j = le nombre de caractères à écrire*/
void write (char [ ], int i, int j)
/*écrire la chaîne de caractères en paramètre dans le flux*/
write (String )
/*écrire une chaîne à partir du caractère i , j étant le nombre de caractères à écrire*/
468
write (String, int i, int j)
La classe java.io.FileWriter
Cette classe gère les flux de caractères en écriture. Elle possède plusieurs
constructeurs qui permettent un ou plusieurs caractères dans le flux:
/*Si le nom spécifié n’existe pas alors le fichier sera créé. S’il existe et qu’il
contient des données, celles-ci seront écrasées*/
FileWriter (String nomfichier)
/* Idem que précédemment mais ici le fichier est précisé avec un objet de
la classe File* /
FileWriter (File nomfichier)
/*le booléen permet de préciser si les données seront ajoutées au fichier
(valeur true) ou écraseront les données existantes (valeur false)*/
FileWriter (String, boolean)
469
La classe java.io.FileWriter
Pour améliorer les performances des flux d’écriture sur un fichier texte, la mise en
tampon des données écrites permet de traiter un ensemble de caractères plutôt que
traiter caractère par caractère. La mise en tampon entraîne un gain de temps.
472
Exercice : écriture***: Corrigé
473
Exercice : écriture***: Corrigé
474
La classe java.io.LineNumberReader
(cette classe permet de numéroter les lignes d’un flux de caractères)
/** Exemple de copie d’un fichier texte dans un autre fichier avec numérotation des
lignes. La première ligne porte le numéro 1.
*/
public class NumeroLigne {
public static void main (String [] st) throws IOException {
File src = new File ("c:\\ joe\\ fex.txt"); // on copie ce fichier
File dest = new File ("c:\\ joe\\ newT.txt"); // dans celui-ci avec des numéros de lignes
LineNumberReader in = new LineNumberReader (new FileReader (src)) ;
BufferedWriter out = new BufferedWriter (new FileWriter (dest));
String s = in.readLine ( );
while (s != null) {
out.write (in.getLineNumber ( ) + ": " + s + "\r\n");
s = in.readLine ( ); // pour marquer une fin de
} //ligne.
in.close ( );
out.close ( );
}} 475
La classe java.io.PrintWriter
476
La classe java.io.PrintWriter
Il existe aussi plusieurs méthodes println (anyType var ) faisant la même chose que la
méthode print mais les données sont écrites avec une fin de ligne.
La classe PrintWriter présente un e méthode spéciale void flush ( ) qui vide le tampon
(sans que le flux ne soit fermé) en écrivant les données dans le flux.
Les méthode write (…) de cette classe hérite de Writer.
477
Exemple PrintWriter
Utiliser la classe PrintWriter Réaliser une classe CopyFile qui permet de copier le
contenu d’un fichier texte dans un autre fichier texte. On prévoira:
-une méthode void copyFile( File src, File dest) permettant de copier le contenu
du fichier src dans le fichier dest. La copie sera conforme (ie les données apparaîtront
dans les deux fichiers exactement de la même manière)
on suppose que le fichier dest peut ne pas exister, dans ce cas, il faut prévoir:
- la méthode void createFile (File f) qui permet de créer le fichier f s’il n’existe pas encore.
Avant de réaliser la copie dans copyFile, il faut s’assurer que le fichier dest existe ou
pas en appelant createFile qui créera éventuellement ce fichier.
/*une classe de test pour cet exercice*/
public class TestCopy {
public static void main(String[] args) {
File s = new File ("c:\\joe\\source.txt");
File d = new File ("c:\\joe\\dest.txt"); // si dest.txt n’existe pas, il est alors créé
new CopyFile ( ).copyFile (s,d) ; // et la copie est effectuée ici
}} 479
Exercice avec PrintWriter : Corrigé
Les classes qui gèrent les flux d’octets héritent d’une des deux classes abstraites
InputStream (flux binaire d’entrée) et OutputStream (flux binaire de sortie).
Ces deux classes abstraites disposent de méthodes rudimentaires:
void write (int ) //écrit un octet int read ( ) // lit un octet, -1 si fin du flux
void write (byte [ ]) // écrit un tableau d’octet int read (byte[ ]) // lit une suite d’octets
void close ( ) //ferme le flux void close ( ) // ferme le flux
void flush ( ) //vide le tampon void skip (long n) // saute n octets dans le
//flux
481
Classe java.io.FileInputStream
Cette classe permet de gérer les flux binaires en lecture sur un fichier.
Cette classe possède plusieurs constructeurs qui peuvent tous lever une
exception de type FileNotFoundException .
Cette classe hérite des méthodes de la classe InputStream mais elle définit aussi
d’autres méthodes qui permettent de lire un ou plusieurs octets dans le flux.
La méthode int available ( ) permet de connaître le nombre d’octets qu’il est encore
possible de lire dans le flux.
482
Exemple de lecture d’un fichier binaire
try { FileInputStream fis = new FileInputStream (f);// on associe un flux au fichier à lire
byte [ ] tab = new byte [(int) f.length ( ) ];
try { while (fis.read ( ) !=-1) // on s’ arrete à la fin du fichier (-1)
fis.read (tab,0,(int) f.length ( ) -1 ); // on lit les octets qu’on stocke dans un tableau
fis.close( );
}
catch (IOException er){System.out .print("Erreur de lecture") ;}
for (int i = 0;i < tab.length ;i++)
System.out .println (tab [i]);// on affiche chaque octet lu
}
catch (FileNotFoundException ee) {System.out .println (ee.getMessage ( ) );}
}
} 483
Exemple de lecture d’un fichier binaire: Notes
484
Flux binaire en lecture tamponné.
On peut doter les flux binaires d’entrée d’un tampon qui permet d’avoir
des opérations plus rapides puisque les données sont lues en rafales.
Pour ce faire, on utilise la classe BufferedInputStream.
Les octets sont lus dans un tableau tampon interne qui est créé
simultanément avec la création de l’objet BufferedInputStream.
Il existe deux constructeurs de cette classe:
BufferedInputStream (InputStream in)
BufferedInputStream (InputStream in, int tailleTampon)
L’exemple précédent pouvez être amélioré en dotant le flux créé d’un tampon
comme ceci:
File f = new File ("c: \\ joe\\entree.dat");
FileInputStream fis = new FileInputStream (f);
BufferedInputStream bis = new BufferedInputStream (fis);
485
Classe java.io.FileOutputStream
Cette classe permet de gérer les flux binaires en écriture sur un fichier.
Cette classe possède plusieurs constructeurs qui peuvent lever tous une exception
de type : FileNotFoundException
(on réalise la copie d’un fichier dans un autre fichier avec usage de tampon)
Les classes de flux utilisées ici lèvent toutes une exception de type
FileNotFoundException.
Les méthodes read ( ) et write(…) lèvent aussi une exception de type
IOException.
Pour gérer ces exceptions, nous avons un bloc try suivi de deux blocs catch
pour les deux types d’erreurs évoquées.
Pour gérer ces mêmes exceptions, au lieu de bloc try … catch, on pourrait
Mentionner après l’en-tête de la méthode:
throws FileNotFoundException, IOException.
Mais, il faut éviter souvent d’utiliser cette dernière possibilité
pour des méthodes de l’ API que vous redéfinissez. Chacune d’elles
gère des exceptions spécifiques.
Par ailleurs, au lieu de deux blocs catch, on pouvait n’utiliser qu’un
seul bloc catch de cette façon: catch ( Exception er).
488
Classe java.io.DataInputStream
Classe java.io.DataOutputStream
489
Exemple de copy de fichier binaire
avec Data|In/Out|putStream
Cette classe gère les fichiers à accès direct permettant ainsi un accès rapide à un
enregistrement dans un fichier binaire.
Il est possible dans un tel fichier de mettre à jour directement un enregistrement.
La classe RandomAccessFile enveloppe les opérations de lecture/écriture dans un fichier.
0 0
100 4
public class TestWriteInt {
public static void main(String [ ] args) { 200 8
String fic = "c:\\joe\\destination.txt";
try { RandomAccessFile rw = new RandomAccessFile (fic,"rw"); 300 12
/*ecriture dans le fichier dix entiers*/
for ( int i = 0;i < 10;i++) 400 16
{ rw.writeInt (i*100 ) ; }
500 20
/*lecture du fichier: accès aux enregistrements*/
for (int i = 0; i < 10; i++) 600 24
{ long pos = rw.getFilePointer ( ) ; // position courante du pointeur
rw.seek (4*i) ; 700 28
System.out .println (rw.readInt ( ) +" "+pos) ;
} 800 32
rw.close() ; ième enregistrement.
} 900 36
catch (Exception e){ } Taille des données (un int est codé sur 4 octets)
}} 493
Entrées/Sorties standards
Le flux de sortie standard défini par la variable out est plus "connu" et est très
facile à manier dans des instructions du genre:
System.out.println ("usage du flux de sortie pour l’affichage sur la console");
494
Exemple de flux standard
(exemple de lecture au clavier de type primitif)
Les Collections sont des objets qui permettent de manipuler des ensembles
d’objets, ou encore de manipuler les structures de données telles que, les
vecteurs dynamiques, les ensembles, les listes chaînées, les tables associatives.
Les interfaces à utiliser par des objets qui gèrent les collections sont:
Collection : interface implémentée par la plupart des objets qui gèrent des collections
Map : interface qui définit des méthodes pour des objets qui gèrent des tables
associatives sous forme clé/valeur.
Set : interface pour des objets qui n’autorisent pas de gestion des doublons dans
l’ensemble
List : interface pour des objets qui autorisent la gestion des doublons et un accès
direct à un élément.
SortedSet : interface qui étend l’interface Set et permet d’ordonner l’ensemble.
SortedMap : interface qui étend l’interface Map et permet d’ordonner l’ensemble.
NB: les interfaces List et Set étendent l’interface Collection, et SortedSet étend Set.
Le framework propose plusieurs objets qui implémentent ces interfaces et qui peuvent
être directement utilisés:
497
Présentation du framework collection (2/2)
interface Iterator
Racine de la hiérarchie
(représente un groupe d’objets) Collection
Collection dont les éléments sont
Collection triés et peuvent être accédés par un index.
dont
les interface interface ListIterator
éléments Set List
ne peuvent interface
être (HashSet) (ArrayList, LinkedList) Map
dupliqués Associe un objet à une clé
interface qui ne peut être associé à un (HashMap)
autre objet.
SortedSet
(TreeSet) Ensemble trié.
Un « Map » qui maintient
interface
ses clés triées selon un ordre sortedMap
ascendant (par exemple
un dictionnaire
(TreeMap)
ou un annuaire téléphonique) 499
Concepts de collections
Mais il est très délicat de manipuler de telles collections, vu qu’il faudra très
souvent recourir au casting (opérateur de cast) et à instanceof (pour trouver la
classe d’un objet).
Donc il est préférable d’essayer de stocker dans une collection des objets de
même type pour faciliter leur manipulation.
Dans l’introduction d’un élément dans une collection , on ne réalise pas de
recopie d’objet, on se contente en fait d’introduire la référence à l’objet.
Ainsi, il est possible d’introduire la référence null dans une collection
500
L’interface java.util.Collection
Cette interface définit des méthodes pour des objets qui gèrent des éléments
d’une façon assez générale.
/*ajoute l’élément fourni en paramètre à la collection. La valeur de retour
indique si la collection a été mise à jour*/
boolean add (Object)
/*ajoute à la collection tous les éléments de la collection fournie en paramètre*/
boolean addAll (Collection)
/*supprime tous les éléments de la collection*/
void clean ( )
/*indique si la collection contient au moins un élément identique à celui fourni
en paramètre (au sens de equals)*/
boolean contains (Object)
/*indique si tous les éléments de la collection fournie en paramètre sont
contenus dans la collection*/
boolean containsAll (Collection) 501
L’interface java.util.Collection
Cette interface fournit des méthodes pour des objets capables de parcourir
les données d’une collection:
boolean hasNext ( ) // indique si il reste à parcourir dans la collection
Object next ( ) // renvoie le prochain élément dans la collection
void remove ( ) // supprime le dernier élément parcouru.
Remarque: la méthode next ( ) lève une exception de type
java.util.NoSuchElementException, si elle est appelée alors que la fin
du parcours des éléments est atteinte. Pour éviter de lever cette exception, il
suffit d’appeler la méthode hasNext ( ) avec le résultat de l’appel à la méthode
next ( ).
503
Exemple de parcours d’un itérateur
NB: L’interface Iterator ne dispose pas de méthode d’ajout d’un élément à une
position donnée.
506
L’interface java.util.List
Une liste est une collection ordonnée d’éléments qui autorise d’avoir des doublons.
Étant ordonné, un élément d’une liste peut être accédé à partir de son index.
Pour les listes, une interface particulière est définie pour assurer le parcours de la
liste dans les deux sens et effectuer des mises à jour: l’interface ListIterator.
507
L’interface java.util.List
ListIterator listIterator( )
// renvoie un objet pour parcourir la liste
//remplace l’élément à l’indice i par l’objet o
Object set( int i, Object o)
void add( int i, Object o)// ajoute à la liste l’objet o à la position i
Object get (int ) // renvoie l’objet à la position spécifiée
int indexOf (Object o) //renvoie la position du premier o trouvé et -1 si l’élément
// n’est pas dans la liste
List subList (int, int) /*renvoie un extrait de la liste contenant les éléments
entre les deux index fournis (le premier inclus, le dernier
exclu); les éléments contenus dans la liste de retour sont
des références sur la liste originale; des mises à jour de
cette liste impactent la liste originale*/
int lastIndexOf (Object) //renvoie l’index du dernier élément fourni en paramètre
// ou -1 si l’élément n’est pas dans la liste
Le framework propose des classes qui implémentent l’interface List:
LinkedList et ArrayList.
508
Les listes chaînées: la classe java.util.LinkedList
Les constructeurs
509
Premier Exemple de liste chaînée
package ndong.collection;
import java.util .*; // package de base des collections
public class ExempleLinkedList01 {
public static void main (String [ ] args) {
LinkedList <String> list = new LinkedList <String> ( ) // cree une liste vide
/*ajout d elements dans la liste*/
list.add ("objet 1") ;
list.add ("objet 2") ;
list.add ("objet 3") ;
/* iterateur bidirectionnel sur la liste*/
ListIterator <String> iter = list.listIterator ( ) ;
/*parcours des elements de la liste*/
while (iter.hasNext ( ) )
{ String o = iter.next ( ) ;
System.out .println ("element "+o) ;
}
}
}
510
Commentaires sur l’exemple de liste chaînée
Une liste chaînée gère une collection de façon ordonnée: l’ajout d’un élément peut se
faire en fin de liste ou après n’importe quel élément. Dans ce cas l’ajout est lié à la
position courante lors du parcours.
Les iterator peuvent être utilisés pour faire des mises à jour de la liste: une exception de
type ConcurrentModificationException est levée si un iterator parcourt la liste alors
q’un autre fait des mises à jour (ajout ou suppression d’un élément de la liste).
Pour gérer facilement cette situation, il faut mieux disposer d’un seul iterator s’il y a des
mises à jour prévues dans la liste.
Voici quelques méthodes spécifiques de la classe LinkedList:
void addFirst( Object) // ajoute l’élément en début de liste
void addLast (Object) // ajoute l’élément en fin de liste
Object getFirst ( ) // renvoie le premier de la liste
Object getLast ( ) // renvoie le dernier de la liste
Object removeFirst ( ) // supprime et renvoie le premier élément
Object removeLast ( ) // supprime et renvoie le dernier élément
La méthode toString ( ) renvoie une chaîne contenant tous les éléments de la liste.
Il n’existe pas de méthode pour accéder directement à un élément de la liste. 511
Deuxième Exemple de liste chaînée
package ndong.collection;
import java.util .*; // package de base des collections
public class ExempleLinkedList02 {
public static void main(String[] args) {
LinkedList <String> list = new LinkedList <String> ( ); // cree une liste vide
/*ajout d elements dans la liste*/
list.add (" a") ; list.add (" b") ; list.add (" c") ; c
/* iterateur bidirectionnel sur la liste//on se place en fin de liste*/ b
ListIterator <String> iter = list.listIterator (list.size( )) ; [a,c]
/*parcours des elements de la liste en sens inverse*/
while (iter.hasPrevious ( ) )
{ String s = iter.previous ( ) ; System.out .println ( s );
if (s.equals ("b ")) ;
{ iter.remove ( ); break; }
}
System.out .println( list. toString( ) ) ; // affiche les éléments de la liste
}} 512
Les Tableaux redimensionnables: la classe java.util.ArrayList
513
ArrayList: les méthodes
Chaque objet ArrayList gère une capacité qui est le nombre d’éléments
qu’il est possible d’insérer avant d’agrandir le tableau. Cette capacité a une
relation avec le nombre d’élément de la collection.
Lors de l’ajout, cette capacité et le nombre d’élément de la collection
détermine si le tableau doit être agrandi.
L’agrandissement de cette capacité s’effectue avec la méthode
ensureCapacity( int) .
515
Premier Exemple de ArrayList
Un ensemble est une collection non ordonnée qui n’autorise pas l’insertion de doublons.
L’interface java.util.Set
Cette interface définit les méthodes d’une collection qui n’accepte pas de doublons
dans ses éléments. Elle hérite de l’interface Collection mais ne définie pas de nouvelles
méthodes.
Pour vérifier si un élément est déjà inséré dans la collection, utiliser la méthode
equals ( ) . Les Objets ajoutés à un Set doivent définir la méthode equals ( ) pour pouvoir
établir l'unicité de l'objet.
Deux classes implémentent l’interface Set: TreeSet et HashSet.
Le choix entre ces deux méthodes est lié à la nécessité de trier les éléments:
les éléments d’un objet HashSet ne sont pas triés: l’insertion d’un nouvel objet
élément est rapide
518
les éléments d’un objet TreeSet sont triés: l’insertion d’un élément est longue.
Construction d’un objet de type HashSet
ou de type TreeSet
519
Spécificités d’un objet de type HashSet
ou de type TreeSet
522
L’interface java.util.SortedSet
Cette interface définit plusieurs méthodes pour tirer parti de cet ordre.
523
java.util.SortedSet: les méthodes
Ce type de collection désignée sous le titre de table associative gère les informations
sous forme de paires clé/valeur. Cette interface n’autorise pas de doublons.
L’intérêt des tables associatives est de pouvoir retrouver rapidement une clé donnée
pour en obtenir l’information associée qui est sa valeur.
Deux types d’organisations sont rencontrées avec les ensembles:
table de hachage: classe HashMap, Hashtable.
arbre binaire: classe TreeMap.
Seule la clé est utilisée pour ordonnancer les informations :
pour HashMap on se servira du code de hachage des objets formant les clés;
pour TreeMap, on se servira de la relation d’ordre induite par compareTo ou par un
comparateur fixé à la construction.
525
interface java.util.Map: les méthodes
526
java.util.HashMap et java.util.TreeMap
La classe HashMap n’est pas synchronisée; pour assurer la gestion des accès
concurrents sur cet objet, il faut l’envelopper dans un objet Map en utilisant
la méthode synchronizedMap de l’interface Collection.
527
Exemple de HashMap
package ndong.collection;
import java.util.*;
public class TestHashMap {
public static void main(String [ ] args) {
HashMap<Integer, String> table = new HashMap <>( );
/*ajout d'éléments dans la table*/
table.put (new Integer (1), "Livre Java") ; table.put( new Integer(2), "Livre Oracle") ;
table.put( new Integer (3), "Livre C++") ; table.put( new Integer(4), "Livre Reseaux") ;
/*recherche d'informations*/
String o = table.get ( new Integer(3)) ; // cherche la valeur associée à la cle 3
/*suppression d'information*/
Integer cle = new Integer(4);
table.remove (cle) ;
System.out .println( "suppression de la valeur" ) ;
else
System.out .println("la cle" +val+ "n'existe pas") ; }}
528
Remarques
529
Notion de vue
530
Exemple avec vue
import java.util.*;
public class TestHashMap_Vue {
public static void main (String [ ] args) {
HashMap <Integer, String> table = new HashMap <Integer, String> ( );
/*ajout d'éléments dans la table*/
table.put( new Integer(1), "Livre Java") ;table.put( new Integer(2), "Livre Oracle") ;
table.put( new Integer(3), "Livre C++") ;table.put( new Integer(4), "Livre Reseaux") ;
Set <Map.Entry<Integer, String>> entrees = table.entrySet ( ) ; //ensemble de paires
Iterator <Map.Entry<Integer, String>> iter = entrees.iterator ( ) ; // iterateur sur les paires
while (iter.hasNext ( ) )
{Map.Entry<Integer, String> entree = iter.next ( ) ; // on est sur la paire courante
L’ensemble fourni pat entrySet n’est pas une copie des informations figurant dans
la table. Il s’agit de ce que l’on nomme une vue.
Toute modification opérée sur la table se répercute sur la vue associée.
Il n’est pas permis d’ajouter directement des éléments dans la vue elle-même.
532
Autres vue
Là, on obtient une collection et non un ensemble car certaines valeurs peuvent bien
évidemment apparaître plusieurs fois.
Package test;
import java.util .*;
public class ExempleVue {
public static void main (String [ ] args) {
HashMap <Integer, String> map = new HashMap <Integer, String> ( );
map.put ("1","stock" ); map.put ( "2","livres" ) ;
map.put ("3","sucre" ) ; map.put ("4","huile" ) ;
//collection des valeurs
Collection <String> valeurs = map.values ( ) ;
System.out .println ( "Affichage 1 "+valeurs);
Iterator <String> iter = valeurs.iterator ( ) ;
while ( iter.hasNext ( ) )
{ String o = iter.next ( ) ; Affichage 1 [huile, sucre, livres, stock]
if (o.equals ( "huile" )) Element courant huile
{ iter.remove ( ) ; Element courant sucre
} Element courant livres
out .println ( "Element courant " +o); Element courant stock
} out .println ( "Affichage 2 " +valeurs); } } Affichage 2 [sucre, livres, stock] 534
Troisième exemple vue
package vup.essai;
import java.util.*;
public class ExempleVue2 {
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("1","stock"); map.put("2","livres") ;
map.put("3","sucre") ; map.put("4","huile") ;
//ensemble des cles Aff1 [4=huile, 3=sucre, 2=livres, 1=stock]
Set cles = map. entrySet ( ) ; Element courant huile
System.out .println("Aff1 "+cles); Element courant sucre
Iterator iter = cles.iterator() ; Element courant livres
while (iter.hasNext ( ) ) Element courant stock
{Map.Entry entree = (Map.Entry )iter.next() ; Affiche [4=riz, 3=sucre, 2=livres, 1=stock]
String s = (String) entree. getValue( ) ;
if (s. equals ("huile"))
entree.setValue ("riz");
System.out .println( "Element courant " +s); }System.out .print( "Affiche " +cles);535}}
Le Tri des Collections
o Comparable
o Comparator.
536
L’interface java.lang.Comparable
Tous les objets qui doivent définir un ordre naturel utilisé par le tri
d’une collection doivent implémenter cette interface.
interface Comparable {
int compareTo (Object o);
}
Certaines classes comme String, File, Date ou Integer, Float,… implémentent
cette interface.
L’interface Comparable ne dispose que d’une seule méthode, compareTo qui
fournit en résultat un ordre qu’on peut qualifier de naturel:
-Ordre lexicographique pour les chaînes, noms de fichier ou la classe Character,
-Ordre numérique pour les classes enveloppes numériques .
Cette méthode renvoie:
+ une valeur entière positive si l’objet courant est supérieur à l’objet fourni,
+ une valeur entière négative si l’objet courant est inférieur à l’objet fourni,
+ une valeur nulle si l’objet courant est égal à l’objet fourni. 537
Exercice avec Comparable
538
Solution (1/2)
541
Exercice avec Comparator
542
Remarque importante
L’interface Comparable doit être utilisée pour les collections acceptant un tri naturel
(TreeSet, TreeMap) et Comparable ou Comparator pour les interfaces n’acceptant pas de
tri naturel (ArrayList, HashSet, etc).
543
public class Produit implements Comparable<Produit>{
private String libelle;
private int quantite;
private int prix;
public Produit (String libelle, int quantite, int prix) {
this.libelle = libelle;
this.quantite = quantite;
this.prix = prix;
}
//getters and setters
@Override
public int compareTo(Produit o) {
String l1=this.getLibelle ( ); String l2=o.getLibelle ( ) ;
int k= l1.compareTo(l2);
if(k>1) return 1;
else if (k<1) return -1;
else return 0;
}
544
public static void main(String[] args)throws Exception {
TreeSet<Produit>v=new TreeSet<>();
v.add(new Produit("Mangue", 20,1000));
v.add(new Produit("Orange", 25,1500));
v.add(new Produit("Orange", 125,15000));
v.add(new Produit("Lait", 63,25));
v.add(new Produit("Riz",69,21));
v.add(new Produit("Huile", 200,58));
Iterator<Produit> it=v.iterator();
while(it.hasNext()){
Produit p=it.next();
System.out.println(p.getLibelle()+" "+p.getQuantite()+" "+p.getPrix());
}
546
Tri d’étudiants dans un TreeSet (2/3)
En intervertissant n1 et n2 et aussi m1 et m2, on change l’ordre de tri, de
croissant vers décroissant.
@Override
public int compareTo (Etudiant v) {
String n1=v.getNom();
String n2=this.getNom();
int k=n2.compareTo (n1);
if (k==0)
{ String m1=v.getPrenom();
String m2=this.getPrenom();
k=m2.compareTo (m1);
}
return k;
}
547
Tri d’étudiants dans un TreeSet (3/3)
}
550
Les Algorithmes
552
Remarques
Pour utiliser la méthode sort(List) , il faut obligatoirement que les éléments inclus
dans la liste implémentent tous l’interface Comparable sinon une exception de
type ClassCastException est levée.
553
Exemple 1
} 554
Notes sur l’exemple 1
555
Exemple 2
556
Code Exemple 2
import java.util.*;
list = Collections.synchronizedList(list) ;
public class Testsynchronized {
public static void main(String[] args) { synchronized (list) {
List list = new LinkedList(); Iterator iter = list.iterator ( ) ;
list.add( new Integer (800)) ; while (iter.hasNext ( ) )
list.add( new String ("livres")) ; {if ( iter.next ( ) instanceof Integer)
list.add("revue"); iter.remove ( ) ;
list.add("articles") ; list.add( null ) ; // illegal
list.add( new Integer(122)) ; } }
list.add( new Object()) ; synchronized (list){
Iterator it = list.iterator ( ) ;
while (it.hasNext ( ) )
{ if ( it.next ( ) instanceof String)
it.remove ( ) ;
Il faut définir un autre itérateur
} }
à cause des deux blocs synchronized.
System.out .println(list.toString( ) ) ;
}} 557
Notes sur l’exemple 2
java.util.ConcurrentModificationException .
558
FIN DU MODULE
Module 14 Programmation WEB: Applets
Une Applet est une classe Java compilée (byte code) qui s’exécute dans un logiciel de
navigation supportant java.
Cette classe doit dérivée soit de java.applet.Applet, soit de javax.swing.JApplet
qui lui donne une certaine interface:
- init ( ), start ( ), paint ( ), stop ( ), destroy ( ),
- l’applet spécifie son propre comportement en redéfinissant ces méthodes
- Elle réside en général sur un poste serveur distant.
-Elle est véhiculée dans une page HTML qui contient son URL.
Les applets permettent d’ajouter du dynamisme ou des possibilités à une page HTML
559
Généralités
Lorsqu’ un navigateur compatible Java (possédant une JVM) reçoit cette page
HTML, il télécharge (par HTTP) le code de la classe et l’exécute sur le poste client
(ie invoque ses méthodes init ( ), start ( ), ….)
C’est alors une véritable application, qui s’exécute dans la page HTML à l’intérieur
du navigateur qui peut:
- construire et gérer une interface graphique,
- créer de nouveaux threads,
- ouvrir des connexions réseaux.
560
Invoquer une applet
(Intégration d’applets dans une page HTML)
Dans une page HTML, il faut utiliser le tag APPLET avec la syntaxe suivante:
< APPLET
CODE = "AppletTest.class"
WIDTH = 200
HEIGHT = 300 >
</ APPLET >
Ce texte doit être intégré dans un fichier d’extension (.html). Il constitue le minimum
requis par le browser.
561
Fichier HTML de lancement d’ une applet
<HTML >
<TITLE > Lancement d’une Applet Java</TITLE >
<BODY>
< APPLET
CODE = "AppletTest.class"
WIDTH = 200
HEIGHT = 300 > Ce fichier est recherché
</ APPLET > dans le répertoire courant
</BODY >
</HTML >
AppletTest.html
Le répertoire courant est:
- le répertoire local si l’applet est exécutée depuis un visualiseur d’applets;
- le répertoire correspondant à l’adresse URL à partir de laquelle a été chargé le fichier
HTML, dans le cas d’un navigateur.
562
Extensions du fichier HTML
Nous venons de décrire le squelette minimal de la balise </applet >contenant les éléments
obligatoire pour le lancement d’une applet.
Mais il existe des paramètres optionnels mais importants utilisables dans cette balise.
< APPLET
CODE = "AppletTest.class"
CODEBASE = "URL de la racine "
WIDTH = 200
HEIGHT = 300
ARCHIVE = "fichier .jar "
NAME = "un nom pour l’applet "
ALIGN = " alignement "
VSPACE = "espace en dessous et en dessus entre l’applet et le texte "
HSPACE = "espace à droite et à gauche " >
<PARAM NAME = " param1 " VALUE = "valeur1 " >
<PARAM NAME = " param2 " VALUE = "valeur2 " >
</ APPLET >
563
Les méthodes de la classe Applet: le cycle de vie (1/2)
(le cycle de vie d’une applet dépend de l’utilisation de ses méthodes)
(a) la balise <applet > est rencontrée, La méthode start ( ) est réappelée
(b) le fichier archive est rapatrié,
(c ) le fichier code est rapatrié,
(d) la classe est chargée,
(e) l’applet est construite,
564
Les méthodes de la classe Applet: le cycle de vie (2/2)
Dans le cycle de vie d’une applet, quatre fonctions sont à l’œuvre de la naissance
à la mort de celle-ci :
[ le constructeur: pour l’instanciation de l’applet.]
public void init ( ) : appelée une seule fois après construction/chargement de
la page, premier lancement de l’applet
public void start ( ): lancement de l’applet ou réapparition
de la page. Appelée après init ( ) ou stop ( )
public void stop ( ) : disparition de la page, elle interrompt tous les processus
en cours
public void destroy ( ) : fermeture de la page, perte de la page
En général, il n’est pas nécessaire de faire un appel explicit aux méthodes ci-dessus, le
navigateur se charge d’appeler ces méthodes en fonction de l’état de la page HTML
contenant l’applet.
565
Remarques
Le constructeur et init ( ) semblent faire la même chose, mais ce n’est pas le cas.
On peut définir les deux et appeler init ( ) dans le constructeur.
566
Écrire une première applet: code de l’applet
<html>
<head>
</head>
<body>
<applet
codebase = "."
code = "applet.Applet1.class"
name = "AppletTest"
width = "400"
height = "300"
hspace = "0"
vspace = "0"
align = "top">
</applet>
</body>
</html>
568
Lancement de la page HTML
(l’heure est affichée de façon statique)
569
Deuxième applet: animation: code de l’applet (1/2)
(regardons maintenant un exemple d’affichage dynamique de l’heure courante)
571
Deuxième applet: animation: fichier HTML
(Applet2.html)
<html>
<head>
<title> Page de test HTML </title>
</head>
<body>
<applet
codebase = "."
code = "applet.Applet2.class"
name = " Com2"
width = "500"
height = "300"
hspace = "0"
vspace = "0"
align = "middle">
</applet>
</body>
</html> 572
Récupérer les Paramètres du fichier HTML dans l’applet
Il est possible de transmettre des informations à une applet depuis le fichier HTML.
Pour passer de la page HTML à l’applet, on utilise la balise <PARAM> ( ce tag doit
être inséré entre la balise <APPLET> et </APPLET>)
Pour récupérer les paramètres utilisateurs définis dans la balise <PARAM> du fichier
HTMl, depuis l’applet, on utilise la méthode getParameter (String param ).
Dans notre deuxième exemple, on pouvait faire de telle sorte qu’à chaque
visite de la page par un utilisateur, qu’on affiche le message suivant:
"Merci pour cette visite", dans une zone de texte.
Il suffit d’ajouter dans le fichier HTML cette ligne:
<param name="message" value = "Merci pour cette visite">
Pour réaliser des applets graphiques (ce qui très souvent le cas), Java dispose de la
méthode public void paint ( Graphics g).
Cette méthode est invoquée par le navigateur lors d’évènements nécessitant
de (re)dessiner dans la surface occupée par l’applet.
cette méthode reçoit en argument un objet de la classe Graphics qui décrit l’envi -
-ronnement graphique courant.
Toutes les opérations de dessin peuvent être effectuées dans cette méthode.
Il y a aussi les méthodes:
- public void repaint ( ): pour le rafraîchissement du programme graphique, en forçant
l’appel de la méthode paint ( ).
- public void update ( Graphics g):pour redessiner un bout de programme graphique
en effaçant l’écran et en appelant paint( ).
Cette méthode entraîne des scintillements désagréables de l’écran. Il faut donc souvent
la redéfinir: par exemple: public void update (Graphics g ) { paint (g);}
574
Chargement d’images avec attente
Regardons d’abord comment charger des images de la façon la plus simple avec
possibilité d’attente.
575
Etapes lors du chargement d’images
On peut aussi enregistrer l’image au même endroit que la page web (la page HTML).
Dans ce cas, utilisez cette syntaxe:
577
Exemple
578
Code Exemple
Dans certains cas, Java peut afficher des images alors que celles-ci ne sont pas encore
complètement chargées via Internet. Le lecteur de la page HTML voit les images
apparaître par morceaux à l’écran. Le lecteur patientera alors.
Souvent vous pouvez avoir besoin d’afficher des images seulement lorsqu’elles sont
arrivées sur l’ordinateur client (du lecteur). Dans ce cas, vous pouvez effectuer le
chargement des images en utilisant la classe MediaTracker.
En lui spécifiant les images à charger, cette classe peut vous indiquez les images qui sont
arrivées, celles qui ont provoqué une erreur, l’état d’avancement du chargement, etc.
580
Exemple MediaTracker
} 581
Exemple MediaTracker
582
Notes
Dans l’instruction:
tracker = new MediaTracker (this);
le this représente le composant sur lequel on dessine l’image, ici il s’agit de
la zone d’affichage de l’applet.
Dans l’instruction:
tracker.addImage (fond, 0);
le deuxième paramètre (0) représente l’importance de l’image (0 est la plus
grande importance).
Attention
La méthode checkAll ( ) renvoie aussi true si le chargement des images a été
interrompu, ou s’il y a eu des erreurs de chargement.
Le MediaTracker possèdent d’autres méthodes plus fines permettant de détecter
les erreurs (par exemple, la méthode isErrorAny ( ), qui vaut true si une erreur se
produit.
Dans l’instruction
g.drawImage (fond,20,20,this);
le dernier paramètre (ici this) représente un objet de l’interface ImageObserver.
Cette interface contient un e seule méthode, imageUpdate ( ) qui est invoquée chaque fois
qu’une portion d’image est chargée. Elle permet de gérer le téléchargement d’images à
partir d’un réseau, en tâche de fond.
584
Applet avec images qui bougent
Pour réaliser des applets avec des images qui bougent ou du texte défilant,
il faut faire usage des threads.
Voyons un exemple dans lequel nous construisons une applet contenant
une bande où on fait défiler un texte de bout en bout et de façon continue.
1 2
Ce texte défile de 1 à 2 le même processus reprend au début tant que la page vit .
585
Applet avec texte défilant (1/3)
586
Applet avec texte défilant (2/3)
/*redéfinition de start*/
public void start ( ){
if (t = = null){
t = new Thread (this);
t.start ( ) ;
repaint ( );
}
}
/*redefinition de run*/
public void run ( ){
while (true) {
paint (this.getGraphics ( ) );
}
}
}//fin de la classe
588
Tremblements dans les animations
En effet, la méthode repaint ( ), dès que cela est possible, appelle la méthode update ( )
qui, à son tour appelle paint ( ). Update ( ) dessine le fond de l’ écran, puis appelle
paint ( ): c’est ce qui produit le tremblements.
590
Communication entre applets
Java permet d’avoir dans une seule page HTML deux applets qui s’exécutent
et communiquent entre elles.
Pour cela, il suffit d’écrire un seul fichier HTML dans lequel il y a les 2 applets.
La communication sera rendu possible par l’exploitation du paramètre NAME de
la balise <applet>.
591
Exemple de Communication entre applets
Nous allons réunir ces deux pages web en une seule page.
(Applet2.html) (ComApplet.html)
Ici, on veut
stocker le temps
de connexion de
l’utilisateur, une
information
qu’on prend de
l’autre page.
En cliquant le temps est stocké
592
Exemple de Communication entre applets
Applet2.class est la première applet dans les exemples précédents (cf. diapos 493 à 495).
Nous donnons ci-dessous le code de la seconde applet dont le byte code sera mis dans
ComApplet.class, nous donnons également son fichier HTML (ComApplet.html).
<html>
<body>
<applet
codebase = "."
code = "applet.ComApplet.class"
name = "Com1"
width = "400"
height = "300"
align = "middle"
> ComApplet.html
</applet>
</body>
</html> 593
Exemple de Communication entre applets
}
public void update (Graphics g){
paint (g);
}
595
Exemple de Communication entre applets
<applet
codebase = "."
code = "applet.Applet2.class"
name = "Com2"
width = "400"
height = "300"
>
</applet> 597
</body> </html>
Exemple de Communication entre applets
(AppletComm.html)
ComApplet.html
Applet2.html
598
Notes
599
Module 15 Java DataBase Connectivity: JDBC
JDBC est une API Java (ensemble de classes et d’interfaces défini par SUN et les
acteurs du domaine des BD) permettant d’accéder aux bases de données à l’aide
du langage Java via des requêtes SQL (langage permettant de dialoguer avec un
SGBDR).
Cette API permet d’atteindre de façon quasi transparente des bases Sybase, Oracle,
Informix,… avec le même programme Java JDBC.
600
Principe de JDBC
601
Architecture JDBC
API
JDBC Gestionnaire
JDBC DriverManager de pilotes
JDBC JDBC
Driver
API
JDBC-ODBC JDBC driver
ODBC driver
MS SQL
MySQL Oracle
Access Server
602
Pilotes (drivers)
L’ensemble des classes qui implémentent les interfaces spécifiées par JDBC pour un
SGBD (Système de Gestion de Bases de Données) particulier est appelé un pilote
JDBC. Les protocoles d’accès aux bases de données étant propriétaires, il y a donc
plusieurs drivers pour atteindre diverses BD.
Chaque BD utilise un pilote qui lui est propre et qui permet de convertir les requêtes
dans le langage natif du SGBDR.
Les drivers dépendent du SGBD auquel ils permettent d’accéder.
Pour travailler avec un SGBD, il faut disposer de classes (driver) qui implémentent les
interfaces de JDBC.
JDBC est totalement indépendant de tout SGBD: la même application peut être
utilisée pour accéder à une base Oracle, Sybase, MySQL,etc.
603
Les Types de drivers (1/4)
SGBD
604
Les Types de drivers (2/4)
Ce sont des drivers partiellement écrits en Java et qui reposent sur des librairies
propriétaires (des fonctions natives non Java : par ex. C) pour accèder au SGBD.
Ils peuvent gérer des appels C/C++ directement avec la base.
Application Java
Partie en Java
Partie native Non Java
Protocole du
SGBD Driver
SGBD 605
Les Types de drivers (3/4)
Application Java
Driver en Java
Protocole du
serveur
Middleware Serveur Middleware
SGBD 606
Les Types de drivers (4/4)
SGBD 607
Chargement du pilote
Un programme JDBC débute toujours par le chargement du pilote approprié pour la BD.
Mais puisque le programme a la possibilité d’accéder à plusieurs types de BD, il peut avoir
plusieurs pilotes.
608
Les URLs JDBC
jdbc: protocole
Type II:
où protocole = protocole spécifique et utilisant des méthodes natives.
610
Structure d’un programme JDBC (2/4)
Connection con =
DriverManager.getConnection ("jdbc:odbc:employe", "login", "passwd");
611
Structure d’un programme JDBC (3/4)
612
Structure d’un programme JDBC (4/4)
Statement st = con.createStatement ( );
ResultSet rs = st.executeQuery ("select * from Client") ;
613
Notes 1
614
Notes 2: Traitement des données retournées
Seules les données demandées sont transférées en mémoire par le driver JDBC.
Il faut donc les lire manuellement et les stocker dans des variables pour un usage
ultérieur.
La méthode next ( ) de ResultSet permet de parcourir itérativement ligne par ligne
l’ensemble des tuples sélectionnés.
Cette méthode :
- retourne false si le dernier tuple est lu, true sinon,
- chaque appel fait avancer le curseur sur le tuple suivant,
- initialement, le curseur est positionné avant le premier tuple
Exécuter next ( ) au moins une fois pour avoir le premier.
while (rs.next ( )) { //traitement tuple par tuple}
Impossible de revenir au tuple précédent ou de parcourir l’ensemble dans un ordre
quelconque. 615
Notes 2: Traitement des données retournées
On peut parcourir le ResultSet ligne par ligne de façon itérative de la fin vers le début:
--- utilisez pour cela la méthode previous ( ), [while (rs.previous ( )) { // …}]
Les colonnes d’une table de la BD sont référencées par leur numéro (commençant par 1)
ou par leur nom.
L’accès aux valeurs des colonnes se fait par des méthodes de la forme getXXX (…)
permettant la lecture de données du type XXX dans chaque colonne du tuple courant.
617
Premier exemple complet d’utilisation de JDBC (1/3)
(exemple avec une source de données ODBC pour MS ACCESS)
619
Premier exemple complet d’utilisation de JDBC (3/3)
(exemple avec une source de données ODBC pour MS ACCESS)
Si vous écrivez une instruction telle que String prenom = rs.getString ("prenom") ;
cela signifie que vous êtes convaincu que la colonne de nom PRENOM a été créée sous
SQL avec le type VARCHAR. Autrement cette instruction causerais une erreur de
runtime.
Donc il est bon de savoir la correspondance entre types SQL et types Java pour pouvoir
manipuler convenablement les données lues.
622
Second exemple complet d’utilisation de JDBC (1/3)
Pour travailler avec JDBC et MySQL, il faut commencer par installer le driver
pour une base de données MySQL.
Ce driver se nomme Connector/J. Vous pouvez le récupérer à l’adresse
http://www.mysql.com/ products/connector-j
Ensuite décompressez le fichier jar ou le zip.
Et maintenant effectuez l’une des opérations suivantes:
- copier le fichier jar (mysql-connector-java-3.1.10-bin.jar par exemple) dans l’un des
répertoires de votre variable CLASSPATH
- ajouter le répertoire contenant le fichier jar à votre CLASSPATH
- copier le fichier jar dans $JAVA_HOME/jre /lib/ext. (pour un déploiement)
Et enfin dans le programme créez une librairie qui encapsule le fichier jar.
Pour tester vous pouvez créer le programme suivant:
623
Second exemple complet d’utilisation de JDBC (2/3)
Parfois, il est très utile et plus efficace de faire usage de l’objet PreparedStatement pour
envoyer une instruction SQL à la base de données.
En effet, si vous voulez exécuter un objet Statement plusieurs fois, le temps d’exécution
sera réduit si vous utilisez plutôt un objet PreparedStatement.
626
L’interface java.sql.PreparedStatement
Si vous réalisez des opérations de mises à jour (ex UPDATE) sur l’objet
PreparedStatement, utilisez la méthode executeUpdate( ) pour effectuer la
transaction dans la base.
Si vous réalisez des opérations de sélection (SELECT) , utilisez la méthode
executeQuery ( ) pour effectuer la transaction dans la base.
Quelques fois, le type de la requête est indéfinie à priori (MàJ ou select):
utilisez dans ce cas la méthode execute ( ) qui renvoie un booléen (true si c’est
une requête SELECT, false dans les cas de MàJ).
629
Les mises à jour de masse (Batch Updates)
JDBC 2.0 permet de réaliser des mises à jour de masse en regroupant plusieurs
traitements pour les envoyer en une seule fois au SGBD. Ceci permet d'améliorer les
performances surtout si le nombre de traitements est important.
Plusieurs méthodes ont été ajoutées à l'interface Statement pour pouvoir utiliser les
mises à jour de masse :
630
Les mises à jour de masse (Batch Updates)
Méthodes Rôle
void addBatch (String) permet d'ajouter une chaîne contenant une requête SQL
int [ ] executeBatch ( ) permet d'exécuter toutes les requêtes. Elle renvoie un tableau
d'entier qui contient pour chaque requête, le nombre de mises à
jour effectuées.
void clearBatch ( ) supprime toutes les requêtes stockées
631
Les mises à jour de masse (Batch Updates)
Gestion des exceptions
L'exception BatchUpdateException est levée si une des requêtes de mise à jour échoue.
L'exception BatchUpdateException possède une méthode getUpdateCounts ( ) qui
renvoie un tableau d'entier qui contient le nombre d'occurrences impactées par
chaque requête réussie.
632
Les mises à jour de masse (Batch Updates):Exemple
Tous les comptes dont le decouvert est supérieur à 30000 sont mis à jour
et le solde devient 500000.
On peut avoir besoin quelque fois des informations sur la structure et le schéma de la
base de données elle-même. Ces informations sont appelées des Métadonnées.
Pour obtenir ces renseignements, il faut utiliser un objet de la classe DatabaseMetaData
à partir de l’objet Connection. La méthode getMetaData ( ) de la classe Connection
permet de créer cet objet.
DatabaseMetaData donneesBD = objet_con.getMetaData ( ) ;
A partir de cet objet, cette classe fournit beaucoup de renseignements sur la BD.
Par exemple:
DatabaseMetaData d = con.getMetaData ( ) ;
String nomSGBD = d.getDatabaseProductName ( ) ; // nom du SGBD
String versionDriver = d.getDriverVersion ( ); // version du driver
String nomDriver = d.getDriverName ( ); //nom du driver
634
Les MétaDonnées
On peut aussi avoir des informations sur les objets ResultSet générés:
- nombre de colonnes contenues dans le ResultSet,
- noms des colonnes
- types des colonnes,
- etc.
Pour récupérer ces Métadonnées, il faut créer un objet de la classe
ResultSetMetaData grâce à la méthode getMetaData ( ) de la classe ResultSet.